Merge "Introduce AmbientLightModeMonitor."
This commit is contained in:
committed by
Android (Google) Code Review
commit
00b3b61f5a
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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 com.android.systemui.idle
|
||||
|
||||
import android.annotation.IntDef
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import android.util.Log
|
||||
import com.android.systemui.util.sensors.AsyncSensorManager
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* Monitors ambient light signals, applies a debouncing algorithm, and produces the current
|
||||
* [AmbientLightMode].
|
||||
*
|
||||
* For debouncer behavior, refer to go/titan-light-sensor-debouncer.
|
||||
*
|
||||
* @property sensorManager the sensor manager used to register sensor event updates.
|
||||
*/
|
||||
class AmbientLightModeMonitor @Inject constructor(
|
||||
private val sensorManager: AsyncSensorManager
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "AmbientLightModeMonitor"
|
||||
private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
|
||||
|
||||
const val AMBIENT_LIGHT_MODE_LIGHT = 0
|
||||
const val AMBIENT_LIGHT_MODE_DARK = 1
|
||||
const val AMBIENT_LIGHT_MODE_UNDECIDED = 2
|
||||
}
|
||||
|
||||
// Light sensor used to detect ambient lighting conditions.
|
||||
private val lightSensor: Sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
|
||||
|
||||
// Registered callback, which gets triggered when the ambient light mode changes.
|
||||
private var callback: Callback? = null
|
||||
|
||||
// Represents all ambient light modes.
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@IntDef(AMBIENT_LIGHT_MODE_LIGHT, AMBIENT_LIGHT_MODE_DARK, AMBIENT_LIGHT_MODE_UNDECIDED)
|
||||
annotation class AmbientLightMode
|
||||
|
||||
// The current ambient light mode.
|
||||
@AmbientLightMode private var mode: Int by Delegates.observable(AMBIENT_LIGHT_MODE_UNDECIDED
|
||||
) { _, old, new ->
|
||||
if (old != new) {
|
||||
callback?.onChange(new)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start monitoring the current ambient light mode.
|
||||
*
|
||||
* @param callback callback that gets triggered when the ambient light mode changes. It also
|
||||
* gets triggered immediately to update the current value when this function is called.
|
||||
*/
|
||||
fun start(callback: Callback) {
|
||||
if (DEBUG) Log.d(TAG, "start monitoring ambient light mode")
|
||||
|
||||
if (this.callback != null) {
|
||||
if (DEBUG) Log.w(TAG, "already started")
|
||||
return
|
||||
}
|
||||
|
||||
this.callback = callback
|
||||
callback.onChange(mode)
|
||||
|
||||
sensorManager.registerListener(mSensorEventListener, lightSensor,
|
||||
SensorManager.SENSOR_DELAY_NORMAL)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop monitoring the current ambient light mode.
|
||||
*/
|
||||
fun stop() {
|
||||
if (DEBUG) Log.d(TAG, "stop monitoring ambient light mode")
|
||||
|
||||
if (callback == null) {
|
||||
if (DEBUG) Log.w(TAG, "haven't started")
|
||||
return
|
||||
}
|
||||
|
||||
callback = null
|
||||
sensorManager.unregisterListener(mSensorEventListener)
|
||||
}
|
||||
|
||||
private val mSensorEventListener: SensorEventListener = object : SensorEventListener {
|
||||
override fun onSensorChanged(event: SensorEvent) {
|
||||
if (event.values.isEmpty()) {
|
||||
if (DEBUG) Log.w(TAG, "SensorEvent doesn't have any value")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(b/201657509): add debouncing logic.
|
||||
val shouldBeLowLight = event.values[0] < 10
|
||||
mode = if (shouldBeLowLight) AMBIENT_LIGHT_MODE_DARK else AMBIENT_LIGHT_MODE_LIGHT
|
||||
}
|
||||
|
||||
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface of the ambient light mode callback, which gets triggered when the mode changes.
|
||||
*/
|
||||
interface Callback {
|
||||
fun onChange(@AmbientLightMode mode: Int)
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemClock;
|
||||
@@ -44,7 +40,6 @@ import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.ViewController;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -56,8 +51,7 @@ import javax.inject.Provider;
|
||||
/**
|
||||
* {@link IdleHostViewController} processes signals to control the lifecycle of the idle screen.
|
||||
*/
|
||||
public class IdleHostViewController extends ViewController<IdleHostView> implements
|
||||
SensorEventListener {
|
||||
public class IdleHostViewController extends ViewController<IdleHostView> {
|
||||
private static final String INPUT_MONITOR_IDENTIFIER = "IdleHostViewController";
|
||||
private static final String TAG = "IdleHostViewController";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
@@ -114,11 +108,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
|
||||
private final PowerManager mPowerManager;
|
||||
|
||||
private final AsyncSensorManager mSensorManager;
|
||||
|
||||
// Light sensor used to detect low light condition.
|
||||
private final Sensor mSensor;
|
||||
|
||||
// Runnable for canceling enabling idle.
|
||||
private Runnable mCancelEnableIdling;
|
||||
|
||||
@@ -146,6 +135,9 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
// Intent filter for receiving dream broadcasts.
|
||||
private IntentFilter mDreamIntentFilter;
|
||||
|
||||
// Monitor for the current ambient light mode. Used to trigger / exit low-light mode.
|
||||
private final AmbientLightModeMonitor mAmbientLightModeMonitor;
|
||||
|
||||
// Delayed callback for starting idling.
|
||||
private final Runnable mEnableIdlingCallback = () -> {
|
||||
if (DEBUG) {
|
||||
@@ -181,6 +173,31 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
}
|
||||
};
|
||||
|
||||
private final AmbientLightModeMonitor.Callback mAmbientLightModeCallback =
|
||||
mode -> {
|
||||
boolean shouldBeLowLight;
|
||||
switch (mode) {
|
||||
case AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_UNDECIDED:
|
||||
return;
|
||||
case AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT:
|
||||
shouldBeLowLight = false;
|
||||
break;
|
||||
case AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK:
|
||||
shouldBeLowLight = true;
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "invalid ambient light mode");
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "ambient light mode changed to " + mode);
|
||||
|
||||
final boolean isLowLight = getState(STATE_LOW_LIGHT);
|
||||
if (shouldBeLowLight != isLowLight) {
|
||||
setState(STATE_LOW_LIGHT, shouldBeLowLight);
|
||||
}
|
||||
};
|
||||
|
||||
final Provider<View> mIdleViewProvider;
|
||||
|
||||
@Inject
|
||||
@@ -188,7 +205,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
Context context,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
PowerManager powerManager,
|
||||
AsyncSensorManager sensorManager,
|
||||
IdleHostView view, InputMonitorFactory factory,
|
||||
@Main DelayableExecutor delayableExecutor,
|
||||
@Main Resources resources,
|
||||
@@ -197,18 +213,19 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
Choreographer choreographer,
|
||||
KeyguardStateController keyguardStateController,
|
||||
StatusBarStateController statusBarStateController,
|
||||
DreamHelper dreamHelper) {
|
||||
DreamHelper dreamHelper,
|
||||
AmbientLightModeMonitor ambientLightModeMonitor) {
|
||||
super(view);
|
||||
mContext = context;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mPowerManager = powerManager;
|
||||
mSensorManager = sensorManager;
|
||||
mIdleViewProvider = idleViewProvider;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mLooper = looper;
|
||||
mChoreographer = choreographer;
|
||||
mDreamHelper = dreamHelper;
|
||||
mAmbientLightModeMonitor = ambientLightModeMonitor;
|
||||
|
||||
mState = STATE_KEYGUARD_SHOWING;
|
||||
|
||||
@@ -222,7 +239,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
mIdleTimeout = resources.getInteger(R.integer.config_idleModeTimeout);
|
||||
mInputMonitorFactory = factory;
|
||||
mDelayableExecutor = delayableExecutor;
|
||||
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "initial state:" + mState + " enabled:" + enabled
|
||||
@@ -405,11 +421,10 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
|
||||
if (mIsMonitoringLowLight) {
|
||||
if (DEBUG) Log.d(TAG, "enable low light monitoring");
|
||||
mSensorManager.registerListener(this /*listener*/, mSensor,
|
||||
SensorManager.SENSOR_DELAY_NORMAL);
|
||||
mAmbientLightModeMonitor.start(mAmbientLightModeCallback);
|
||||
} else {
|
||||
if (DEBUG) Log.d(TAG, "disable low light monitoring");
|
||||
mSensorManager.unregisterListener(this);
|
||||
mAmbientLightModeMonitor.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,28 +464,6 @@ public class IdleHostViewController extends ViewController<IdleHostView> impleme
|
||||
mStatusBarStateController.removeCallback(mStatusBarCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (event.values.length == 0) {
|
||||
if (DEBUG) Log.w(TAG, "SensorEvent doesn't have value");
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean shouldBeLowLight = event.values[0] < 10;
|
||||
final boolean isLowLight = getState(STATE_LOW_LIGHT);
|
||||
|
||||
if (shouldBeLowLight != isLowLight) {
|
||||
setState(STATE_LOW_LIGHT, shouldBeLowLight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onAccuracyChanged accuracy=" + accuracy);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether the device just stopped idling by comparing the previous state with the
|
||||
// current one.
|
||||
private boolean stoppedIdling(int oldState) {
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* 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 com.android.systemui.idle
|
||||
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.sensors.AsyncSensorManager
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.reset
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class AmbientLightModeMonitorTest : SysuiTestCase() {
|
||||
@Mock private lateinit var sensorManager: AsyncSensorManager
|
||||
@Mock private lateinit var sensor: Sensor
|
||||
|
||||
private lateinit var ambientLightModeMonitor: AmbientLightModeMonitor
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
`when`(sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(sensor)
|
||||
ambientLightModeMonitor = AmbientLightModeMonitor(sensorManager)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldTriggerCallbackImmediatelyOnStart() {
|
||||
val callback = mock(AmbientLightModeMonitor.Callback::class.java)
|
||||
ambientLightModeMonitor.start(callback)
|
||||
|
||||
// Monitor just started, should receive UNDECIDED.
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_UNDECIDED)
|
||||
|
||||
// Receives SensorEvent, and now mode is LIGHT.
|
||||
val sensorEventListener = captureSensorEventListener()
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(15f))
|
||||
|
||||
// Stop monitor.
|
||||
ambientLightModeMonitor.stop()
|
||||
|
||||
// Restart monitor.
|
||||
reset(callback)
|
||||
ambientLightModeMonitor.start(callback)
|
||||
|
||||
// Verify receiving current mode (LIGHT) immediately.
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldReportDarkModeWhenSensorValueIsLessThanTen() {
|
||||
val callback = mock(AmbientLightModeMonitor.Callback::class.java)
|
||||
ambientLightModeMonitor.start(callback)
|
||||
|
||||
val sensorEventListener = captureSensorEventListener()
|
||||
reset(callback)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(0f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(1f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(5f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(9.9f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldReportLightModeWhenSensorValueIsGreaterThanOrEqualToTen() {
|
||||
val callback = mock(AmbientLightModeMonitor.Callback::class.java)
|
||||
ambientLightModeMonitor.start(callback)
|
||||
|
||||
val sensorEventListener = captureSensorEventListener()
|
||||
reset(callback)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(10f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(10.1f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(15f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT)
|
||||
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(100f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldOnlyTriggerCallbackWhenValueChanges() {
|
||||
val callback = mock(AmbientLightModeMonitor.Callback::class.java)
|
||||
ambientLightModeMonitor.start(callback)
|
||||
|
||||
val sensorEventListener = captureSensorEventListener()
|
||||
|
||||
// Light mode, should trigger callback.
|
||||
reset(callback)
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(20f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT)
|
||||
|
||||
// Light mode again, should NOT trigger callback.
|
||||
reset(callback)
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(25f))
|
||||
verify(callback, never()).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT)
|
||||
|
||||
// Dark mode, should trigger callback.
|
||||
reset(callback)
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(2f))
|
||||
verify(callback).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK)
|
||||
|
||||
// Dark mode again, should not trigger callback.
|
||||
reset(callback)
|
||||
sensorEventListener.onSensorChanged(sensorEventWithSingleValue(3f))
|
||||
verify(callback, never()).onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK)
|
||||
}
|
||||
|
||||
// Captures [SensorEventListener], assuming it has been registered with [sensorManager].
|
||||
private fun captureSensorEventListener(): SensorEventListener {
|
||||
val captor = ArgumentCaptor.forClass(SensorEventListener::class.java)
|
||||
verify(sensorManager).registerListener(captor.capture(), any(), anyInt())
|
||||
return captor.value
|
||||
}
|
||||
|
||||
// Returns a [SensorEvent] with a single [value].
|
||||
private fun sensorEventWithSingleValue(value: Float): SensorEvent {
|
||||
return SensorEvent(sensor, 1, 1, FloatArray(1) { value })
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,6 @@ import static org.mockito.Mockito.when;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
@@ -46,7 +44,6 @@ import com.android.systemui.shared.system.InputChannelCompat;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -55,8 +52,6 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
@SmallTest
|
||||
@@ -64,7 +59,6 @@ import javax.inject.Provider;
|
||||
public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
@Mock private BroadcastDispatcher mBroadcastDispatcher;
|
||||
@Mock private PowerManager mPowerManager;
|
||||
@Mock private AsyncSensorManager mSensorManager;
|
||||
@Mock private IdleHostView mIdleHostView;
|
||||
@Mock private InputMonitorFactory mInputMonitorFactory;
|
||||
@Mock private DelayableExecutor mDelayableExecutor;
|
||||
@@ -74,12 +68,11 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
@Mock private Choreographer mChoreographer;
|
||||
@Mock private KeyguardStateController mKeyguardStateController;
|
||||
@Mock private StatusBarStateController mStatusBarStateController;
|
||||
@Mock private Sensor mSensor;
|
||||
@Mock private DreamHelper mDreamHelper;
|
||||
@Mock private InputMonitorCompat mInputMonitor;
|
||||
@Mock private InputChannelCompat.InputEventReceiver mInputEventReceiver;
|
||||
@Mock private AmbientLightModeMonitor mAmbientLightModeMonitor;
|
||||
|
||||
private final long mTimestamp = Instant.now().toEpochMilli();
|
||||
private KeyguardStateController.Callback mKeyguardStateCallback;
|
||||
private StatusBarStateController.StateListener mStatusBarStateListener;
|
||||
private IdleHostViewController mController;
|
||||
@@ -90,15 +83,15 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
|
||||
when(mResources.getBoolean(R.bool.config_enableIdleMode)).thenReturn(true);
|
||||
when(mStatusBarStateController.isDozing()).thenReturn(false);
|
||||
when(mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(mSensor);
|
||||
when(mInputMonitorFactory.getInputMonitor("IdleHostViewController"))
|
||||
.thenReturn(mInputMonitor);
|
||||
when(mInputMonitor.getInputReceiver(any(), any(), any())).thenReturn(mInputEventReceiver);
|
||||
|
||||
mController = new IdleHostViewController(mContext,
|
||||
mBroadcastDispatcher, mPowerManager, mSensorManager, mIdleHostView,
|
||||
mBroadcastDispatcher, mPowerManager, mIdleHostView,
|
||||
mInputMonitorFactory, mDelayableExecutor, mResources, mLooper, mViewProvider,
|
||||
mChoreographer, mKeyguardStateController, mStatusBarStateController, mDreamHelper);
|
||||
mChoreographer, mKeyguardStateController, mStatusBarStateController, mDreamHelper,
|
||||
mAmbientLightModeMonitor);
|
||||
mController.init();
|
||||
mController.onViewAttached();
|
||||
|
||||
@@ -122,9 +115,9 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
mKeyguardStateCallback.onKeyguardShowingChanged();
|
||||
|
||||
// Regular ambient lighting.
|
||||
final SensorEvent sensorEvent = new SensorEvent(mSensor, 3, mTimestamp,
|
||||
new float[]{90});
|
||||
mController.onSensorChanged(sensorEvent);
|
||||
final AmbientLightModeMonitor.Callback lightMonitorCallback =
|
||||
captureAmbientLightModeMonitorCallback();
|
||||
lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);
|
||||
|
||||
// Times out.
|
||||
ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
|
||||
@@ -149,9 +142,9 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
final BroadcastReceiver dreamBroadcastReceiver = dreamBroadcastReceiverCaptor.getValue();
|
||||
|
||||
// Low ambient lighting.
|
||||
final SensorEvent sensorEvent = new SensorEvent(mSensor, 3, mTimestamp,
|
||||
new float[]{5});
|
||||
mController.onSensorChanged(sensorEvent);
|
||||
final AmbientLightModeMonitor.Callback lightMonitorCallback =
|
||||
captureAmbientLightModeMonitorCallback();
|
||||
lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK);
|
||||
|
||||
// Verifies it goes to sleep because of low light.
|
||||
verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
|
||||
@@ -179,15 +172,15 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testTransitionBetweenIdleAndLowLightMode() {
|
||||
// Regular ambient lighting.
|
||||
final SensorEvent sensorEventRegularLight = new SensorEvent(mSensor, 3, mTimestamp,
|
||||
new float[]{90});
|
||||
mController.onSensorChanged(sensorEventRegularLight);
|
||||
|
||||
// Keyguard showing.
|
||||
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
||||
mKeyguardStateCallback.onKeyguardShowingChanged();
|
||||
|
||||
// Regular ambient lighting.
|
||||
final AmbientLightModeMonitor.Callback lightMonitorCallback =
|
||||
captureAmbientLightModeMonitorCallback();
|
||||
lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);
|
||||
|
||||
// Times out.
|
||||
ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(mDelayableExecutor).executeDelayed(callbackCapture.capture(), anyLong());
|
||||
@@ -198,15 +191,13 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
clearInvocations(mDreamHelper);
|
||||
|
||||
// Ambient lighting becomes dim.
|
||||
final SensorEvent sensorEventLowLight = new SensorEvent(mSensor, 3, mTimestamp,
|
||||
new float[]{5});
|
||||
mController.onSensorChanged(sensorEventLowLight);
|
||||
lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK);
|
||||
|
||||
// Verifies in low light mode (dozing).
|
||||
verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
|
||||
|
||||
// Ambient lighting becomes bright again.
|
||||
mController.onSensorChanged(sensorEventRegularLight);
|
||||
lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);
|
||||
|
||||
// Verifies in idle mode (dreaming).
|
||||
verify(mDreamHelper).startDreaming(any());
|
||||
@@ -214,22 +205,20 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testStartDozingWhenLowLight() {
|
||||
// Regular ambient lighting.
|
||||
final SensorEvent sensorEventRegularLight = new SensorEvent(mSensor, 3, mTimestamp,
|
||||
new float[]{90});
|
||||
mController.onSensorChanged(sensorEventRegularLight);
|
||||
|
||||
// Keyguard showing.
|
||||
when(mKeyguardStateController.isShowing()).thenReturn(true);
|
||||
mKeyguardStateCallback.onKeyguardShowingChanged();
|
||||
|
||||
// Regular ambient lighting.
|
||||
final AmbientLightModeMonitor.Callback lightMonitorCallback =
|
||||
captureAmbientLightModeMonitorCallback();
|
||||
lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_LIGHT);
|
||||
|
||||
// Verifies it doesn't go to sleep yet.
|
||||
verify(mPowerManager, never()).goToSleep(anyLong(), anyInt(), anyInt());
|
||||
|
||||
// Ambient lighting becomes dim.
|
||||
final SensorEvent sensorEventLowLight = new SensorEvent(mSensor, 3, mTimestamp,
|
||||
new float[]{5});
|
||||
mController.onSensorChanged(sensorEventLowLight);
|
||||
lightMonitorCallback.onChange(AmbientLightModeMonitor.AMBIENT_LIGHT_MODE_DARK);
|
||||
|
||||
// Verifies it goes to sleep.
|
||||
verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
|
||||
@@ -251,4 +240,13 @@ public class IdleHostViewControllerTest extends SysuiTestCase {
|
||||
// Should dispose input event receiver.
|
||||
verify(mInputEventReceiver).dispose();
|
||||
}
|
||||
|
||||
// Captures [AmbientLightModeMonitor.Callback] assuming that the ambient light mode monitor
|
||||
// has been started.
|
||||
private AmbientLightModeMonitor.Callback captureAmbientLightModeMonitorCallback() {
|
||||
ArgumentCaptor<AmbientLightModeMonitor.Callback> captor =
|
||||
ArgumentCaptor.forClass(AmbientLightModeMonitor.Callback.class);
|
||||
verify(mAmbientLightModeMonitor).start(captor.capture());
|
||||
return captor.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user