diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java index ea248a0f0..07866e142 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.java @@ -72,6 +72,7 @@ import com.nextcloud.talk.models.json.signaling.SignalingOverall; import com.nextcloud.talk.models.json.signaling.settings.IceServer; import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall; import com.nextcloud.talk.utils.ApiUtils; +import com.nextcloud.talk.utils.MagicFlipView; import com.nextcloud.talk.utils.animations.PulseAnimation; import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; @@ -152,6 +153,9 @@ public class CallController extends BaseController { Manifest.permission.RECORD_AUDIO }; + @BindView(R.id.callControlEnableSpeaker) + MagicFlipView callControlEnableSpeaker; + @BindView(R.id.pip_video_view) SurfaceViewRenderer pipVideoView; @BindView(R.id.relative_layout) @@ -300,6 +304,10 @@ public class CallController extends BaseController { Log.e(TAG, "Failed to evict cache"); } + if (isVoiceOnlyCall) { + callControlEnableSpeaker.setVisibility(View.VISIBLE); + } + callControls.setZ(100.0f); basicInitialization(); @@ -330,7 +338,7 @@ public class CallController extends BaseController { // Create and audio manager that will take care of audio routing, // audio modes, audio device enumeration etc. - audioManager = MagicAudioManager.create(getApplicationContext()); + audioManager = MagicAudioManager.create(getApplicationContext(), !isVoiceOnlyCall); // Store existing audio settings and change audio mode to // MODE_IN_COMMUNICATION for best possible VoIP performance. Log.d(TAG, "Starting the audio manager..."); @@ -422,7 +430,7 @@ public class CallController extends BaseController { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(PERMISSIONS_CALL, 100); } else { - onRequestPermissionsResult(100, PERMISSIONS_CALL, new int[]{1}); + onRequestPermissionsResult(100, PERMISSIONS_CALL, new int[]{1, 1}); } } @@ -586,6 +594,20 @@ public class CallController extends BaseController { return true; } + @OnClick(R.id.callControlEnableSpeaker) + public void onEnableSpeakerphoneClick() { + if (audioManager != null) { + audioManager.toggleUseSpeakerphone(); + if (audioManager.isSpeakerphoneAutoOn()) { + callControlEnableSpeaker.getFrontImageView().setImageDrawable(getResources().getDrawable(R.drawable + .ic_speaker_white_24dp)); + } else { + callControlEnableSpeaker.getFrontImageView().setImageDrawable(getResources().getDrawable(R.drawable + .ic_hearing_white_24dp)); + } + } + } + @OnClick(R.id.call_control_microphone) public void onMicrophoneClick() { if (getActivity() != null && EffortlessPermissions.hasPermissions(getActivity(), PERMISSIONS_MICROPHONE)) { diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/MagicAudioManager.java b/app/src/main/java/com/nextcloud/talk/webrtc/MagicAudioManager.java index 3fa5cadff..5afa153a7 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicAudioManager.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/MagicAudioManager.java @@ -59,7 +59,7 @@ public class MagicAudioManager { private static final String SPEAKERPHONE_FALSE = "false"; private final Context magicContext; // Contains speakerphone setting: auto, true or false - private final String useSpeakerphone; + private String useSpeakerphone; // Handles all tasks related to Bluetooth headset devices. private final MagicBluetoothManager bluetoothManager; private AudioManager audioManager; @@ -96,7 +96,23 @@ public class MagicAudioManager { // Callback method for changes in audio focus. private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener; - private MagicAudioManager(Context context) { + public void toggleUseSpeakerphone() { + if (useSpeakerphone.equals(SPEAKERPHONE_FALSE)) { + useSpeakerphone = SPEAKERPHONE_AUTO; + setDefaultAudioDevice(AudioDevice.SPEAKER_PHONE); + } else { + useSpeakerphone = SPEAKERPHONE_FALSE; + setDefaultAudioDevice(AudioDevice.EARPIECE); + } + + updateAudioDeviceState(); + } + + public boolean isSpeakerphoneAutoOn() { + return (useSpeakerphone.equals(SPEAKERPHONE_AUTO)); + } + + private MagicAudioManager(Context context, boolean useProximitySensor) { Log.d(TAG, "ctor"); ThreadUtils.checkIsOnMainThread(); magicContext = context; @@ -105,7 +121,13 @@ public class MagicAudioManager { wiredHeadsetReceiver = new WiredHeadsetReceiver(); amState = AudioManagerState.UNINITIALIZED; - useSpeakerphone = SPEAKERPHONE_AUTO; + if (useProximitySensor) { + useSpeakerphone = SPEAKERPHONE_AUTO; + } else { + useSpeakerphone = SPEAKERPHONE_FALSE; + } + + if (useSpeakerphone.equals(SPEAKERPHONE_FALSE)) { defaultAudioDevice = AudioDevice.EARPIECE; } else { @@ -130,8 +152,8 @@ public class MagicAudioManager { /** * Construction. */ - public static MagicAudioManager create(Context context) { - return new MagicAudioManager(context); + public static MagicAudioManager create(Context context, boolean useProximitySensor) { + return new MagicAudioManager(context, useProximitySensor); } /** @@ -140,14 +162,6 @@ public class MagicAudioManager { */ private void onProximitySensorChangedState() { - if (proximitySensor.sensorReportsNearState()) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType - .SENSOR_NEAR, null, null, null)); - } else { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType - .SENSOR_FAR, null, null, null)); - } - if (!useSpeakerphone.equals(SPEAKERPHONE_AUTO)) { return; } @@ -160,10 +174,17 @@ public class MagicAudioManager { // Sensor reports that a "handset is being held up to a person's ear", // or "something is covering the light sensor". setAudioDeviceInternal(MagicAudioManager.AudioDevice.EARPIECE); + + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType + .SENSOR_FAR, null, null, null)); + } else { // Sensor reports that a "handset is removed from a person's ear", or // "the light sensor is no longer covered". setAudioDeviceInternal(MagicAudioManager.AudioDevice.SPEAKER_PHONE); + + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType + .SENSOR_NEAR, null, null, null)); } } } diff --git a/app/src/main/res/drawable/ic_hearing_white_24dp.xml b/app/src/main/res/drawable/ic_hearing_white_24dp.xml new file mode 100644 index 000000000..d335efbba --- /dev/null +++ b/app/src/main/res/drawable/ic_hearing_white_24dp.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_speaker_white_24dp.xml b/app/src/main/res/drawable/ic_speaker_white_24dp.xml new file mode 100644 index 000000000..b06e76e66 --- /dev/null +++ b/app/src/main/res/drawable/ic_speaker_white_24dp.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/app/src/main/res/layout/controller_call.xml b/app/src/main/res/layout/controller_call.xml index 9c7bddd45..7aa7485cd 100644 --- a/app/src/main/res/layout/controller_call.xml +++ b/app/src/main/res/layout/controller_call.xml @@ -140,6 +140,19 @@ app:enableInitialAnimation="false" app:frontBackgroundColor="@color/nc_darkRed" app:frontImage="@drawable/ic_call_end_white_24px"/> + + + - \ No newline at end of file +