summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyan_Hsieh <cyanhsieh@google.com>2023-02-17 11:51:58 +0800
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-02-20 12:04:03 +0000
commit1a7fb35c86a57b72c577163099818e2fc1d36a3d (patch)
treed44eb7ece3510540da0af8906fcd35be3ddb8757
parent3e0b68a41f97461d0ef19d814ccca1a3d597f391 (diff)
downloadbase-1a7fb35c86a57b72c577163099818e2fc1d36a3d.tar.gz
Revert "[Submit only to device branch] Add custom device state provider"
This reverts commit 57766bb95afe69797b9e14a8d89a593a65c63236. reason for revert: replace with new patch bug:253490171 Change-Id: I95148bc2a76efbe2292f5ae0e0416f3e8a41aa5d (cherry picked from commit 4ad1c8a5d58de265f1d56d3b20209f3e409b3825) Merged-In: I95148bc2a76efbe2292f5ae0e0416f3e8a41aa5d
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStatePolicy.java10
-rw-r--r--services/core/java/com/android/server/policy/FoldableDeviceStateProvider.java362
-rw-r--r--services/core/java/com/android/server/policy/TentModeDeviceStatePolicy.java115
-rw-r--r--services/proguard.flags2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/DeviceStatePolicyProviderTest.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java288
-rw-r--r--services/tests/servicestests/src/com/android/server/policy/TentModeDeviceStateProviderTest.java323
7 files changed, 20 insertions, 1114 deletions
diff --git a/services/core/java/com/android/server/devicestate/DeviceStatePolicy.java b/services/core/java/com/android/server/devicestate/DeviceStatePolicy.java
index c876a8b76dc1..5c4e2f3426ee 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStatePolicy.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStatePolicy.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
-import android.util.Slog;
import com.android.server.policy.DeviceStatePolicyImpl;
@@ -93,16 +92,11 @@ public abstract class DeviceStatePolicy {
try {
return (DeviceStatePolicy.Provider) Class.forName(name).newInstance();
- } catch (ClassCastException e) {
+ } catch (ReflectiveOperationException | ClassCastException e) {
throw new IllegalStateException("Couldn't instantiate class " + name
+ " for config_deviceSpecificDeviceStatePolicyProvider:"
+ " make sure it has a public zero-argument constructor"
- + " and implements DeviceStatePolicy.Provider");
- } catch (ReflectiveOperationException e) {
- Slog.e("DeviceStatePolicy", "Couldn't instantiate class " + name
- + " for config_deviceSpecificDeviceStatePolicyProvider:"
- + " using default provider", e);
- return new DeviceStatePolicy.DefaultProvider();
+ + " and implements DeviceStatePolicy.Provider", e);
}
}
}
diff --git a/services/core/java/com/android/server/policy/FoldableDeviceStateProvider.java b/services/core/java/com/android/server/policy/FoldableDeviceStateProvider.java
deleted file mode 100644
index 0575df5b0fe6..000000000000
--- a/services/core/java/com/android/server/policy/FoldableDeviceStateProvider.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2022 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.server.policy;
-
-import static android.hardware.SensorManager.SENSOR_DELAY_FASTEST;
-import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-import com.android.server.devicestate.DeviceState;
-import com.android.server.devicestate.DeviceStateProvider;
-
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.function.BooleanSupplier;
-import java.util.function.Function;
-
-/**
- * Device state provider for foldable devices.
- *
- * It is an implementation of {@link DeviceStateProvider} tailored specifically for
- * foldable devices and allows simple callback-based configuration with hall sensor
- * and hinge angle sensor values.
- */
-public final class FoldableDeviceStateProvider implements DeviceStateProvider,
- SensorEventListener {
-
- private static final String TAG = "FoldableDeviceStateProvider";
- private static final boolean DEBUG = false;
-
- // Lock for internal state.
- private final Object mLock = new Object();
-
- // List of supported states in ascending order based on their identifier.
- private final DeviceState[] mOrderedStates;
-
- // Map of state identifier to a boolean supplier that returns true when all required conditions
- // are met for the device to be in the state.
- private final SparseArray<BooleanSupplier> mStateConditions = new SparseArray<>();
-
- private final Sensor mHingeAngleSensor;
- private final Sensor mHallSensor;
-
- @Nullable
- @GuardedBy("mLock")
- private Listener mListener = null;
- @GuardedBy("mLock")
- private int mLastReportedState = INVALID_DEVICE_STATE;
- @GuardedBy("mLock")
- private SensorEvent mLastHingeAngleSensorEvent = null;
- @GuardedBy("mLock")
- private SensorEvent mLastHallSensorEvent = null;
-
- public FoldableDeviceStateProvider(@NonNull SensorManager sensorManager,
- @NonNull Sensor hingeAngleSensor,
- @NonNull Sensor hallSensor,
- @NonNull DeviceStateConfiguration[] deviceStateConfigurations) {
-
- Preconditions.checkArgument(deviceStateConfigurations.length > 0,
- "Device state configurations array must not be empty");
-
- mHingeAngleSensor = hingeAngleSensor;
- mHallSensor = hallSensor;
-
- sensorManager.registerListener(this, mHingeAngleSensor, SENSOR_DELAY_FASTEST);
- sensorManager.registerListener(this, mHallSensor, SENSOR_DELAY_FASTEST);
-
- mOrderedStates = new DeviceState[deviceStateConfigurations.length];
- for (int i = 0; i < deviceStateConfigurations.length; i++) {
- final DeviceStateConfiguration configuration = deviceStateConfigurations[i];
- mOrderedStates[i] = configuration.mDeviceState;
-
- if (mStateConditions.get(configuration.mDeviceState.getIdentifier()) != null) {
- throw new IllegalArgumentException("Device state configurations must have unique"
- + " device state identifiers, found duplicated identifier: " +
- configuration.mDeviceState.getIdentifier());
- }
-
- mStateConditions.put(configuration.mDeviceState.getIdentifier(), () ->
- configuration.mPredicate.apply(this));
- }
-
- Arrays.sort(mOrderedStates, Comparator.comparingInt(DeviceState::getIdentifier));
- }
-
- @Override
- public void setListener(Listener listener) {
- synchronized (mLock) {
- if (mListener != null) {
- throw new RuntimeException("Provider already has a listener set.");
- }
- mListener = listener;
- }
- notifySupportedStatesChanged();
- notifyDeviceStateChangedIfNeeded();
- }
-
- /** Notifies the listener that the set of supported device states has changed. */
- private void notifySupportedStatesChanged() {
- DeviceState[] supportedStates;
- Listener listener;
- synchronized (mLock) {
- if (mListener == null) {
- return;
- }
-
- listener = mListener;
- supportedStates = Arrays.copyOf(mOrderedStates, mOrderedStates.length);
- }
-
- listener.onSupportedDeviceStatesChanged(supportedStates);
- }
-
- /** Computes the current device state and notifies the listener of a change, if needed. */
- void notifyDeviceStateChangedIfNeeded() {
- int stateToReport = INVALID_DEVICE_STATE;
- Listener listener;
- synchronized (mLock) {
- if (mListener == null) {
- return;
- }
-
- listener = mListener;
-
- int newState = INVALID_DEVICE_STATE;
- for (int i = 0; i < mOrderedStates.length; i++) {
- int state = mOrderedStates[i].getIdentifier();
- if (DEBUG) {
- Slog.d(TAG, "Checking conditions for " + mOrderedStates[i].getName() + "("
- + i + ")");
- }
- boolean conditionSatisfied;
- try {
- conditionSatisfied = mStateConditions.get(state).getAsBoolean();
- } catch (IllegalStateException e) {
- // Failed to compute the current state based on current available data. Continue
- // with the expectation that notifyDeviceStateChangedIfNeeded() will be called
- // when a callback with the missing data is triggered. May trigger another state
- // change if another state is satisfied currently.
- Slog.w(TAG, "Unable to check current state = " + state, e);
- dumpSensorValues();
- continue;
- }
-
- if (conditionSatisfied) {
- if (DEBUG) {
- Slog.d(TAG, "Device State conditions satisfied, transition to " + state);
- }
- newState = state;
- break;
- }
- }
- if (newState == INVALID_DEVICE_STATE) {
- Slog.e(TAG, "No declared device states match any of the required conditions.");
- dumpSensorValues();
- }
-
- if (newState != INVALID_DEVICE_STATE && newState != mLastReportedState) {
- mLastReportedState = newState;
- stateToReport = newState;
- }
- }
-
- if (stateToReport != INVALID_DEVICE_STATE) {
- listener.onStateChanged(stateToReport);
- }
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- synchronized (mLock) {
- if (event.sensor == mHallSensor) {
- mLastHallSensorEvent = event;
- } else if (event.sensor == mHingeAngleSensor) {
- mLastHingeAngleSensorEvent = event;
- }
- }
- notifyDeviceStateChangedIfNeeded();
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- // Do nothing.
- }
-
- private float getSensorValue(@Nullable SensorEvent sensorEvent) {
- if (sensorEvent == null) {
- throw new IllegalStateException("Have not received sensor event.");
- }
-
- if (sensorEvent.values.length < 1) {
- throw new IllegalStateException("Values in the sensor event are empty");
- }
-
- return sensorEvent.values[0];
- }
-
- @GuardedBy("mLock")
- private void dumpSensorValues() {
- Slog.i(TAG, "Sensor values:");
- dumpSensorValues(mHallSensor, mLastHallSensorEvent);
- dumpSensorValues(mHingeAngleSensor, mLastHingeAngleSensorEvent);
- }
-
- @GuardedBy("mLock")
- private void dumpSensorValues(@NonNull Sensor sensor, @Nullable SensorEvent event) {
- if (event != null) {
- Slog.i(TAG, sensor.getName() + ": " + Arrays.toString(event.values));
- } else {
- Slog.i(TAG, sensor.getName() + ": null");
- }
- }
-
- /**
- * Configuration for a single device state, contains information about the state like
- * identifier, name, flags and a predicate that should return true if the state should
- * be selected.
- */
- public static class DeviceStateConfiguration {
- private final DeviceState mDeviceState;
- private final Function<FoldableDeviceStateProvider, Boolean> mPredicate;
-
- private DeviceStateConfiguration(DeviceState deviceState,
- Function<FoldableDeviceStateProvider, Boolean> predicate) {
- mDeviceState = deviceState;
- mPredicate = predicate;
- }
-
- public static DeviceStateConfiguration createConfig(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
- @NonNull String name,
- @DeviceState.DeviceStateFlags int flags,
- Function<FoldableDeviceStateProvider, Boolean> predicate
- ) {
- return new DeviceStateConfiguration(new DeviceState(identifier, name, flags),
- predicate);
- }
-
- public static DeviceStateConfiguration createConfig(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
- @NonNull String name,
- Function<FoldableDeviceStateProvider, Boolean> predicate
- ) {
- return new DeviceStateConfiguration(new DeviceState(identifier, name, /* flags= */ 0),
- predicate);
- }
-
- /**
- * Creates a device state configuration for a closed tent-mode aware state.
- * This is useful to create a behavior when the device could be used in a tent mode: a mode
- * on a foldable device where we keep the outer display on after partially unfolding
- * the device so it could be used in a posture where both left and right edges of
- * the unfolded device are on the table.
- *
- * The predicate returns false when the hinge angle reaches
- * {@code tentModeSwitchAngleDegrees}. Then it switches back only when the hinge angle
- * becomes less than {@code maxClosedAngleDegrees}. Hinge angle is 0 degrees when the device
- * is fully closed and 180 degrees when it is fully unfolded.
- *
- * For example, when tentModeSwitchAngleDegrees = 90 and maxClosedAngleDegrees = 5 degrees:
- * - when unfolding the device from fully closed posture (last state == closed or it is
- * undefined yet) this state will become not matching when reaching the angle
- * of 90 degrees, it allows the device to switch the outer display to the inner display
- * only when reaching this threshold
- * - when folding (last state != 'closed') this state will become matching when reaching
- * the angle less than 5 degrees and when hall sensor detected that the device is closed,
- * so the switch from the inner display to the outer will become only when the device
- * is fully closed.
- *
- * @param identifier state identifier
- * @param name state name
- * @param flags state flags
- * @param minClosedAngleDegrees minimum (inclusive) hinge angle value for the closed state
- * @param maxClosedAngleDegrees maximum (non-inclusive) hinge angle value for the closed
- * state
- * @param tentModeSwitchAngleDegrees the angle when this state should switch when unfolding
- * @return device state configuration
- */
- public static DeviceStateConfiguration createTentModeClosedState(
- @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
- @NonNull String name,
- @DeviceState.DeviceStateFlags int flags,
- int minClosedAngleDegrees,
- int maxClosedAngleDegrees,
- int tentModeSwitchAngleDegrees
- ) {
- return new DeviceStateConfiguration(new DeviceState(identifier, name, flags),
- (stateContext) -> {
- final boolean hallSensorClosed = stateContext.isHallSensorClosed();
- final float hingeAngle = stateContext.getHingeAngle();
- final int lastState = stateContext.getLastReportedDeviceState();
-
- final int closedDeviceState = identifier;
- final boolean isLastStateClosed = lastState == closedDeviceState
- || lastState == INVALID_DEVICE_STATE;
-
- final boolean shouldBeClosedBecauseTentMode = isLastStateClosed
- && hingeAngle >= minClosedAngleDegrees
- && hingeAngle < tentModeSwitchAngleDegrees;
-
- final boolean shouldBeClosedBecauseFullyShut = hallSensorClosed
- && hingeAngle >= minClosedAngleDegrees
- && hingeAngle < maxClosedAngleDegrees;
-
- return shouldBeClosedBecauseFullyShut || shouldBeClosedBecauseTentMode;
- });
- }
- }
-
- /**
- * @return current hinge angle value of a foldable device
- */
- public float getHingeAngle() {
- synchronized (mLock) {
- return getSensorValue(mLastHingeAngleSensorEvent);
- }
- }
-
- /**
- * @return true if hall sensor detected that the device is closed (fully shut)
- */
- public boolean isHallSensorClosed() {
- synchronized (mLock) {
- return getSensorValue(mLastHallSensorEvent) > 0f;
- }
- }
-
- /**
- * @return last reported device state
- */
- public int getLastReportedDeviceState() {
- synchronized (mLock) {
- return mLastReportedState;
- }
- }
-}
diff --git a/services/core/java/com/android/server/policy/TentModeDeviceStatePolicy.java b/services/core/java/com/android/server/policy/TentModeDeviceStatePolicy.java
deleted file mode 100644
index abba0194cd52..000000000000
--- a/services/core/java/com/android/server/policy/TentModeDeviceStatePolicy.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2022 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.server.policy;
-
-import static com.android.server.devicestate.DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS;
-import static com.android.server.devicestate.DeviceState.FLAG_EMULATED_ONLY;
-import static com.android.server.policy.FoldableDeviceStateProvider.DeviceStateConfiguration.createConfig;
-import static com.android.server.policy.FoldableDeviceStateProvider.DeviceStateConfiguration.createTentModeClosedState;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-
-import com.android.internal.util.CollectionUtils;
-import com.android.server.devicestate.DeviceStatePolicy;
-import com.android.server.devicestate.DeviceStateProvider;
-import com.android.server.policy.FoldableDeviceStateProvider.DeviceStateConfiguration;
-
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Device state policy for a foldable device that supports tent mode: a mode when the device
- * keeps the outer display on until reaching a certain hinge angle threshold.
- *
- * Contains configuration for {@link FoldableDeviceStateProvider}.
- */
-public class TentModeDeviceStatePolicy extends DeviceStatePolicy {
-
- private static final int DEVICE_STATE_CLOSED = 0;
- private static final int DEVICE_STATE_HALF_OPENED = 1;
- private static final int DEVICE_STATE_OPENED = 2;
- private static final int DEVICE_STATE_REAR_DISPLAY_STATE = 3;
-
- private static final int TENT_MODE_SWITCH_ANGLE_DEGREES = 90;
- private static final int TABLE_TOP_MODE_SWITCH_ANGLE_DEGREES = 125;
- private static final int MIN_CLOSED_ANGLE_DEGREES = 0;
- private static final int MAX_CLOSED_ANGLE_DEGREES = 5;
-
- private final DeviceStateProvider mProvider;
-
- protected TentModeDeviceStatePolicy(@NonNull Context context) {
- super(context);
-
- final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
- final Sensor hingeAngleSensor =
- sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE, /* wakeUp= */ true);
-
- final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
- final Sensor hallSensor = CollectionUtils.find(sensors,
- (sensor) -> Objects.equals(sensor.getStringType(),
- "com.google.sensor.hall_effect"));
-
- mProvider = new FoldableDeviceStateProvider(sensorManager, hingeAngleSensor, hallSensor,
- createConfiguration());
- }
-
- private DeviceStateConfiguration[] createConfiguration() {
- return new DeviceStateConfiguration[]{
- createTentModeClosedState(DEVICE_STATE_CLOSED,
- /* name= */ "CLOSED",
- /* flags= */ FLAG_CANCEL_OVERRIDE_REQUESTS,
- MIN_CLOSED_ANGLE_DEGREES,
- MAX_CLOSED_ANGLE_DEGREES,
- TENT_MODE_SWITCH_ANGLE_DEGREES),
- createConfig(DEVICE_STATE_HALF_OPENED,
- /* name= */ "HALF_OPENED",
- (provider) -> {
- final float hingeAngle = provider.getHingeAngle();
- return hingeAngle >= MAX_CLOSED_ANGLE_DEGREES
- && hingeAngle <= TABLE_TOP_MODE_SWITCH_ANGLE_DEGREES;
- }),
- createConfig(DEVICE_STATE_OPENED,
- /* name= */ "OPENED",
- (provider) -> true),
- createConfig(DEVICE_STATE_REAR_DISPLAY_STATE,
- /* name= */ "REAR_DISPLAY_STATE",
- /* flags= */ FLAG_EMULATED_ONLY,
- (provider) -> false)
- };
- }
-
- @Override
- public DeviceStateProvider getDeviceStateProvider() {
- return mProvider;
- }
-
- @Override
- public void configureDeviceForState(int state, @NonNull Runnable onComplete) {
- onComplete.run();
- }
-
- public static class Provider implements DeviceStatePolicy.Provider {
-
- @Override
- public DeviceStatePolicy instantiate(@NonNull Context context) {
- return new TentModeDeviceStatePolicy(context);
- }
- }
-}
diff --git a/services/proguard.flags b/services/proguard.flags
index 255157b4acc8..c648f7d3ac45 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -110,8 +110,6 @@
public <init>(...);
}
-keep,allowoptimization,allowaccessmodification class android.hardware.usb.gadget.** { *; }
--keep,allowoptimization,allowaccessmodification class com.android.server.policy.TentModeDeviceStatePolicy { *; }
--keep,allowoptimization,allowaccessmodification class com.android.server.policy.TentModeDeviceStatePolicy$Provider { *; }
# Needed when optimizations enabled
# TODO(b/210510433): Revisit and fix with @Keep.
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStatePolicyProviderTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStatePolicyProviderTest.java
index 4ec0fa14937c..0bd81b78ac97 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStatePolicyProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStatePolicyProviderTest.java
@@ -16,8 +16,6 @@
package com.android.server.devicestate;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
@@ -26,6 +24,8 @@ import android.content.Context;
import android.content.res.Resources;
import android.platform.test.annotations.Presubmit;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
import org.junit.Test;
/**
@@ -39,35 +39,37 @@ public class DeviceStatePolicyProviderTest {
@Test
public void test_emptyPolicyProvider() {
- assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider("")),
- instanceOf(DeviceStatePolicy.DefaultProvider.class));
+ Assert.assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider("")),
+ Matchers.instanceOf(DeviceStatePolicy.DefaultProvider.class));
}
@Test
public void test_nullPolicyProvider() {
- assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(null)),
- instanceOf(DeviceStatePolicy.DefaultProvider.class));
+ Assert.assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(null)),
+ Matchers.instanceOf(DeviceStatePolicy.DefaultProvider.class));
}
@Test
public void test_customPolicyProvider() {
- assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
- TestProvider.class.getName())),
- instanceOf(TestProvider.class));
+ Assert.assertThat(DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
+ TestProvider.class.getName())),
+ Matchers.instanceOf(TestProvider.class));
}
@Test
public void test_badPolicyProvider_notImplementingProviderInterface() {
- assertThrows(IllegalStateException.class, () ->
- DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
- Object.class.getName())));
+ assertThrows(IllegalStateException.class, () -> {
+ DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
+ Object.class.getName()));
+ });
}
@Test
- public void test_badPolicyProvider_returnsDefault() {
- assertThat(DeviceStatePolicy.Provider.fromResources(
- resourcesWithProvider("com.android.devicestate.nonexistent.policy")),
- instanceOf(DeviceStatePolicy.DefaultProvider.class));
+ public void test_badPolicyProvider_doesntExist() {
+ assertThrows(IllegalStateException.class, () -> {
+ DeviceStatePolicy.Provider.fromResources(resourcesWithProvider(
+ "com.android.devicestate.nonexistent.policy"));
+ });
}
private static Resources resourcesWithProvider(String provider) {
diff --git a/services/tests/servicestests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java b/services/tests/servicestests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
deleted file mode 100644
index 066300c7d7f9..000000000000
--- a/services/tests/servicestests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2022 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.server.policy;
-
-
-import static com.android.server.policy.FoldableDeviceStateProvider.DeviceStateConfiguration.createConfig;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorManager;
-import android.hardware.input.InputSensorInfo;
-
-import com.android.server.devicestate.DeviceState;
-import com.android.server.devicestate.DeviceStateProvider.Listener;
-import com.android.server.policy.FoldableDeviceStateProvider.DeviceStateConfiguration;
-
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.internal.util.reflection.FieldSetter;
-
-/**
- * Unit tests for {@link FoldableDeviceStateProvider}.
- * <p/>
- * Run with <code>atest FoldableDeviceStateProviderTest</code>.
- */
-public final class FoldableDeviceStateProviderTest {
-
- private final ArgumentCaptor<DeviceState[]> mDeviceStateArrayCaptor = ArgumentCaptor.forClass(
- DeviceState[].class);
- private final ArgumentCaptor<Integer> mIntegerCaptor = ArgumentCaptor.forClass(Integer.class);
-
- private final SensorManager mSensorManager = mock(SensorManager.class);
- private final Sensor mHallSensor = new Sensor(mock(InputSensorInfo.class));
- private final Sensor mHingeAngleSensor = new Sensor(mock(InputSensorInfo.class));
-
- private FoldableDeviceStateProvider mProvider;
-
- @Test
- public void create_emptyConfiguration_throwsException() {
- assertThrows(IllegalArgumentException.class, this::createProvider);
- }
-
- @Test
- public void create_duplicatedDeviceStateIdentifiers_throwsException() {
- assertThrows(IllegalArgumentException.class,
- () -> createProvider(
- createConfig(
- /* identifier= */ 0, /* name= */ "ONE", (c) -> true),
- createConfig(
- /* identifier= */ 0, /* name= */ "TWO", (c) -> true)
- ));
- }
-
- @Test
- public void create_allMatchingStatesDefaultsToTheFirstIdentifier() {
- createProvider(
- createConfig(
- /* identifier= */ 1, /* name= */ "ONE", (c) -> true),
- createConfig(
- /* identifier= */ 2, /* name= */ "TWO", (c) -> true),
- createConfig(
- /* identifier= */ 3, /* name= */ "THREE", (c) -> true)
- );
-
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
-
- verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
- final DeviceState[] expectedStates = new DeviceState[]{
- new DeviceState(1, "ONE", /* flags= */ 0),
- new DeviceState(2, "TWO", /* flags= */ 0),
- new DeviceState(3, "THREE", /* flags= */ 0),
- };
- assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
-
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(1, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void create_multipleMatchingStatesDefaultsToTheLowestIdentifier() {
- createProvider(
- createConfig(
- /* identifier= */ 1, /* name= */ "ONE", (c) -> false),
- createConfig(
- /* identifier= */ 3, /* name= */ "THREE", (c) -> false),
- createConfig(
- /* identifier= */ 4, /* name= */ "FOUR", (c) -> true),
- createConfig(
- /* identifier= */ 2, /* name= */ "TWO", (c) -> true)
- );
-
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
-
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(2, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_hingeAngleUpdatedFirstTime_switchesToMatchingState() throws Exception {
- createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
- (c) -> c.getHingeAngle() < 90f),
- createConfig(/* identifier= */ 2, /* name= */ "TWO",
- (c) -> c.getHingeAngle() >= 90f));
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
- verify(listener, never()).onStateChanged(anyInt());
- clearInvocations(listener);
-
- sendSensorEvent(mHingeAngleSensor, /* value= */ 100f);
-
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(2, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_hallSensorUpdatedFirstTime_switchesToMatchingState() throws Exception {
- createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
- (c) -> !c.isHallSensorClosed()),
- createConfig(/* identifier= */ 2, /* name= */ "TWO",
- FoldableDeviceStateProvider::isHallSensorClosed));
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
- verify(listener, never()).onStateChanged(anyInt());
- clearInvocations(listener);
-
- // Hall sensor value '1f' is for the closed state
- sendSensorEvent(mHallSensor, /* value= */ 1f);
-
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(2, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_hingeAngleUpdatedSecondTime_switchesToMatchingState() throws Exception {
- createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
- (c) -> c.getHingeAngle() < 90f),
- createConfig(/* identifier= */ 2, /* name= */ "TWO",
- (c) -> c.getHingeAngle() >= 90f));
- sendSensorEvent(mHingeAngleSensor, /* value= */ 30f);
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(1, mIntegerCaptor.getValue().intValue());
- clearInvocations(listener);
-
- sendSensorEvent(mHingeAngleSensor, /* value= */ 100f);
-
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(2, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_hallSensorUpdatedSecondTime_switchesToMatchingState() throws Exception {
- createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
- (c) -> !c.isHallSensorClosed()),
- createConfig(/* identifier= */ 2, /* name= */ "TWO",
- FoldableDeviceStateProvider::isHallSensorClosed));
- sendSensorEvent(mHallSensor, /* value= */ 0f);
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(1, mIntegerCaptor.getValue().intValue());
- clearInvocations(listener);
-
- // Hall sensor value '1f' is for the closed state
- sendSensorEvent(mHallSensor, /* value= */ 1f);
-
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(2, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_invalidSensorValues_onStateChangedIsNotTriggered() throws Exception {
- createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
- (c) -> c.getHingeAngle() < 90f),
- createConfig(/* identifier= */ 2, /* name= */ "TWO",
- (c) -> c.getHingeAngle() >= 90f));
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
- clearInvocations(listener);
-
- // First, switch to a non-default state.
- sendSensorEvent(mHingeAngleSensor, /* value= */ 100f);
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(2, mIntegerCaptor.getValue().intValue());
-
- clearInvocations(listener);
-
- // Then, send an invalid sensor event, verify that onStateChanged() is not triggered.
- sendInvalidSensorEvent(mHingeAngleSensor);
-
- verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
- verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
- }
-
- @Test
- public void test_previousStateBasedPredicate() {
- // Create a configuration where state TWO could be matched only if
- // the previous state was 'THREE'
- createProvider(
- createConfig(
- /* identifier= */ 1, /* name= */ "ONE", (c) -> c.getHingeAngle() < 30f),
- createConfig(
- /* identifier= */ 2, /* name= */ "TWO",
- (c) -> c.getLastReportedDeviceState() == 3 && c.getHingeAngle() > 120f),
- createConfig(
- /* identifier= */ 3, /* name= */ "THREE",
- (c) -> c.getHingeAngle() > 90f)
- );
- sendSensorEvent(mHingeAngleSensor, /* value= */ 0f);
- Listener listener = mock(Listener.class);
- mProvider.setListener(listener);
-
- // Check that the initial state is 'ONE'
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(1, mIntegerCaptor.getValue().intValue());
- clearInvocations(listener);
-
- // Should not match state 'TWO', it should match only state 'THREE'
- // (because the previous state is not 'THREE', it is 'ONE')
- sendSensorEvent(mHingeAngleSensor, /* value= */ 180f);
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(3, mIntegerCaptor.getValue().intValue());
- clearInvocations(listener);
-
- // Now it should match state 'TWO'
- // (because the previous state is 'THREE' now)
- sendSensorEvent(mHingeAngleSensor, /* value= */ 180f);
- verify(listener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(2, mIntegerCaptor.getValue().intValue());
- }
-
- private void sendSensorEvent(Sensor sensor, float value) {
- SensorEvent event = mock(SensorEvent.class);
- event.sensor = sensor;
- try {
- FieldSetter.setField(event, event.getClass().getField("values"),
- new float[]{value});
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
-
- mProvider.onSensorChanged(event);
- }
-
- private void sendInvalidSensorEvent(Sensor sensor) {
- SensorEvent event = mock(SensorEvent.class);
- event.sensor = sensor;
- try {
- // Set empty values array to make the event invalid
- FieldSetter.setField(event, event.getClass().getField("values"),
- new float[]{});
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- mProvider.onSensorChanged(event);
- }
-
- private void createProvider(DeviceStateConfiguration... configurations) {
- mProvider = new FoldableDeviceStateProvider(mSensorManager, mHingeAngleSensor, mHallSensor,
- configurations);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/policy/TentModeDeviceStateProviderTest.java b/services/tests/servicestests/src/com/android/server/policy/TentModeDeviceStateProviderTest.java
deleted file mode 100644
index 43c55508ebc7..000000000000
--- a/services/tests/servicestests/src/com/android/server/policy/TentModeDeviceStateProviderTest.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2023 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.server.policy;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.hardware.input.InputSensorInfo;
-
-import com.android.server.devicestate.DeviceStateProvider;
-import com.android.server.devicestate.DeviceStateProvider.Listener;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.internal.util.reflection.FieldSetter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit tests for {@link TentModeDeviceStatePolicy.Provider}.
- * <p/>
- * Run with <code>atest TentModeDeviceStateProviderTest</code>.
- */
-public final class TentModeDeviceStateProviderTest {
-
- private static final int DEVICE_STATE_CLOSED = 0;
- private static final int DEVICE_STATE_HALF_OPENED = 1;
- private static final int DEVICE_STATE_OPENED = 2;
-
- private final ArgumentCaptor<Integer> mIntegerCaptor = ArgumentCaptor.forClass(Integer.class);
-
- private final Context mContext = mock(Context.class);
- private final SensorManager mSensorManager = mock(SensorManager.class);
- private final Sensor mHallSensor = new Sensor(mock(InputSensorInfo.class));
- private final Sensor mHingeAngleSensor = new Sensor(mock(InputSensorInfo.class));
- private final Listener mListener = mock(Listener.class);
-
- private SensorEventListener mSensorEventListener;
- private DeviceStateProvider mProvider;
-
- @Before
- public void setup() {
- when(mContext.getSystemServiceName(SensorManager.class)).thenReturn(Context.SENSOR_SERVICE);
- when(mContext.getSystemService(Context.SENSOR_SERVICE)).thenReturn(mSensorManager);
-
- when(mSensorManager.getDefaultSensor(eq(Sensor.TYPE_HINGE_ANGLE), eq(true)))
- .thenReturn(mHingeAngleSensor);
-
- final List<Sensor> sensors = new ArrayList<>();
- sensors.add(mHallSensor);
- sensors.add(mHingeAngleSensor);
-
- when(mSensorManager.registerListener(any(), any(), anyInt())).thenAnswer(invocation -> {
- mSensorEventListener = invocation.getArgument(0);
- return true;
- });
-
- try {
- FieldSetter.setField(mHallSensor, mHallSensor.getClass()
- .getDeclaredField("mStringType"), "com.google.sensor.hall_effect");
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
-
- when(mSensorManager.getSensorList(eq(Sensor.TYPE_ALL)))
- .thenReturn(sensors);
-
- mProvider = new TentModeDeviceStatePolicy.Provider().instantiate(mContext)
- .getDeviceStateProvider();
- }
-
- @Test
- public void test_noSensorEventsYet_reportOpenedState() {
- mProvider.setListener(mListener);
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_OPENED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_deviceClosedSensorEventsBecameAvailable_reportsClosedState() {
- mProvider.setListener(mListener);
- clearInvocations(mListener);
-
- sendClosedHallSensorEvent();
- sendHingeAngle(0f);
-
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_CLOSED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_hallSensorClosedAndHingeAngleClosed_reportsClosedState() {
- sendClosedHallSensorEvent();
- sendHingeAngle(0f);
-
- mProvider.setListener(mListener);
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_CLOSED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_hallSensorClosedAndHingeAngleFullyOpened_reportsOpenedState() {
- sendClosedHallSensorEvent();
- sendHingeAngle(180f);
-
- mProvider.setListener(mListener);
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_OPENED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_hallSensorOpenedAndHingeAngleClosed_reportsClosedState() {
- sendOpenedHallSensorEvent();
- sendHingeAngle(0f);
-
- mProvider.setListener(mListener);
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_CLOSED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_unfoldingFromClosedToFullyOpened_reportsOpenedEvent() {
- sendClosedHallSensorEvent();
- sendHingeAngle(0f);
- mProvider.setListener(mListener);
- clearInvocations(mListener);
-
- sendOpenedHallSensorEvent();
- sendHingeAngle(180f);
-
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_OPENED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_unfoldingFromClosedToTentMode_keepsClosedState() {
- sendClosedHallSensorEvent();
- sendHingeAngle(0f);
- mProvider.setListener(mListener);
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_CLOSED, mIntegerCaptor.getValue().intValue());
- clearInvocations(mListener);
-
- sendOpenedHallSensorEvent();
- sendHingeAngle(60f);
-
- verify(mListener, never()).onStateChanged(mIntegerCaptor.capture());
- }
-
- @Test
- public void test_foldingFromFullyOpenToAlmostClosed_movesToHalfOpenedState() {
- sendOpenedHallSensorEvent();
- sendHingeAngle(180f);
- mProvider.setListener(mListener);
- clearInvocations(mListener);
-
- sendHingeAngle(15f);
-
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- // Assert that we don't go into tent mode (OPENED state) and switch to HALF_OPENED state
- assertEquals(DEVICE_STATE_HALF_OPENED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_foldingFromFullyOpenToFullyClosed_movesToClosedState() {
- sendOpenedHallSensorEvent();
- sendHingeAngle(180f);
-
- sendClosedHallSensorEvent();
- sendHingeAngle(0f);
-
- mProvider.setListener(mListener);
- verify(mListener).onStateChanged(mIntegerCaptor.capture());
- assertEquals(DEVICE_STATE_CLOSED, mIntegerCaptor.getValue().intValue());
- }
-
- @Test
- public void test_slowUnfolding_reportsEventsInOrder() {
- sendClosedHallSensorEvent();
- sendHingeAngle(0f);
- mProvider.setListener(mListener);
-
- sendHingeAngle(2f);
- sendOpenedHallSensorEvent();
- sendHingeAngle(10f);
- sendHingeAngle(60f);
- sendHingeAngle(100f);
- sendHingeAngle(180f);
-
- verify(mListener, atLeastOnce()).onStateChanged(mIntegerCaptor.capture());
- assertThat(mIntegerCaptor.getAllValues()).containsExactly(
- DEVICE_STATE_CLOSED,
- DEVICE_STATE_HALF_OPENED,
- DEVICE_STATE_OPENED
- );
- }
-
- @Test
- public void test_slowFolding_reportsEventsInOrder() {
- sendOpenedHallSensorEvent();
- sendHingeAngle(180f);
- mProvider.setListener(mListener);
-
- sendHingeAngle(180f);
- sendHingeAngle(100f);
- sendHingeAngle(60f);
- sendHingeAngle(10f);
- sendClosedHallSensorEvent();
- sendHingeAngle(2f);
-
- verify(mListener, atLeastOnce()).onStateChanged(mIntegerCaptor.capture());
- assertThat(mIntegerCaptor.getAllValues()).containsExactly(
- DEVICE_STATE_OPENED,
- DEVICE_STATE_HALF_OPENED,
- DEVICE_STATE_CLOSED
- );
- }
-
- @Test
- public void test_slowUnfoldingAndFolding_reportsEventsInOrder() {
- sendClosedHallSensorEvent();
- sendHingeAngle(0f);
- mProvider.setListener(mListener);
- assertLatestReportedState(DEVICE_STATE_CLOSED);
-
- // Started unfolding
- sendHingeAngle(2f);
- sendOpenedHallSensorEvent();
- sendHingeAngle(30f);
- assertLatestReportedState(DEVICE_STATE_CLOSED);
- sendHingeAngle(60f);
- assertLatestReportedState(DEVICE_STATE_CLOSED);
- sendHingeAngle(100f);
- assertLatestReportedState(DEVICE_STATE_HALF_OPENED);
- sendHingeAngle(180f);
- assertLatestReportedState(DEVICE_STATE_OPENED);
-
- // Started folding
- sendHingeAngle(100f);
- assertLatestReportedState(DEVICE_STATE_HALF_OPENED);
- sendHingeAngle(60f);
- assertLatestReportedState(DEVICE_STATE_HALF_OPENED);
- sendHingeAngle(30f);
- assertLatestReportedState(DEVICE_STATE_HALF_OPENED);
- sendClosedHallSensorEvent();
- sendHingeAngle(2f);
- assertLatestReportedState(DEVICE_STATE_CLOSED);
-
- verify(mListener, atLeastOnce()).onStateChanged(mIntegerCaptor.capture());
- assertThat(mIntegerCaptor.getAllValues()).containsExactly(
- DEVICE_STATE_CLOSED,
- DEVICE_STATE_HALF_OPENED,
- DEVICE_STATE_OPENED,
- DEVICE_STATE_HALF_OPENED,
- DEVICE_STATE_CLOSED
- );
- }
-
- private void assertLatestReportedState(int state) {
- final ArgumentCaptor<Integer> integerCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mListener, atLeastOnce()).onStateChanged(integerCaptor.capture());
- assertEquals(state, integerCaptor.getValue().intValue());
- }
-
- private void sendSensorEvent(Sensor sensor, float value) {
- SensorEvent event = mock(SensorEvent.class);
- event.sensor = sensor;
- try {
- FieldSetter.setField(event, event.getClass().getField("values"),
- new float[]{value});
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
-
- mSensorEventListener.onSensorChanged(event);
- }
-
- private void sendClosedHallSensorEvent() {
- // Hall sensor value '1f' is for the closed state
- sendSensorEvent(mHallSensor, /* value= */ 1f);
- }
-
- private void sendOpenedHallSensorEvent() {
- // Hall sensor value '0f' is for the opened state
- sendSensorEvent(mHallSensor, /* value= */ 0f);
- }
-
- private void sendHingeAngle(float angle) {
- sendSensorEvent(mHingeAngleSensor, /* value= */ angle);
- }
-}