From 96845d31dbbb42e672d37df331e87294a4ad74aa Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 31 Aug 2020 14:03:52 +0300 Subject: [PATCH 01/10] Proximity sensor implementation. --- .../app/features/call/CallProximityManager.kt | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt diff --git a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt new file mode 100644 index 0000000000..4da1c3fa45 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.call + +import android.annotation.SuppressLint +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import android.os.PowerManager +import im.vector.app.R +import javax.inject.Inject + +/** + * Manages the proximity sensor and turns the screen off when the proximity sensor activates. + */ +class CallProximityManager @Inject constructor(val context: Context) : SensorEventListener { + + private val PROXIMITY_WAKE_LOCK_TAG = "PROXIMITY_WAKE_LOCK_TAG" + + private lateinit var powerManager: PowerManager + private lateinit var sensorManager: SensorManager + + private var wakeLock: PowerManager.WakeLock? = null + private var sensor: Sensor? = null + + /** + * Start listening the proximity sensor. [stop] function should be called to release the sensor and the WakeLock. + */ + fun start() { + powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager + sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) + + if (sensor != null && powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { + sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL) + } + } + + /** + * Stop listening proximity sensor changes and release the WakeLock. + */ + fun stop() { + if (this::sensorManager.isInitialized) { + sensorManager.unregisterListener(this) + } + wakeLock?.release() + } + + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { + // NOOP + } + + override fun onSensorChanged(event: SensorEvent) { + val distanceInCentimeters = event.values[0] + if (distanceInCentimeters < sensor?.maximumRange ?: 0f) { + onProximityNear() + } else { + onProximityFar() + } + } + + /** + * Recommending naming convention for WakeLock tags is "app:tag" + */ + private fun generateWakeLockTag() = "${context.getString(R.string.app_name)}:$PROXIMITY_WAKE_LOCK_TAG" + + @SuppressLint("WakelockTimeout") + private fun onProximityNear() { + wakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, generateWakeLockTag()) + wakeLock?.acquire() + } + + private fun onProximityFar() { + wakeLock?.release() + } +} From 8e3d83579b5a030b6c9e3364931765dd4b4da5a5 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 31 Aug 2020 14:04:43 +0300 Subject: [PATCH 02/10] Remove attachBaseContext to fix the crash. --- .../main/java/im/vector/app/core/services/VectorService.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/VectorService.kt b/vector/src/main/java/im/vector/app/core/services/VectorService.kt index 223d720d8a..888f7a8cac 100644 --- a/vector/src/main/java/im/vector/app/core/services/VectorService.kt +++ b/vector/src/main/java/im/vector/app/core/services/VectorService.kt @@ -17,10 +17,8 @@ package im.vector.app.core.services import android.app.Service -import android.content.Context import android.content.Intent import android.os.IBinder -import im.vector.app.core.extensions.vectorComponent import timber.log.Timber /** @@ -33,10 +31,6 @@ abstract class VectorService : Service() { */ private var mIsSelfDestroyed = false - override fun attachBaseContext(base: Context) { - super.attachBaseContext(vectorComponent().vectorConfiguration().getLocalisedContext(base)) - } - override fun onCreate() { super.onCreate() From b89b3db077cb1c0731e7735a4f5e6c1a73d1a44f Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 31 Aug 2020 14:06:15 +0300 Subject: [PATCH 03/10] Use proximity manager to turn the screen off while the ear speaker is used. --- .../app/features/call/VectorCallViewModel.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index 8ad1b1a267..1fb9f83e1f 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -87,7 +87,8 @@ class VectorCallViewModel @AssistedInject constructor( @Assisted initialState: VectorCallViewState, @Assisted val args: CallArgs, val session: Session, - val webRtcPeerConnectionManager: WebRtcPeerConnectionManager + val webRtcPeerConnectionManager: WebRtcPeerConnectionManager, + val proximityManager: CallProximityManager ) : VectorViewModel(initialState) { var call: MxCall? = null @@ -145,10 +146,17 @@ class VectorCallViewModel @AssistedInject constructor( } override fun onAudioDevicesChange(mgr: WebRtcPeerConnectionManager) { + val currentSoundDevice = mgr.audioManager.getCurrentSoundDevice() + if (currentSoundDevice == CallAudioManager.SoundDevice.PHONE) { + proximityManager.start() + } else { + proximityManager.stop() + } + setState { copy( availableSoundDevices = mgr.audioManager.getAvailableSoundDevices(), - soundDevice = mgr.audioManager.getCurrentSoundDevice() + soundDevice = currentSoundDevice ) } } @@ -175,12 +183,18 @@ class VectorCallViewModel @AssistedInject constructor( val item: MatrixItem? = session.getUser(mxCall.otherUserId)?.toMatrixItem() mxCall.addListener(callStateListener) + + val currentSoundDevice = webRtcPeerConnectionManager.audioManager.getCurrentSoundDevice() + if (currentSoundDevice == CallAudioManager.SoundDevice.PHONE) { + proximityManager.start() + } + setState { copy( isVideoCall = mxCall.isVideoCall, callState = Success(mxCall.state), otherUserMatrixItem = item?.let { Success(it) } ?: Uninitialized, - soundDevice = webRtcPeerConnectionManager.audioManager.getCurrentSoundDevice(), + soundDevice = currentSoundDevice, availableSoundDevices = webRtcPeerConnectionManager.audioManager.getAvailableSoundDevices(), isFrontCamera = webRtcPeerConnectionManager.currentCameraType() == CameraType.FRONT, canSwitchCamera = webRtcPeerConnectionManager.canSwitchCamera(), @@ -201,6 +215,7 @@ class VectorCallViewModel @AssistedInject constructor( // session.callService().removeCallListener(callServiceListener) webRtcPeerConnectionManager.removeCurrentCallListener(currentCallListener) this.call?.removeListener(callStateListener) + proximityManager.stop() super.onCleared() } From 78728380568c4fb22279e7a8e7cef324ff086dee Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 31 Aug 2020 14:06:41 +0300 Subject: [PATCH 04/10] Changelog added. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index db98189499..09e1775ae2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Improvements 🙌: - Add long click gesture to copy userId, user display name, room name, room topic and room alias (#1774) - Fix several issues when uploading bug files (#1889) - Do not propose to verify session if there is only one session and 4S is not configured (#1901) + - Call screen does not use proximity sensor (#1735) Bugfix 🐛: - Display name not shown under Settings/General (#1926) From bd05484b2d0b5619268f2a141be51c62163bfb31 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 1 Sep 2020 10:58:45 +0300 Subject: [PATCH 05/10] Initialize fields in the constructor. --- .../app/features/call/CallProximityManager.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt index 4da1c3fa45..357fe8d41e 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt @@ -39,14 +39,16 @@ class CallProximityManager @Inject constructor(val context: Context) : SensorEve private var wakeLock: PowerManager.WakeLock? = null private var sensor: Sensor? = null + init { + powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager + sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) + } + /** * Start listening the proximity sensor. [stop] function should be called to release the sensor and the WakeLock. */ fun start() { - powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager - sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager - sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) - if (sensor != null && powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL) } @@ -56,9 +58,7 @@ class CallProximityManager @Inject constructor(val context: Context) : SensorEve * Stop listening proximity sensor changes and release the WakeLock. */ fun stop() { - if (this::sensorManager.isInitialized) { - sensorManager.unregisterListener(this) - } + sensorManager.unregisterListener(this) wakeLock?.release() } From 914ec895ee4216a1115139a55379c02e8308d424 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 4 Sep 2020 17:00:33 +0300 Subject: [PATCH 06/10] Use ContextCompat.getSystemService function. --- .../im/vector/app/features/call/CallProximityManager.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt index 357fe8d41e..40b760ad52 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt @@ -23,6 +23,7 @@ import android.hardware.SensorEvent import android.hardware.SensorEventListener import android.hardware.SensorManager import android.os.PowerManager +import androidx.core.content.ContextCompat.getSystemService import im.vector.app.R import javax.inject.Inject @@ -33,15 +34,13 @@ class CallProximityManager @Inject constructor(val context: Context) : SensorEve private val PROXIMITY_WAKE_LOCK_TAG = "PROXIMITY_WAKE_LOCK_TAG" - private lateinit var powerManager: PowerManager - private lateinit var sensorManager: SensorManager + private var powerManager: PowerManager = getSystemService(context, PowerManager::class.java)!! + private var sensorManager: SensorManager = getSystemService(context, SensorManager::class.java)!! private var wakeLock: PowerManager.WakeLock? = null private var sensor: Sensor? = null init { - powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager - sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) } From e790c3527037538ad7346a799267a562cf33a398 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 4 Sep 2020 17:02:44 +0300 Subject: [PATCH 07/10] Use stringProvider. --- .../im/vector/app/features/call/CallProximityManager.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt index 40b760ad52..99719236bb 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt @@ -25,12 +25,15 @@ import android.hardware.SensorManager import android.os.PowerManager import androidx.core.content.ContextCompat.getSystemService import im.vector.app.R +import im.vector.app.core.resources.StringProvider import javax.inject.Inject /** * Manages the proximity sensor and turns the screen off when the proximity sensor activates. */ -class CallProximityManager @Inject constructor(val context: Context) : SensorEventListener { +class CallProximityManager @Inject constructor(val context: Context, + val stringProvider: StringProvider +) : SensorEventListener { private val PROXIMITY_WAKE_LOCK_TAG = "PROXIMITY_WAKE_LOCK_TAG" @@ -77,7 +80,7 @@ class CallProximityManager @Inject constructor(val context: Context) : SensorEve /** * Recommending naming convention for WakeLock tags is "app:tag" */ - private fun generateWakeLockTag() = "${context.getString(R.string.app_name)}:$PROXIMITY_WAKE_LOCK_TAG" + private fun generateWakeLockTag() = "${stringProvider.getString(R.string.app_name)}:$PROXIMITY_WAKE_LOCK_TAG" @SuppressLint("WakelockTimeout") private fun onProximityNear() { From 8045d61e1f37740153c13b461a4ec0514e30e1f9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 4 Sep 2020 17:19:11 +0200 Subject: [PATCH 08/10] Code cleanup --- .../app/features/call/CallProximityManager.kt | 34 ++++++++++--------- .../app/features/call/VectorCallViewModel.kt | 2 -- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt index 99719236bb..bcbf757ad0 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt @@ -16,14 +16,13 @@ package im.vector.app.features.call -import android.annotation.SuppressLint import android.content.Context import android.hardware.Sensor import android.hardware.SensorEvent import android.hardware.SensorEventListener import android.hardware.SensorManager import android.os.PowerManager -import androidx.core.content.ContextCompat.getSystemService +import androidx.core.content.getSystemService import im.vector.app.R import im.vector.app.core.resources.StringProvider import javax.inject.Inject @@ -31,21 +30,23 @@ import javax.inject.Inject /** * Manages the proximity sensor and turns the screen off when the proximity sensor activates. */ -class CallProximityManager @Inject constructor(val context: Context, - val stringProvider: StringProvider +class CallProximityManager @Inject constructor( + context: Context, + private val stringProvider: StringProvider ) : SensorEventListener { - private val PROXIMITY_WAKE_LOCK_TAG = "PROXIMITY_WAKE_LOCK_TAG" + companion object { + private const val PROXIMITY_WAKE_LOCK_TAG = "PROXIMITY_WAKE_LOCK_TAG" - private var powerManager: PowerManager = getSystemService(context, PowerManager::class.java)!! - private var sensorManager: SensorManager = getSystemService(context, SensorManager::class.java)!! + // 1 hour + private const val WAKE_LOCK_TIMEOUT_MILLIS = 3_600_000L + } + + private val powerManager = context.getSystemService()!! + private val sensorManager = context.getSystemService()!! private var wakeLock: PowerManager.WakeLock? = null - private var sensor: Sensor? = null - - init { - sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) - } + private var sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) /** * Start listening the proximity sensor. [stop] function should be called to release the sensor and the WakeLock. @@ -70,7 +71,7 @@ class CallProximityManager @Inject constructor(val context: Context, override fun onSensorChanged(event: SensorEvent) { val distanceInCentimeters = event.values[0] - if (distanceInCentimeters < sensor?.maximumRange ?: 0f) { + if (distanceInCentimeters < sensor?.maximumRange ?: 20f) { onProximityNear() } else { onProximityFar() @@ -82,10 +83,11 @@ class CallProximityManager @Inject constructor(val context: Context, */ private fun generateWakeLockTag() = "${stringProvider.getString(R.string.app_name)}:$PROXIMITY_WAKE_LOCK_TAG" - @SuppressLint("WakelockTimeout") private fun onProximityNear() { - wakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, generateWakeLockTag()) - wakeLock?.acquire() + if (wakeLock == null) { + wakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, generateWakeLockTag()) + } + wakeLock?.acquire(WAKE_LOCK_TIMEOUT_MILLIS) } private fun onProximityFar() { diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt index 1fb9f83e1f..cee67cd818 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallViewModel.kt @@ -172,9 +172,7 @@ class VectorCallViewModel @AssistedInject constructor( } init { - initialState.callId?.let { - webRtcPeerConnectionManager.addCurrentCallListener(currentCallListener) session.callSignalingService().getCallWithId(it)?.let { mxCall -> From 8ead3716035b9c7f25d2182e14169393e9f927c8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 4 Sep 2020 18:43:59 +0200 Subject: [PATCH 09/10] Fix crash with WakeLock --- .../im/vector/app/features/call/CallProximityManager.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt index bcbf757ad0..1b561f7990 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt @@ -62,7 +62,9 @@ class CallProximityManager @Inject constructor( */ fun stop() { sensorManager.unregisterListener(this) - wakeLock?.release() + wakeLock + ?.takeIf { it.isHeld } + ?.release() } override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { @@ -91,6 +93,8 @@ class CallProximityManager @Inject constructor( } private fun onProximityFar() { - wakeLock?.release() + wakeLock + ?.takeIf { it.isHeld } + ?.release() } } From f689871fc0cf3a99b7b7bfab63571fe5ed2d9b65 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 4 Sep 2020 18:45:49 +0200 Subject: [PATCH 10/10] Code symmetry --- .../app/features/call/CallProximityManager.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt index 1b561f7990..74e6c40783 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallProximityManager.kt @@ -46,13 +46,15 @@ class CallProximityManager @Inject constructor( private val sensorManager = context.getSystemService()!! private var wakeLock: PowerManager.WakeLock? = null - private var sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) + private val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) + + private val isSupported = sensor != null && powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) /** * Start listening the proximity sensor. [stop] function should be called to release the sensor and the WakeLock. */ fun start() { - if (sensor != null && powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { + if (isSupported) { sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL) } } @@ -61,10 +63,12 @@ class CallProximityManager @Inject constructor( * Stop listening proximity sensor changes and release the WakeLock. */ fun stop() { - sensorManager.unregisterListener(this) - wakeLock - ?.takeIf { it.isHeld } - ?.release() + if (isSupported) { + sensorManager.unregisterListener(this) + wakeLock + ?.takeIf { it.isHeld } + ?.release() + } } override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {