mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-24 22:17:25 +00:00
feat: hooking up calls and fixing broken dependencies and compile errors
This commit is contained in:
@@ -37,10 +37,12 @@ dependencies {
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
||||
implementation 'androidx.activity:activity-ktx:1.2.2'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.3.2'
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
@@ -153,7 +155,7 @@ dependencies {
|
||||
testImplementation 'org.robolectric:shadows-multidex:4.4'
|
||||
}
|
||||
|
||||
def canonicalVersionCode = 231
|
||||
def canonicalVersionCode = 232
|
||||
def canonicalVersionName = "1.11.12"
|
||||
|
||||
def postFixSize = 10
|
||||
|
@@ -54,7 +54,6 @@ import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
|
||||
import org.thoughtcrime.securesms.database.JobDatabase;
|
||||
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.database.Storage;
|
||||
import org.thoughtcrime.securesms.dependencies.CallComponent;
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseModule;
|
||||
import org.thoughtcrime.securesms.groups.OpenGroupManager;
|
||||
@@ -82,6 +81,7 @@ import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository;
|
||||
import org.thoughtcrime.securesms.util.Broadcaster;
|
||||
import org.thoughtcrime.securesms.util.UiModeUtilities;
|
||||
import org.thoughtcrime.securesms.util.dynamiclanguage.LocaleParseHelper;
|
||||
import org.thoughtcrime.securesms.webrtc.CallMessageProcessor;
|
||||
import org.webrtc.PeerConnectionFactory;
|
||||
import org.webrtc.PeerConnectionFactory.InitializationOptions;
|
||||
import org.webrtc.voiceengine.WebRtcAudioManager;
|
||||
@@ -134,6 +134,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
@Inject Storage storage;
|
||||
@Inject MessageDataProvider messageDataProvider;
|
||||
@Inject JobDatabase jobDatabase;
|
||||
CallMessageProcessor callMessageProcessor;
|
||||
|
||||
private volatile boolean isAppVisible;
|
||||
|
||||
@@ -160,6 +161,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
public void onCreate() {
|
||||
DatabaseModule.init(this);
|
||||
super.onCreate();
|
||||
callMessageProcessor = new CallMessageProcessor(this, ProcessLifecycleOwner.get().getLifecycle());
|
||||
Log.i(TAG, "onCreate()");
|
||||
startKovenant();
|
||||
initializeSecurityProvider();
|
||||
|
@@ -8,28 +8,17 @@ import android.content.IntentFilter
|
||||
import android.media.AudioManager
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.android.synthetic.main.activity_webrtc_tests.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||
import org.session.libsession.messaging.utilities.WebRtcUtils
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.webrtc.CallViewModel
|
||||
import org.webrtc.*
|
||||
import org.webrtc.IceCandidate
|
||||
import java.util.*
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -67,7 +56,6 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
|
||||
super.onCreate(savedInstanceState, ready)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
setContentView(R.layout.activity_webrtc_tests)
|
||||
volumeControlStream = AudioManager.STREAM_VOICE_CALL
|
||||
|
||||
@@ -81,16 +69,16 @@ class WebRtcCallActivity: PassphraseRequiredActionBarActivity() {
|
||||
.execute()
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel
|
||||
}
|
||||
// repeat on start or something
|
||||
}
|
||||
|
||||
|
||||
|
||||
registerReceiver(object: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
finish()
|
||||
}
|
||||
}, IntentFilter(ACTION_END))
|
||||
},IntentFilter(ACTION_END))
|
||||
}
|
||||
|
||||
private fun initializeResources() {
|
||||
|
@@ -24,7 +24,6 @@ import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.loader.app.LoaderManager
|
||||
import androidx.loader.content.Loader
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
@@ -457,7 +456,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
}
|
||||
|
||||
private fun setUpLinkPreviewObserver() {
|
||||
val linkPreviewViewModel = ViewModelProviders.of(this, LinkPreviewViewModel.Factory(LinkPreviewRepository()))[LinkPreviewViewModel::class.java]
|
||||
val linkPreviewViewModel = ViewModelProvider(this, LinkPreviewViewModel.Factory(LinkPreviewRepository()))[LinkPreviewViewModel::class.java]
|
||||
this.linkPreviewViewModel = linkPreviewViewModel
|
||||
if (!TextSecurePreferences.isLinkPreviewsEnabled(this)) {
|
||||
linkPreviewViewModel.onUserCancel(); return
|
||||
|
@@ -43,10 +43,10 @@ import org.thoughtcrime.securesms.conversation.v2.utilities.NotificationUtils
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.groups.EditClosedGroupActivity
|
||||
import org.thoughtcrime.securesms.groups.EditClosedGroupActivity.Companion.groupIDKey
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||
import org.thoughtcrime.securesms.util.getColorWithID
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
object ConversationMenuHelper {
|
||||
|
||||
@@ -183,16 +183,14 @@ object ConversationMenuHelper {
|
||||
}
|
||||
|
||||
private fun call(context: Context, thread: Recipient) {
|
||||
AlertDialog.Builder(context)
|
||||
.setTitle("Call")
|
||||
.setMessage("Use relay?")
|
||||
.setPositiveButton("Use Relay") { d, w ->
|
||||
TODO()
|
||||
}
|
||||
.setNeutralButton("P2P only") { d, w ->
|
||||
TODO()
|
||||
}
|
||||
.show()
|
||||
val service = WebRtcCallService.createCall(context, thread)
|
||||
context.startService(service)
|
||||
|
||||
val activity = Intent(context, WebRtcCallActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
context.startActivity(activity)
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
|
@@ -148,49 +148,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
|
||||
}
|
||||
this.broadcastReceiver = broadcastReceiver
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged"))
|
||||
lifecycleScope.launchWhenCreated {
|
||||
// web rtc channel handling
|
||||
for (message in WebRtcUtils.SIGNAL_QUEUE) {
|
||||
// TODO: check errors here in the
|
||||
val sender = Address.fromSerialized(message.sender!!)
|
||||
val callId = message.callId!!
|
||||
synchronized(WebRtcUtils.callCache) {
|
||||
val set = WebRtcUtils.callCache[callId] ?: mutableSetOf()
|
||||
set += message
|
||||
WebRtcUtils.callCache[callId] = set
|
||||
}
|
||||
when (message.type) {
|
||||
SignalServiceProtos.CallMessage.Type.OFFER -> {
|
||||
// show bottom sheet
|
||||
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
||||
CallBottomSheet().apply {
|
||||
arguments = bundleOf(
|
||||
CallBottomSheet.ARGUMENT_ADDRESS to sender,
|
||||
CallBottomSheet.ARGUMENT_SDP to message.sdps.toTypedArray(),
|
||||
CallBottomSheet.ARGUMENT_TYPE to message.type!!.number,
|
||||
CallBottomSheet.ARGUMENT_CALL_ID to callId.toString()
|
||||
)
|
||||
show(this@HomeActivity.supportFragmentManager,"call-sheet")
|
||||
}
|
||||
}
|
||||
}
|
||||
SignalServiceProtos.CallMessage.Type.END_CALL -> {
|
||||
// dismiss the call sheet
|
||||
supportFragmentManager.findFragmentByTag("call-sheet")?.let { callSheet ->
|
||||
if (callSheet is BottomSheetDialogFragment) {
|
||||
callSheet.dismiss()
|
||||
}
|
||||
}
|
||||
// clear the callCache for this sender
|
||||
synchronized(WebRtcUtils.callCache) {
|
||||
WebRtcUtils.callCache[callId] = mutableSetOf()
|
||||
}
|
||||
sendBroadcast(Intent(WebRtcCallActivity.ACTION_END))
|
||||
}
|
||||
else -> { /* do nothing */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launchWhenStarted {
|
||||
launch(Dispatchers.IO) {
|
||||
|
@@ -86,6 +86,17 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
||||
|
||||
fun acceptCallIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_ANSWER_CALL)
|
||||
|
||||
fun createCall(context: Context, recipient: Recipient) = Intent(context, WebRtcCallService::class.java)
|
||||
.setAction(ACTION_OUTGOING_CALL)
|
||||
.putExtra(EXTRA_RECIPIENT_ADDRESS, recipient.address)
|
||||
|
||||
fun incomingCall(context: Context, address: Address, sdp: String, callId: UUID) =
|
||||
Intent(context, WebRtcCallService::class.java)
|
||||
.setAction(ACTION_INCOMING_CALL)
|
||||
.putExtra(EXTRA_RECIPIENT_ADDRESS, address)
|
||||
.putExtra(EXTRA_CALL_ID, callId)
|
||||
.putExtra(EXTRA_REMOTE_DESCRIPTION, sdp)
|
||||
|
||||
fun denyCallIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_DENY_CALL)
|
||||
|
||||
fun hangupIntent(context: Context) = Intent(context, WebRtcCallService::class.java).setAction(ACTION_LOCAL_HANGUP)
|
||||
@@ -122,15 +133,14 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
||||
|
||||
@Synchronized
|
||||
private fun terminate() {
|
||||
stopForeground(true)
|
||||
sendBroadcast(Intent(WebRtcCallActivity.ACTION_END))
|
||||
callManager.stop()
|
||||
stopForeground(true)
|
||||
}
|
||||
|
||||
private fun isBusy() = callManager.isBusy(this)
|
||||
|
||||
private fun initializeVideo() {
|
||||
callManager.initializeVideo(this)
|
||||
}
|
||||
private fun isIdle() = callManager.isIdle()
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
@@ -142,7 +152,7 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
||||
action == ACTION_INCOMING_CALL && isBusy() -> handleBusyCall(intent)
|
||||
action == ACTION_REMOTE_BUSY -> handleBusyMessage(intent)
|
||||
action == ACTION_INCOMING_CALL -> handleIncomingCall(intent)
|
||||
action == ACTION_OUTGOING_CALL -> handleOutgoingCall(intent)
|
||||
action == ACTION_OUTGOING_CALL && isIdle() -> handleOutgoingCall(intent)
|
||||
action == ACTION_ANSWER_CALL -> handleAnswerCall(intent)
|
||||
action == ACTION_DENY_CALL -> handleDenyCall(intent)
|
||||
action == ACTION_LOCAL_HANGUP -> handleLocalHangup(intent)
|
||||
@@ -288,12 +298,11 @@ class WebRtcCallService: Service(), PeerConnection.Observer {
|
||||
callManager.initializeVideo(this)
|
||||
|
||||
callManager.postViewModelState(CallViewModel.State.CALL_OUTGOING)
|
||||
// update phone state IN_CALL
|
||||
lockManager.updatePhoneState(LockManager.PhoneState.IN_CALL)
|
||||
callManager.initializeAudioForCall()
|
||||
callManager.startOutgoingRinger(OutgoingRinger.Type.RINGING)
|
||||
// bluetoothStateManager.setWantsConnection(true)
|
||||
setCallInProgressNotification(TYPE_OUTGOING_RINGING, callManager.recipient)
|
||||
// DatabaseComponent.get(this).insertOutgoingCall(callManager.recipient!!.address)
|
||||
// TODO: DatabaseComponent.get(this).insertOutgoingCall(callManager.recipient!!.address)
|
||||
timeoutExecutor.schedule(TimeoutRunnable(callId, this), 2, TimeUnit.MINUTES)
|
||||
|
||||
val expectedState = callManager.currentConnectionState
|
||||
|
@@ -54,17 +54,17 @@ class CallBottomSheet: BottomSheetDialogFragment() {
|
||||
nameTextView.text = recipient.name ?: address.serialize()
|
||||
|
||||
acceptButton.setOnClickListener {
|
||||
val intent = Intent(requireContext(), WebRtcCallActivity::class.java)
|
||||
val bundle = bundleOf(
|
||||
WebRtcCallActivity.EXTRA_ADDRESS to address,
|
||||
WebRtcCallActivity.EXTRA_CALL_ID to callId
|
||||
)
|
||||
intent.action = WebRtcCallActivity.ACTION_ANSWER
|
||||
bundle.putStringArray(WebRtcCallActivity.EXTRA_SDP, sdp)
|
||||
|
||||
intent.putExtras(bundle)
|
||||
startActivity(intent)
|
||||
dismiss()
|
||||
// val intent = Intent(requireContext(), WebRtcCallActivity::class.java)
|
||||
// val bundle = bundleOf(
|
||||
// WebRtcCallActivity.EXTRA_ADDRESS to address,
|
||||
// WebRtcCallActivity.EXTRA_CALL_ID to callId
|
||||
// )
|
||||
// intent.action = WebRtcCallActivity.ACTION_ANSWER
|
||||
// bundle.putStringArray(WebRtcCallActivity.EXTRA_SDP, sdp)
|
||||
//
|
||||
// intent.putExtras(bundle)
|
||||
// startActivity(intent)
|
||||
// dismiss()
|
||||
}
|
||||
|
||||
declineButton.setOnClickListener {
|
||||
|
@@ -147,6 +147,8 @@ class CallManager(context: Context, audioManager: AudioManagerCompat): PeerConne
|
||||
fun isBusy(context: Context) = currentConnectionState != CallState.STATE_IDLE
|
||||
|| context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE
|
||||
|
||||
fun isIdle() = currentConnectionState == CallState.STATE_IDLE
|
||||
|
||||
fun initializeVideo(context: Context) {
|
||||
Util.runOnMainSync {
|
||||
val base = EglBase.create()
|
||||
|
@@ -0,0 +1,45 @@
|
||||
package org.thoughtcrime.securesms.webrtc
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.lifecycle.coroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import org.session.libsession.messaging.messages.control.CallMessage
|
||||
import org.session.libsession.messaging.utilities.WebRtcUtils
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsignal.protos.SignalServiceProtos
|
||||
import org.session.libsignal.protos.SignalServiceProtos.CallMessage.Type.OFFER
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class CallMessageProcessor(private val context: Context, lifecycle: Lifecycle) {
|
||||
|
||||
init {
|
||||
lifecycle.coroutineScope.launch {
|
||||
while (isActive) {
|
||||
val nextMessage = WebRtcUtils.SIGNAL_QUEUE.receive()
|
||||
when {
|
||||
// TODO: handle messages as they come in
|
||||
nextMessage.type == OFFER -> incomingCall(nextMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun incomingCall(callMessage: CallMessage) {
|
||||
val recipientAddress = callMessage.recipient ?: return
|
||||
val callId = callMessage.callId ?: return
|
||||
val sdp = callMessage.sdps.firstOrNull() ?: return
|
||||
val incomingIntent = WebRtcCallService.incomingCall(
|
||||
context = context,
|
||||
address = Address.fromSerialized(recipientAddress),
|
||||
sdp = sdp,
|
||||
callId = callId
|
||||
)
|
||||
context.startService(incomingIntent)
|
||||
}
|
||||
|
||||
}
|
@@ -165,7 +165,7 @@ class PeerConnectionWrapper(context: Context,
|
||||
fun createOffer(mediaConstraints: MediaConstraints): SessionDescription {
|
||||
val future = SettableFuture<SessionDescription>()
|
||||
|
||||
peerConnection.createAnswer(object:SdpObserver {
|
||||
peerConnection.createOffer(object:SdpObserver {
|
||||
override fun onCreateSuccess(sdp: SessionDescription?) {
|
||||
future.set(sdp)
|
||||
}
|
||||
|
@@ -37,9 +37,9 @@ class SignalAudioManager(private val context: Context,
|
||||
private val androidAudioManager: AudioManagerCompat) {
|
||||
|
||||
private var commandAndControlThread: HandlerThread? = HandlerThread("call-audio").apply { start() }
|
||||
private var handler = SignalAudioHandler(commandAndControlThread!!.looper)
|
||||
private var handler: SignalAudioHandler? = null
|
||||
|
||||
private val signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler)
|
||||
private var signalBluetoothManager: SignalBluetoothManager? = null
|
||||
|
||||
private var state: State = State.UNINITIALIZED
|
||||
|
||||
@@ -66,7 +66,7 @@ class SignalAudioManager(private val context: Context,
|
||||
private var wiredHeadsetReceiver: WiredHeadsetReceiver? = null
|
||||
|
||||
fun handleCommand(command: AudioManagerCommand) {
|
||||
handler.post {
|
||||
handler?.post {
|
||||
when (command) {
|
||||
is AudioManagerCommand.Initialize -> initialize()
|
||||
is AudioManagerCommand.Shutdown -> shutdown()
|
||||
@@ -89,27 +89,32 @@ class SignalAudioManager(private val context: Context,
|
||||
commandAndControlThread = HandlerThread("call-audio").apply { start() }
|
||||
handler = SignalAudioHandler(commandAndControlThread!!.looper)
|
||||
|
||||
savedAudioMode = androidAudioManager.mode
|
||||
savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn
|
||||
savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute
|
||||
hasWiredHeadset = androidAudioManager.isWiredHeadsetOn
|
||||
signalBluetoothManager = SignalBluetoothManager(context, this, androidAudioManager, handler!!)
|
||||
|
||||
androidAudioManager.requestCallAudioFocus()
|
||||
handler!!.post {
|
||||
|
||||
setMicrophoneMute(false)
|
||||
savedAudioMode = androidAudioManager.mode
|
||||
savedIsSpeakerPhoneOn = androidAudioManager.isSpeakerphoneOn
|
||||
savedIsMicrophoneMute = androidAudioManager.isMicrophoneMute
|
||||
hasWiredHeadset = androidAudioManager.isWiredHeadsetOn
|
||||
|
||||
audioDevices.clear()
|
||||
androidAudioManager.requestCallAudioFocus()
|
||||
|
||||
signalBluetoothManager.start()
|
||||
setMicrophoneMute(false)
|
||||
|
||||
updateAudioDeviceState()
|
||||
audioDevices.clear()
|
||||
|
||||
wiredHeadsetReceiver = WiredHeadsetReceiver()
|
||||
context.registerReceiver(wiredHeadsetReceiver, IntentFilter(if (Build.VERSION.SDK_INT >= 21) AudioManager.ACTION_HEADSET_PLUG else Intent.ACTION_HEADSET_PLUG))
|
||||
signalBluetoothManager!!.start()
|
||||
|
||||
state = State.PREINITIALIZED
|
||||
updateAudioDeviceState()
|
||||
|
||||
Log.d(TAG, "Initialized")
|
||||
wiredHeadsetReceiver = WiredHeadsetReceiver()
|
||||
context.registerReceiver(wiredHeadsetReceiver, IntentFilter(if (Build.VERSION.SDK_INT >= 21) AudioManager.ACTION_HEADSET_PLUG else Intent.ACTION_HEADSET_PLUG))
|
||||
|
||||
state = State.PREINITIALIZED
|
||||
|
||||
Log.d(TAG, "Initialized")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +164,7 @@ class SignalAudioManager(private val context: Context,
|
||||
}
|
||||
wiredHeadsetReceiver = null
|
||||
|
||||
signalBluetoothManager.stop()
|
||||
signalBluetoothManager?.stop()
|
||||
|
||||
setSpeakerphoneOn(savedIsSpeakerPhoneOn)
|
||||
setMicrophoneMute(savedIsMicrophoneMute)
|
||||
@@ -172,7 +177,7 @@ class SignalAudioManager(private val context: Context,
|
||||
}
|
||||
|
||||
private fun shutdown() {
|
||||
handler.post {
|
||||
handler?.post {
|
||||
stop(false)
|
||||
if (commandAndControlThread != null) {
|
||||
Log.i(TAG, "Shutting down command and control")
|
||||
@@ -183,25 +188,25 @@ class SignalAudioManager(private val context: Context,
|
||||
}
|
||||
|
||||
private fun updateAudioDeviceState() {
|
||||
handler.assertHandlerThread()
|
||||
handler!!.assertHandlerThread()
|
||||
|
||||
Log.i(
|
||||
TAG,
|
||||
"updateAudioDeviceState(): " +
|
||||
"wired: $hasWiredHeadset " +
|
||||
"bt: ${signalBluetoothManager.state} " +
|
||||
"bt: ${signalBluetoothManager!!.state} " +
|
||||
"available: $audioDevices " +
|
||||
"selected: $selectedAudioDevice " +
|
||||
"userSelected: $userSelectedAudioDevice"
|
||||
)
|
||||
|
||||
if (signalBluetoothManager.state.shouldUpdate()) {
|
||||
signalBluetoothManager.updateDevice()
|
||||
if (signalBluetoothManager!!.state.shouldUpdate()) {
|
||||
signalBluetoothManager!!.updateDevice()
|
||||
}
|
||||
|
||||
val newAudioDevices = mutableSetOf(AudioDevice.SPEAKER_PHONE)
|
||||
|
||||
if (signalBluetoothManager.state.hasDevice()) {
|
||||
if (signalBluetoothManager!!.state.hasDevice()) {
|
||||
newAudioDevices += AudioDevice.BLUETOOTH
|
||||
}
|
||||
|
||||
@@ -217,7 +222,7 @@ class SignalAudioManager(private val context: Context,
|
||||
var audioDeviceSetUpdated = audioDevices != newAudioDevices
|
||||
audioDevices = newAudioDevices
|
||||
|
||||
if (signalBluetoothManager.state == SignalBluetoothManager.State.UNAVAILABLE && userSelectedAudioDevice == AudioDevice.BLUETOOTH) {
|
||||
if (signalBluetoothManager!!.state == SignalBluetoothManager.State.UNAVAILABLE && userSelectedAudioDevice == AudioDevice.BLUETOOTH) {
|
||||
userSelectedAudioDevice = AudioDevice.NONE
|
||||
}
|
||||
|
||||
@@ -230,33 +235,33 @@ class SignalAudioManager(private val context: Context,
|
||||
userSelectedAudioDevice = AudioDevice.NONE
|
||||
}
|
||||
|
||||
val needBluetoothAudioStart = signalBluetoothManager.state == SignalBluetoothManager.State.AVAILABLE &&
|
||||
val needBluetoothAudioStart = signalBluetoothManager!!.state == SignalBluetoothManager.State.AVAILABLE &&
|
||||
(userSelectedAudioDevice == AudioDevice.NONE || userSelectedAudioDevice == AudioDevice.BLUETOOTH || autoSwitchToBluetooth)
|
||||
|
||||
val needBluetoothAudioStop = (signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTED || signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTING) &&
|
||||
val needBluetoothAudioStop = (signalBluetoothManager!!.state == SignalBluetoothManager.State.CONNECTED || signalBluetoothManager!!.state == SignalBluetoothManager.State.CONNECTING) &&
|
||||
(userSelectedAudioDevice != AudioDevice.NONE && userSelectedAudioDevice != AudioDevice.BLUETOOTH)
|
||||
|
||||
if (signalBluetoothManager.state.hasDevice()) {
|
||||
Log.i(TAG, "Need bluetooth audio: state: ${signalBluetoothManager.state} start: $needBluetoothAudioStart stop: $needBluetoothAudioStop")
|
||||
if (signalBluetoothManager!!.state.hasDevice()) {
|
||||
Log.i(TAG, "Need bluetooth audio: state: ${signalBluetoothManager!!.state} start: $needBluetoothAudioStart stop: $needBluetoothAudioStop")
|
||||
}
|
||||
|
||||
if (needBluetoothAudioStop) {
|
||||
signalBluetoothManager.stopScoAudio()
|
||||
signalBluetoothManager.updateDevice()
|
||||
signalBluetoothManager!!.stopScoAudio()
|
||||
signalBluetoothManager!!.updateDevice()
|
||||
}
|
||||
|
||||
if (!autoSwitchToBluetooth && signalBluetoothManager.state == SignalBluetoothManager.State.UNAVAILABLE) {
|
||||
if (!autoSwitchToBluetooth && signalBluetoothManager!!.state == SignalBluetoothManager.State.UNAVAILABLE) {
|
||||
autoSwitchToBluetooth = true
|
||||
}
|
||||
|
||||
if (needBluetoothAudioStart && !needBluetoothAudioStop) {
|
||||
if (!signalBluetoothManager.startScoAudio()) {
|
||||
if (!signalBluetoothManager!!.startScoAudio()) {
|
||||
audioDevices.remove(AudioDevice.BLUETOOTH)
|
||||
audioDeviceSetUpdated = true
|
||||
}
|
||||
}
|
||||
|
||||
if (autoSwitchToBluetooth && signalBluetoothManager.state == SignalBluetoothManager.State.CONNECTED) {
|
||||
if (autoSwitchToBluetooth && signalBluetoothManager!!.state == SignalBluetoothManager.State.CONNECTED) {
|
||||
userSelectedAudioDevice = AudioDevice.BLUETOOTH
|
||||
autoSwitchToBluetooth = false
|
||||
}
|
||||
@@ -373,7 +378,7 @@ class SignalAudioManager(private val context: Context,
|
||||
val pluggedIn = intent.getIntExtra("state", 0) == 1
|
||||
val hasMic = intent.getIntExtra("microphone", 0) == 1
|
||||
|
||||
handler.post { onWiredHeadsetChange(pluggedIn, hasMic) }
|
||||
handler?.post { onWiredHeadsetChange(pluggedIn, hasMic) }
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 834 B |
BIN
app/src/main/res/drawable-anydpi-v24/ic_close_grey600_32dp.webp
Normal file
BIN
app/src/main/res/drawable-anydpi-v24/ic_close_grey600_32dp.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 404 B |
BIN
app/src/main/res/drawable-anydpi-v24/ic_phone_grey600_32dp.webp
Normal file
BIN
app/src/main/res/drawable-anydpi-v24/ic_phone_grey600_32dp.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 966 B |
Reference in New Issue
Block a user