Skip to content

Commit

Permalink
feat: isAvailable check implemented + several DX optimizations & fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mfkrause committed Nov 20, 2024
1 parent 4215972 commit e8ee38b
Show file tree
Hide file tree
Showing 16 changed files with 643 additions and 384 deletions.
35 changes: 35 additions & 0 deletions android/src/main/java/com/voicekit/VoiceError.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.voicekit

sealed class VoiceError(
val code: String,
val message: String
) {
object SpeechRecognizerNotAvailable : VoiceError(
"ERR_SPEECH_RECOGNIZER_NOT_AVAILABLE",
"Speech recognition is not available on this device"
)
object RecordingStartFailed : VoiceError(
"ERR_RECORDING_START_FAILED",
"Failed to start audio recording"
)
object RecognitionFailed : VoiceError(
"ERR_RECOGNITION_FAILED",
"Failed to recognize speech"
)
object PermissionDenied : VoiceError(
"ERR_PERMISSION_DENIED",
"Speech recognition permission was denied"
)
object PermissionRestricted : VoiceError(
"ERR_PERMISSION_RESTRICTED",
"Speech recognition is restricted on this device"
)
object PermissionNotDetermined : VoiceError(
"ERR_PERMISSION_NOT_DETERMINED",
"Speech recognition permission was not yet determined"
)
class Unknown(message: String = "An unknown error occurred") : VoiceError(
"ERR_UNKNOWN",
message
)
}
52 changes: 33 additions & 19 deletions android/src/main/java/com/voicekit/VoiceKitModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,25 @@ class VoiceKitModule(reactContext: ReactApplicationContext) :
fun startListening(options: ReadableMap, promise: Promise) {
val currentActivity = currentActivity
if (currentActivity == null) {
promise.reject("ERROR", "Activity is null")
promise.reject(
VoiceError.Unknown("Activity is null").code,
VoiceError.Unknown("Activity is null").message
)
return
}

// Check for permission
// TODO: Currently we don't wait for the pop-up permission dialog to be closed, but we should
if (ContextCompat.checkSelfPermission(currentActivity, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
currentActivity,
arrayOf(Manifest.permission.RECORD_AUDIO),
PERMISSION_REQUEST_CODE
)
promise.reject("ERROR", "Speech recognition permission denied")
promise.reject(
VoiceError.PermissionDenied.code,
VoiceError.PermissionDenied.message
)
return
}

Expand Down Expand Up @@ -79,19 +84,18 @@ class VoiceKitModule(reactContext: ReactApplicationContext) :

override fun onError(error: Int) {
Log.d("VoiceKitModule", "onError: $error")
val errorMessage = when (error) {
SpeechRecognizer.ERROR_AUDIO -> "Audio recording error"
SpeechRecognizer.ERROR_CLIENT -> "Client side error"
SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> "Insufficient permissions"
SpeechRecognizer.ERROR_NETWORK -> "Network error"
SpeechRecognizer.ERROR_NETWORK_TIMEOUT -> "Network timeout"
SpeechRecognizer.ERROR_NO_MATCH -> "No recognition result matched"
SpeechRecognizer.ERROR_RECOGNIZER_BUSY -> "Recognition service busy"
SpeechRecognizer.ERROR_SERVER -> "Server error"
SpeechRecognizer.ERROR_SPEECH_TIMEOUT -> "No speech input"
else -> "Unknown error"
val voiceError = when (error) {
SpeechRecognizer.ERROR_AUDIO -> VoiceError.RecordingStartFailed
SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> VoiceError.PermissionDenied
SpeechRecognizer.ERROR_NETWORK,
SpeechRecognizer.ERROR_NETWORK_TIMEOUT -> VoiceError.Unknown("Network error occurred")
SpeechRecognizer.ERROR_NO_MATCH -> VoiceError.RecognitionFailed
SpeechRecognizer.ERROR_RECOGNIZER_BUSY -> VoiceError.Unknown("Recognition service busy")
SpeechRecognizer.ERROR_SERVER -> VoiceError.Unknown("Server error occurred")
SpeechRecognizer.ERROR_SPEECH_TIMEOUT -> VoiceError.Unknown("No speech input")
else -> VoiceError.Unknown("Unknown error occurred")
}
promise.reject("ERROR", errorMessage)
promise.reject(voiceError.code, voiceError.message)
}

override fun onResults(results: Bundle?) {
Expand Down Expand Up @@ -128,11 +132,11 @@ class VoiceKitModule(reactContext: ReactApplicationContext) :
speechRecognizer?.startListening(intent)
promise.resolve(true)
} catch (e: Exception) {
promise.reject("ERROR", "Failed to start listening: ${e.message}")
promise.reject(VoiceError.RecognitionFailed.code, VoiceError.RecognitionFailed.message)
}
}
} catch (e: Exception) {
promise.reject("ERROR", "Failed to start listening: ${e.message}")
promise.reject(VoiceError.RecognitionFailed.code, VoiceError.RecognitionFailed.message)
}
}

Expand All @@ -146,11 +150,21 @@ class VoiceKitModule(reactContext: ReactApplicationContext) :
speechRecognizer = null
promise.resolve(true)
} catch (e: Exception) {
promise.reject("ERROR", "Failed to stop listening: ${e.message}")
promise.reject(VoiceError.RecognitionFailed.code, VoiceError.RecognitionFailed.message)
}
}
} catch (e: Exception) {
promise.reject("ERROR", "Failed to stop listening: ${e.message}")
promise.reject(VoiceError.RecognitionFailed.code, VoiceError.RecognitionFailed.message)
}
}

@ReactMethod
fun isSpeechRecognitionAvailable(promise: Promise) {
try {
val available = SpeechRecognizer.isRecognitionAvailable(reactApplicationContext)
promise.resolve(available)
} catch (e: Exception) {
promise.resolve(false)
}
}

Expand Down
Loading

0 comments on commit e8ee38b

Please sign in to comment.