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() + } +}