[Feature] Custom Named Exception (#386)
This commit is contained in:
Родитель
0032939274
Коммит
fdb97aa35f
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.azure.android.communication.ui.calling;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Defines the base type of custom Exception that can be thrown by this Library.
|
||||
*/
|
||||
public final class CallCompositeException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Constructs a new Calling Composite exception with the specified error message and cause. Note
|
||||
* that the error message associated with "cause" is not automatically incorporated into this
|
||||
* exception's error message.
|
||||
*
|
||||
* @param errorMessage - the error message. The error message can be retrieved by the
|
||||
* getMessage() method
|
||||
* @param cause - the cause (which is saved for later retrieval by the getCause() method). A
|
||||
* null value is permitted, and indicates that the cause is non-existent or unknown.
|
||||
*/
|
||||
public CallCompositeException(final String errorMessage, @NonNull final Throwable cause) {
|
||||
super(errorMessage, cause);
|
||||
}
|
||||
/**
|
||||
* Constructs a new Calling Composite exception with the specified cause and message of
|
||||
* (cause==null ? null : cause.toString()) (which typically contains the class and detail message
|
||||
* of cause). This constructor is useful for exceptions that are little more than wrappers for
|
||||
* other throwables.
|
||||
*
|
||||
* @param cause - the cause (which is saved for later retrieval by the Throwable.getCause() method).
|
||||
* A null value is permitted, and indicates that the cause is nonexistent or unknown.
|
||||
*/
|
||||
public CallCompositeException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
package com.azure.android.communication.ui.calling.configuration
|
||||
|
||||
import com.azure.android.communication.ui.calling.CallCompositeException
|
||||
import com.azure.android.communication.ui.calling.configuration.events.CallCompositeEventsHandler
|
||||
import com.azure.android.communication.ui.calling.models.CallCompositeLocalOptions
|
||||
import com.azure.android.communication.ui.calling.models.CallCompositeLocalizationOptions
|
||||
import java.lang.RuntimeException
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
internal class CallCompositeConfiguration {
|
||||
var themeConfig: Int? = null
|
||||
|
@ -43,8 +44,9 @@ internal class CallCompositeConfiguration {
|
|||
// Gets a config by it's ID
|
||||
// May return null if the Configuration becomes garbage collected
|
||||
fun getConfig(id: Int): CallCompositeConfiguration = configs[id]
|
||||
?: throw RuntimeException(
|
||||
"This ID is not valid, and no entry exists in the map. Please file a bug, this is an error in the composite"
|
||||
?: throw CallCompositeException(
|
||||
"This ID is not valid, and no entry exists in the map. Please file a bug, this is an error in the composite",
|
||||
IllegalStateException()
|
||||
)
|
||||
|
||||
// Check if config exists
|
||||
|
|
|
@ -6,6 +6,7 @@ package com.azure.android.communication.ui.calling.presentation
|
|||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import com.azure.android.communication.ui.R
|
||||
import com.azure.android.communication.ui.calling.CallCompositeException
|
||||
import com.azure.android.communication.ui.calling.configuration.CallCompositeConfiguration
|
||||
import com.azure.android.communication.ui.calling.di.DependencyInjectionContainer
|
||||
import com.azure.android.communication.ui.calling.di.DependencyInjectionContainerImpl
|
||||
|
@ -18,7 +19,6 @@ import com.azure.android.communication.ui.calling.service.sdk.CallingSDK
|
|||
import com.azure.android.communication.ui.calling.utilities.CoroutineContextProvider
|
||||
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.lang.RuntimeException
|
||||
|
||||
/**
|
||||
* ViewModel for the CallCompositeActivity
|
||||
|
@ -35,24 +35,26 @@ internal class DependencyInjectionContainerHolder(
|
|||
private val customVideoStreamRendererFactory: VideoStreamRendererFactory?,
|
||||
private val customCoroutineContextProvider: CoroutineContextProvider?
|
||||
) : AndroidViewModel(application) {
|
||||
companion object {
|
||||
private const val commonMessage =
|
||||
"Please ensure that you have set a valid instanceId before retrieving the container."
|
||||
}
|
||||
// Instance ID to locate Configuration. -1 is invalid.
|
||||
var instanceId: Int = -1
|
||||
set(value) {
|
||||
if (!CallCompositeConfiguration.hasConfig(value)) {
|
||||
throw IllegalArgumentException(
|
||||
"Configuration with instanceId:$value does not exist. " +
|
||||
"Please ensure that you have set a valid instanceId before retrieving the container."
|
||||
)
|
||||
val exceptionMessage =
|
||||
"Configuration with instanceId:$value does not exist. $commonMessage"
|
||||
throw CallCompositeException(exceptionMessage, IllegalArgumentException(exceptionMessage))
|
||||
}
|
||||
field = value
|
||||
}
|
||||
|
||||
val container: DependencyInjectionContainer by lazy {
|
||||
if (instanceId == -1) {
|
||||
throw RuntimeException(
|
||||
"Will not be able to locate a Configuration for instanceId: -1. " +
|
||||
"Please ensure that you have set instanceId before retrieving the container."
|
||||
)
|
||||
val exceptionMessage =
|
||||
"Will not be able to locate a Configuration for instanceId: -1. $commonMessage"
|
||||
throw CallCompositeException(exceptionMessage, IllegalStateException(exceptionMessage))
|
||||
}
|
||||
|
||||
// Generate a new instance
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.os.Bundle
|
|||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.coroutineScope
|
||||
import com.azure.android.communication.ui.calling.CallCompositeException
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.IllegalArgumentException
|
||||
import com.azure.android.communication.ui.calling.redux.state.PermissionStatus
|
||||
|
@ -79,7 +80,7 @@ internal class AudioSessionManager(
|
|||
|
||||
fun onStart(activity: Activity) {
|
||||
if (activity !is LifecycleOwner) {
|
||||
throw IllegalArgumentException("Activity must be a LifecycleOwner)")
|
||||
throw CallCompositeException("Activity must be a LifecycleOwner", IllegalArgumentException())
|
||||
}
|
||||
(activity as LifecycleOwner).lifecycle.coroutineScope.launch {
|
||||
// On first launch we need to init the redux-state, check Bluetooth and Headset status
|
||||
|
|
|
@ -5,6 +5,7 @@ package com.azure.android.communication.ui.calling.redux
|
|||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import com.azure.android.communication.ui.calling.CallCompositeException
|
||||
import com.azure.android.communication.ui.calling.redux.action.Action
|
||||
import com.azure.android.communication.ui.calling.redux.reducer.Reducer
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
|
@ -14,8 +15,6 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
internal class AppStoreException(msg: String, e: Throwable? = null) : Exception(msg, e)
|
||||
|
||||
internal class AppStore<S>(
|
||||
initialState: S,
|
||||
private val reducer: Reducer<S>,
|
||||
|
@ -25,7 +24,7 @@ internal class AppStore<S>(
|
|||
// Any exceptions encountered in the reducer are rethrown to crash the app and not get silently ignored.
|
||||
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
|
||||
Handler(Looper.getMainLooper()).postAtFrontOfQueue {
|
||||
throw AppStoreException("Exception while reducing state", throwable)
|
||||
throw CallCompositeException("App store exception while reducing state", throwable)
|
||||
}
|
||||
// At this point (after an exception) we don't want to accept any more work.
|
||||
scope.cancel()
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.azure.android.communication.calling.JoinMeetingLocator
|
|||
import com.azure.android.communication.calling.TeamsMeetingLinkLocator
|
||||
import com.azure.android.communication.calling.VideoDevicesUpdatedListener
|
||||
import com.azure.android.communication.calling.VideoOptions
|
||||
import com.azure.android.communication.ui.calling.CallCompositeException
|
||||
import com.azure.android.communication.ui.calling.configuration.CallCompositeConfiguration
|
||||
import com.azure.android.communication.ui.calling.configuration.CallConfiguration
|
||||
import com.azure.android.communication.ui.calling.configuration.CallType
|
||||
|
@ -54,18 +55,23 @@ internal class CallingSDKWrapper(
|
|||
|
||||
private val callConfig: CallConfiguration
|
||||
get() {
|
||||
if (configuration.callConfig == null)
|
||||
throw IllegalStateException("Call configurations are not set")
|
||||
|
||||
return configuration.callConfig!!
|
||||
try {
|
||||
return configuration.callConfig!!
|
||||
} catch (ex: Exception) {
|
||||
throw CallCompositeException(
|
||||
"Call configurations are not set",
|
||||
IllegalStateException()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val call: Call
|
||||
get() {
|
||||
if (nullableCall == null)
|
||||
throw IllegalStateException("Call is not started")
|
||||
|
||||
return nullableCall!!
|
||||
try {
|
||||
return nullableCall!!
|
||||
} catch (ex: Exception) {
|
||||
throw CallCompositeException("Call is not started", IllegalStateException())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRemoteParticipantsMap(): Map<String, RemoteParticipant> =
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.azure.android.communication.ui.configuration
|
||||
|
||||
import com.azure.android.communication.ui.calling.CallCompositeException
|
||||
import com.azure.android.communication.ui.calling.configuration.CallCompositeConfiguration
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.junit.MockitoJUnitRunner
|
||||
|
||||
@RunWith(MockitoJUnitRunner::class)
|
||||
internal class CallCompositeExceptionTest {
|
||||
|
||||
@Test
|
||||
fun callCompositeConfiguration_errorHandling() {
|
||||
val classObj = CallCompositeException::class.java
|
||||
CallCompositeConfiguration.putConfig(0, CallCompositeConfiguration())
|
||||
|
||||
val ex = assertThrows(classObj, ::getCallCompositeConfig)
|
||||
assertThat(
|
||||
"invalid type: ${ex.javaClass.simpleName}",
|
||||
ex.javaClass.simpleName == classObj.simpleName
|
||||
)
|
||||
assertThat(
|
||||
"invalid message, expecting: ${ex.message}",
|
||||
ex.message?.startsWith("This ID is not valid, and no entry exists in the map") ?: false
|
||||
)
|
||||
|
||||
assertThat(
|
||||
"Invalid cause, expecting: ${ex.cause}",
|
||||
ex.cause is IllegalStateException
|
||||
)
|
||||
}
|
||||
|
||||
private fun getCallCompositeConfig() = CallCompositeConfiguration.getConfig(1)
|
||||
}
|
Загрузка…
Ссылка в новой задаче