summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Darryl Johnson <darryljohnson@google.com> 2021-03-01 22:22:06 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-03-01 22:22:06 +0000
commite72cce52353e6f4c12dfa04d28bcc8e4d37a2bee (patch)
tree1d39f2fc819ad25e8d2d68b08b137bf7a54d4e41
parenta25f62e2a24b253d3878ea314d7d7f581b9ad72e (diff)
parent2c35bdf90173c3c11c1a5c05f66be53945631bc9 (diff)
Merge "Add callbacks for change in supported device states and non-override state." into sc-dev
-rw-r--r--core/api/test-current.txt10
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateInfo.aidl19
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateInfo.java162
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManager.java61
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java155
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateRequest.java6
-rw-r--r--core/java/android/hardware/devicestate/IDeviceStateManager.aidl9
-rw-r--r--core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl23
-rw-r--r--core/tests/devicestatetests/Android.bp1
-rw-r--r--core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java127
-rw-r--r--core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java182
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java152
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java4
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java6
-rw-r--r--services/core/java/com/android/server/policy/DisplayFoldController.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java133
16 files changed, 773 insertions, 283 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 316be0bc5625..6ee57d6b0392 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1021,17 +1021,19 @@ package android.hardware.camera2 {
package android.hardware.devicestate {
public final class DeviceStateManager {
- method public void addDeviceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
method @NonNull public int[] getSupportedStates();
- method public void removeDeviceStateListener(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
+ method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
+ method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback);
field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff
field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0
}
- public static interface DeviceStateManager.DeviceStateListener {
- method public void onDeviceStateChanged(int);
+ public static interface DeviceStateManager.DeviceStateCallback {
+ method public default void onBaseStateChanged(int);
+ method public void onStateChanged(int);
+ method public default void onSupportedStatesChanged(@NonNull int[]);
}
public final class DeviceStateRequest {
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.aidl b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
new file mode 100644
index 000000000000..e85679243994
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.hardware.devicestate;
+
+parcelable DeviceStateInfo;
diff --git a/core/java/android/hardware/devicestate/DeviceStateInfo.java b/core/java/android/hardware/devicestate/DeviceStateInfo.java
new file mode 100644
index 000000000000..bc6af37afc45
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateInfo.java
@@ -0,0 +1,162 @@
+/*
+ * 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 android.hardware.devicestate;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+
+/**
+ * Information about the state of the device.
+ *
+ * @hide
+ */
+public final class DeviceStateInfo implements Parcelable {
+ /** Bit that indicates the {@link #supportedStates} field has changed. */
+ public static final int CHANGED_SUPPORTED_STATES = 1 << 0;
+
+ /** Bit that indicates the {@link #baseState} field has changed. */
+ public static final int CHANGED_BASE_STATE = 1 << 1;
+
+ /** Bit that indicates the {@link #currentState} field has changed. */
+ public static final int CHANGED_CURRENT_STATE = 1 << 2;
+
+ @IntDef(prefix = {"CHANGED_"}, flag = true, value = {
+ CHANGED_SUPPORTED_STATES,
+ CHANGED_BASE_STATE,
+ CHANGED_CURRENT_STATE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ChangeFlags {}
+
+ /**
+ * The list of states supported by the device.
+ */
+ @NonNull
+ public final int[] supportedStates;
+
+ /**
+ * The base (non-override) state of the device. The base state is the state of the device
+ * ignoring any override requests made through a call to {@link DeviceStateManager#requestState(
+ * DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+ */
+ public final int baseState;
+
+ /**
+ * The state of the device.
+ */
+ public final int currentState;
+
+ /**
+ * Creates a new instance of {@link DeviceStateInfo}.
+ * <p>
+ * NOTE: Unlike {@link #DeviceStateInfo(DeviceStateInfo)}, this constructor does not copy the
+ * supplied parameters.
+ */
+ public DeviceStateInfo(@NonNull int[] supportedStates, int baseState, int state) {
+ this.supportedStates = supportedStates;
+ this.baseState = baseState;
+ this.currentState = state;
+ }
+
+ /**
+ * Creates a new instance of {@link DeviceStateInfo} copying the fields of {@code info} into
+ * the fields of the returned instance.
+ */
+ public DeviceStateInfo(@NonNull DeviceStateInfo info) {
+ this(Arrays.copyOf(info.supportedStates, info.supportedStates.length),
+ info.baseState, info.currentState);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (this == other) return true;
+ if (other == null || getClass() != other.getClass()) return false;
+ DeviceStateInfo that = (DeviceStateInfo) other;
+ return baseState == that.baseState
+ && currentState == that.currentState
+ && Arrays.equals(supportedStates, that.supportedStates);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(baseState, currentState);
+ result = 31 * result + Arrays.hashCode(supportedStates);
+ return result;
+ }
+
+ /** Returns a bitmask of the differences between this instance and {@code other}. */
+ @ChangeFlags
+ public int diff(@NonNull DeviceStateInfo other) {
+ int diff = 0;
+ if (!Arrays.equals(supportedStates, other.supportedStates)) {
+ diff |= CHANGED_SUPPORTED_STATES;
+ }
+ if (baseState != other.baseState) {
+ diff |= CHANGED_BASE_STATE;
+ }
+ if (currentState != other.currentState) {
+ diff |= CHANGED_CURRENT_STATE;
+ }
+ return diff;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(supportedStates.length);
+ for (int i = 0; i < supportedStates.length; i++) {
+ dest.writeInt(supportedStates[i]);
+ }
+
+ dest.writeInt(baseState);
+ dest.writeInt(currentState);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<DeviceStateInfo>() {
+ @Override
+ public DeviceStateInfo createFromParcel(Parcel source) {
+ final int numberOfSupportedStates = source.readInt();
+ final int[] supportedStates = new int[numberOfSupportedStates];
+ for (int i = 0; i < numberOfSupportedStates; i++) {
+ supportedStates[i] = source.readInt();
+ }
+ final int baseState = source.readInt();
+ final int currentState = source.readInt();
+
+ return new DeviceStateInfo(supportedStates, baseState, currentState);
+ }
+
+ @Override
+ public DeviceStateInfo[] newArray(int size) {
+ return new DeviceStateInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index 2d4b2ccd7514..250145e92b89 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -111,38 +111,63 @@ public final class DeviceStateManager {
}
/**
- * Registers a listener to receive notifications about changes in device state.
+ * Registers a callback to receive notifications about changes in device state.
*
* @param executor the executor to process notifications.
- * @param listener the listener to register.
+ * @param callback the callback to register.
*
- * @see DeviceStateListener
+ * @see DeviceStateCallback
*/
- public void addDeviceStateListener(@NonNull @CallbackExecutor Executor executor,
- @NonNull DeviceStateListener listener) {
- mGlobal.registerDeviceStateListener(listener, executor);
+ public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull DeviceStateCallback callback) {
+ mGlobal.registerDeviceStateCallback(callback, executor);
}
/**
- * Unregisters a listener previously registered with
- * {@link #addDeviceStateListener(Executor, DeviceStateListener)}.
+ * Unregisters a callback previously registered with
+ * {@link #registerCallback(Executor, DeviceStateCallback)}.
*/
- public void removeDeviceStateListener(@NonNull DeviceStateListener listener) {
- mGlobal.unregisterDeviceStateListener(listener);
+ public void unregisterCallback(@NonNull DeviceStateCallback callback) {
+ mGlobal.unregisterDeviceStateCallback(callback);
}
- /**
- * Listens for changes in device states.
- */
- public interface DeviceStateListener {
+ /** Callback to receive notifications about changes in device state. */
+ public interface DeviceStateCallback {
+ /**
+ * Called in response to a change in the states supported by the device.
+ * <p>
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in the supported states.
+ *
+ * @param supportedStates the new supported states.
+ *
+ * @see DeviceStateManager#getSupportedStates()
+ */
+ default void onSupportedStatesChanged(@NonNull int[] supportedStates) {}
+
+ /**
+ * Called in response to a change in the base device state.
+ * <p>
+ * The base state is the state of the device without considering any requests made through
+ * calls to {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}
+ * from any client process. The base state is guaranteed to match the state provided with a
+ * call to {@link #onStateChanged(int)} when there are no active requests from any process.
+ * <p>
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in the non-override state.
+ *
+ * @param state the new base device state.
+ */
+ default void onBaseStateChanged(int state) {}
+
/**
* Called in response to device state changes.
* <p>
- * Guaranteed to be called once on registration of the listener with the
- * initial value and then on every subsequent change in device state.
+ * Guaranteed to be called once on registration of the callback with the initial value and
+ * then on every subsequent change in device state.
*
- * @param deviceState the new device state.
+ * @param state the new device state.
*/
- void onDeviceStateChanged(int deviceState);
+ void onStateChanged(int state);
}
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index b9ae88ea840f..1b37fb9fdad3 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -19,7 +19,7 @@ package android.hardware.devicestate;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.devicestate.DeviceStateManager.DeviceStateListener;
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -31,12 +31,14 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.concurrent.Executor;
/**
* Provides communication with the device state system service on behalf of applications.
*
* @see DeviceStateManager
+ *
* @hide
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
@@ -68,13 +70,13 @@ public final class DeviceStateManagerGlobal {
private DeviceStateManagerCallback mCallback;
@GuardedBy("mLock")
- private final ArrayList<DeviceStateListenerWrapper> mListeners = new ArrayList<>();
+ private final ArrayList<DeviceStateCallbackWrapper> mCallbacks = new ArrayList<>();
@GuardedBy("mLock")
private final ArrayMap<IBinder, DeviceStateRequestWrapper> mRequests = new ArrayMap<>();
@Nullable
@GuardedBy("mLock")
- private Integer mLastReceivedState;
+ private DeviceStateInfo mLastReceivedInfo;
@VisibleForTesting
public DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
@@ -87,18 +89,31 @@ public final class DeviceStateManagerGlobal {
* @see DeviceStateManager#getSupportedStates()
*/
public int[] getSupportedStates() {
- try {
- return mDeviceStateManager.getSupportedDeviceStates();
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
+ synchronized (mLock) {
+ final DeviceStateInfo currentInfo;
+ if (mLastReceivedInfo != null) {
+ // If we have mLastReceivedInfo a callback is registered for this instance and it
+ // is receiving the most recent info from the server. Use that info here.
+ currentInfo = mLastReceivedInfo;
+ } else {
+ // If mLastReceivedInfo is null there is no registered callback so we manually
+ // fetch the current info.
+ try {
+ currentInfo = mDeviceStateManager.getDeviceStateInfo();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ return Arrays.copyOf(currentInfo.supportedStates, currentInfo.supportedStates.length);
}
}
/**
* Submits a {@link DeviceStateRequest request} to modify the device state.
*
- * @see DeviceStateManager#requestState(DeviceStateRequest,
- * Executor, DeviceStateRequest.Callback)
+ * @see DeviceStateManager#requestState(DeviceStateRequest, Executor,
+ * DeviceStateRequest.Callback)
* @see DeviceStateRequest
*/
public void requestState(@NonNull DeviceStateRequest request,
@@ -157,49 +172,56 @@ public final class DeviceStateManagerGlobal {
}
/**
- * Registers a listener to receive notifications about changes in device state.
+ * Registers a callback to receive notifications about changes in device state.
*
- * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+ * @see DeviceStateManager#registerCallback(Executor, DeviceStateCallback)
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
- public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
+ public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
@NonNull Executor executor) {
- Integer stateToReport;
- DeviceStateListenerWrapper wrapper;
+ DeviceStateCallbackWrapper wrapper;
+ DeviceStateInfo currentInfo;
synchronized (mLock) {
- registerCallbackIfNeededLocked();
-
- int index = findListenerLocked(listener);
+ int index = findCallbackLocked(callback);
if (index != -1) {
- // This listener is already registered.
+ // This callback is already registered.
return;
}
- wrapper = new DeviceStateListenerWrapper(listener, executor);
- mListeners.add(wrapper);
- stateToReport = mLastReceivedState;
- }
+ registerCallbackIfNeededLocked();
+ if (mLastReceivedInfo == null) {
+ // Initialize the last received info with the current info if this is the first
+ // callback being registered.
+ try {
+ mLastReceivedInfo = mDeviceStateManager.getDeviceStateInfo();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
- if (stateToReport != null) {
- // Notify the listener with the most recent device state from the server. If the state
- // to report is null this is likely the first listener added and we're still waiting
- // from the callback from the server.
- wrapper.notifyDeviceStateChanged(stateToReport);
+ currentInfo = new DeviceStateInfo(mLastReceivedInfo);
+
+ wrapper = new DeviceStateCallbackWrapper(callback, executor);
+ mCallbacks.add(wrapper);
}
+
+ wrapper.notifySupportedStatesChanged(currentInfo.supportedStates);
+ wrapper.notifyBaseStateChanged(currentInfo.baseState);
+ wrapper.notifyStateChanged(currentInfo.currentState);
}
/**
- * Unregisters a listener previously registered with
- * {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
+ * Unregisters a callback previously registered with
+ * {@link #registerDeviceStateCallback(DeviceStateCallback, Executor)}}.
*
- * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
+ * @see DeviceStateManager#unregisterCallback(DeviceStateCallback)
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
- public void unregisterDeviceStateListener(DeviceStateListener listener) {
+ public void unregisterDeviceStateCallback(@NonNull DeviceStateCallback callback) {
synchronized (mLock) {
- int indexToRemove = findListenerLocked(listener);
+ int indexToRemove = findCallbackLocked(callback);
if (indexToRemove != -1) {
- mListeners.remove(indexToRemove);
+ mCallbacks.remove(indexToRemove);
}
}
}
@@ -210,14 +232,15 @@ public final class DeviceStateManagerGlobal {
try {
mDeviceStateManager.registerCallback(mCallback);
} catch (RemoteException ex) {
+ mCallback = null;
throw ex.rethrowFromSystemServer();
}
}
}
- private int findListenerLocked(DeviceStateListener listener) {
- for (int i = 0; i < mListeners.size(); i++) {
- if (mListeners.get(i).mDeviceStateListener.equals(listener)) {
+ private int findCallbackLocked(DeviceStateCallback callback) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ if (mCallbacks.get(i).mDeviceStateCallback.equals(callback)) {
return i;
}
}
@@ -234,16 +257,34 @@ public final class DeviceStateManagerGlobal {
return null;
}
- /** Handles a call from the server that the device state has changed. */
- private void handleDeviceStateChanged(int newDeviceState) {
- ArrayList<DeviceStateListenerWrapper> listeners;
+ /** Handles a call from the server that the device state info has changed. */
+ private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
+ ArrayList<DeviceStateCallbackWrapper> callbacks;
+ DeviceStateInfo oldInfo;
synchronized (mLock) {
- mLastReceivedState = newDeviceState;
- listeners = new ArrayList<>(mListeners);
+ oldInfo = mLastReceivedInfo;
+ mLastReceivedInfo = info;
+ callbacks = new ArrayList<>(mCallbacks);
}
- for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).notifyDeviceStateChanged(newDeviceState);
+ final int diff = oldInfo == null ? 1 : info.diff(oldInfo);
+ if ((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ // Copy the array to prevent callbacks from modifying the internal state.
+ final int[] supportedStates = Arrays.copyOf(info.supportedStates,
+ info.supportedStates.length);
+ callbacks.get(i).notifySupportedStatesChanged(supportedStates);
+ }
+ }
+ if ((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ callbacks.get(i).notifyBaseStateChanged(info.baseState);
+ }
+ }
+ if ((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ callbacks.get(i).notifyStateChanged(info.currentState);
+ }
}
}
@@ -291,8 +332,8 @@ public final class DeviceStateManagerGlobal {
private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
@Override
- public void onDeviceStateChanged(int deviceState) {
- handleDeviceStateChanged(deviceState);
+ public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+ handleDeviceStateInfoChanged(info);
}
@Override
@@ -311,17 +352,29 @@ public final class DeviceStateManagerGlobal {
}
}
- private static final class DeviceStateListenerWrapper {
- private final DeviceStateListener mDeviceStateListener;
+ private static final class DeviceStateCallbackWrapper {
+ @NonNull
+ private final DeviceStateCallback mDeviceStateCallback;
+ @NonNull
private final Executor mExecutor;
- DeviceStateListenerWrapper(DeviceStateListener listener, Executor executor) {
- mDeviceStateListener = listener;
+ DeviceStateCallbackWrapper(@NonNull DeviceStateCallback callback,
+ @NonNull Executor executor) {
+ mDeviceStateCallback = callback;
mExecutor = executor;
}
- void notifyDeviceStateChanged(int newDeviceState) {
- mExecutor.execute(() -> mDeviceStateListener.onDeviceStateChanged(newDeviceState));
+ void notifySupportedStatesChanged(int[] newSupportedStates) {
+ mExecutor.execute(() ->
+ mDeviceStateCallback.onSupportedStatesChanged(newSupportedStates));
+ }
+
+ void notifyBaseStateChanged(int newBaseState) {
+ mExecutor.execute(() -> mDeviceStateCallback.onBaseStateChanged(newBaseState));
+ }
+
+ void notifyStateChanged(int newDeviceState) {
+ mExecutor.execute(() -> mDeviceStateCallback.onStateChanged(newDeviceState));
}
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateRequest.java b/core/java/android/hardware/devicestate/DeviceStateRequest.java
index 70f7002597ed..df488d2f6df1 100644
--- a/core/java/android/hardware/devicestate/DeviceStateRequest.java
+++ b/core/java/android/hardware/devicestate/DeviceStateRequest.java
@@ -116,7 +116,7 @@ public final class DeviceStateRequest {
* requested state.
* <p>
* Guaranteed to be called after a call to
- * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)} with a state
+ * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)} with a state
* matching the requested state.
*/
default void onRequestActivated(@NonNull DeviceStateRequest request) {}
@@ -125,7 +125,7 @@ public final class DeviceStateRequest {
* Called to indicate the request has been temporarily suspended.
* <p>
* Guaranteed to be called before a call to
- * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+ * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
*/
default void onRequestSuspended(@NonNull DeviceStateRequest request) {}
@@ -135,7 +135,7 @@ public final class DeviceStateRequest {
* DeviceStateRequest.Callback)}.
* <p>
* Guaranteed to be called before a call to
- * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+ * {@link DeviceStateManager.DeviceStateCallback#onStateChanged(int)}.
* <p>
* Note: A call to {@link #onRequestSuspended(DeviceStateRequest)} is not guaranteed to
* occur before this method.
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
index 323ad21e4884..14ed03d09fd0 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -16,25 +16,26 @@
package android.hardware.devicestate;
+import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.IDeviceStateManagerCallback;
/** @hide */
interface IDeviceStateManager {
+ /** Returns the current device state info. */
+ DeviceStateInfo getDeviceStateInfo();
+
/**
* Registers a callback to receive notifications from the device state manager. Only one
* callback can be registered per-process.
* <p>
* As the callback mechanism is used to alert the caller of changes to request status a callback
* <b>MUST</b> be registered before calling {@link #requestState(IBinder, int, int)} or
- * {@link #cancelRequest(IBinder)}. Otherwise an exception will be thrown.
+ * {@link #cancelRequest(IBinder)}, otherwise an exception will be thrown.
*
* @throws SecurityException if a callback is already registered for the calling process.
*/
void registerCallback(in IDeviceStateManagerCallback callback);
- /** Returns the array of supported device state identifiers. */
- int[] getSupportedDeviceStates();
-
/**
* Requests that the device enter the supplied {@code state}. A callback <b>MUST</b> have been
* previously registered with {@link #registerCallback(IDeviceStateManagerCallback)} before a
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
index ee2a071741ef..593be867fe28 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
@@ -16,20 +16,23 @@
package android.hardware.devicestate;
+import android.hardware.devicestate.DeviceStateInfo;
+
/** @hide */
interface IDeviceStateManagerCallback {
/**
- * Called in response to a change in device state. Guaranteed to be called once with the initial
- * value on registration of the callback.
+ * Called in response to a change in {@link DeviceStateInfo}.
+ *
+ * @param info the new device state info.
*
- * @param deviceState the new state of the device.
+ * @see DeviceStateInfo
*/
- oneway void onDeviceStateChanged(int deviceState);
+ oneway void onDeviceStateInfoChanged(in DeviceStateInfo info);
/**
* Called to notify the callback that a request has become active. Guaranteed to be called
- * after a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming active
- * resulted in a device state change.
+ * after a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+ * becoming active resulted in a change of device state info.
*
* @param token the request token previously registered with
* {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -38,8 +41,8 @@ interface IDeviceStateManagerCallback {
/**
* Called to notify the callback that a request has become suspended. Guaranteed to be called
- * before a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming
- * suspended resulted in a device state change.
+ * before a subsequent call to {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request
+ * becoming suspended resulted in a change of device state info.
*
* @param token the request token previously registered with
* {@link IDeviceStateManager#requestState(IBinder, int, int)}
@@ -49,8 +52,8 @@ interface IDeviceStateManagerCallback {
/**
* Called to notify the callback that a request has become canceled. No further callbacks will
* be triggered for this request. Guaranteed to be called before a subsequent call to
- * {@link #onDeviceStateChanged(int)} if the request becoming canceled resulted in a device
- * state change.
+ * {@link #onDeviceStateInfoChanged(DeviceStateInfo)} if the request becoming canceled resulted
+ * in a change of device state info.
*
* @param token the request token previously registered with
* {@link IDeviceStateManager#requestState(IBinder, int, int)}
diff --git a/core/tests/devicestatetests/Android.bp b/core/tests/devicestatetests/Android.bp
index f7b593264cda..7748de57c2bc 100644
--- a/core/tests/devicestatetests/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -28,6 +28,7 @@ android_test {
static_libs: [
"androidx.test.rules",
"frameworks-base-testutils",
+ "mockito-target-minus-junit4",
],
libs: ["android.test.runner"],
platform_apis: true,
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
new file mode 100644
index 000000000000..dcef0a7c316d
--- /dev/null
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateInfoTest.java
@@ -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 android.hardware.devicestate;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for {@link DeviceStateInfo}.
+ * <p/>
+ * Run with <code>atest DeviceStateInfoTest</code>.
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+public final class DeviceStateInfoTest {
+ @Test
+ public void create() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int baseState = 0;
+ final int currentState = 2;
+
+ final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+ assertNotNull(info.supportedStates);
+ assertEquals(supportedStates, info.supportedStates);
+ assertEquals(baseState, info.baseState);
+ assertEquals(currentState, info.currentState);
+ }
+
+ @Test
+ public void equals() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int baseState = 0;
+ final int currentState = 2;
+
+ final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+ assertTrue(info.equals(info));
+
+ final DeviceStateInfo sameInfo = new DeviceStateInfo(supportedStates, baseState,
+ currentState);
+ assertTrue(info.equals(sameInfo));
+
+ final DeviceStateInfo differentInfo = new DeviceStateInfo(new int[]{ 0, 2}, baseState,
+ currentState);
+ assertFalse(info.equals(differentInfo));
+ }
+
+ @Test
+ public void diff_sameObject() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int baseState = 0;
+ final int currentState = 2;
+
+ final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
+ assertEquals(0, info.diff(info));
+ }
+
+ @Test
+ public void diff_differentSupportedStates() {
+ final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 0);
+ final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 2 }, 0, 0);
+ final int diff = info.diff(otherInfo);
+ assertTrue((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+ }
+
+ @Test
+ public void diff_differentNonOverrideState() {
+ final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 1, 0);
+ final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 2, 0);
+ final int diff = info.diff(otherInfo);
+ assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+ assertTrue((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+ }
+
+ @Test
+ public void diff_differentState() {
+ final DeviceStateInfo info = new DeviceStateInfo(new int[] { 1 }, 0, 1);
+ final DeviceStateInfo otherInfo = new DeviceStateInfo(new int[] { 1 }, 0, 2);
+ final int diff = info.diff(otherInfo);
+ assertFalse((diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES) > 0);
+ assertFalse((diff & DeviceStateInfo.CHANGED_BASE_STATE) > 0);
+ assertTrue((diff & DeviceStateInfo.CHANGED_CURRENT_STATE) > 0);
+ }
+
+ @Test
+ public void writeToParcel() {
+ final int[] supportedStates = new int[] { 0, 1, 2 };
+ final int nonOverrideState = 0;
+ final int state = 2;
+ final DeviceStateInfo originalInfo =
+ new DeviceStateInfo(supportedStates, nonOverrideState, state);
+
+ final Parcel parcel = Parcel.obtain();
+ originalInfo.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
+
+ final DeviceStateInfo info = DeviceStateInfo.CREATOR.createFromParcel(parcel);
+ assertEquals(originalInfo, info);
+ }
+}
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index e7fdfb8c19e9..79b4d8bc5f1c 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -16,11 +16,15 @@
package android.hardware.devicestate;
-import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import android.annotation.Nullable;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,6 +36,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.HashSet;
@@ -58,42 +63,75 @@ public final class DeviceStateManagerGlobalTest {
}
@Test
- public void registerListener() {
- mService.setBaseState(DEFAULT_DEVICE_STATE);
-
- TestDeviceStateListener listener1 = new TestDeviceStateListener();
- TestDeviceStateListener listener2 = new TestDeviceStateListener();
+ public void registerCallback() {
+ DeviceStateCallback callback1 = mock(DeviceStateCallback.class);
+ DeviceStateCallback callback2 = mock(DeviceStateCallback.class);
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener1,
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback1,
ConcurrentUtils.DIRECT_EXECUTOR);
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener2,
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback2,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(DEFAULT_DEVICE_STATE, listener1.getLastReportedState().intValue());
- assertEquals(DEFAULT_DEVICE_STATE, listener2.getLastReportedState().intValue());
+ // Verify initial callbacks
+ verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback1).onStateChanged(eq(mService.getMergedState()));
+ verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+ Mockito.reset(callback1);
+ Mockito.reset(callback2);
+
+ // Change the supported states and verify callback
+ mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE });
+ verify(callback1).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE });
+
+ Mockito.reset(callback1);
+ Mockito.reset(callback2);
+
+ // Change the base state and verify callback
mService.setBaseState(OTHER_DEVICE_STATE);
- assertEquals(OTHER_DEVICE_STATE, listener1.getLastReportedState().intValue());
- assertEquals(OTHER_DEVICE_STATE, listener2.getLastReportedState().intValue());
+ verify(callback1).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback1).onStateChanged(eq(mService.getMergedState()));
+ verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback2).onStateChanged(eq(mService.getMergedState()));
+
+ Mockito.reset(callback1);
+ Mockito.reset(callback2);
+
+ // Change the requested state and verify callback
+ DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
+ mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
+
+ verify(callback1).onStateChanged(eq(mService.getMergedState()));
+ verify(callback2).onStateChanged(eq(mService.getMergedState()));
}
@Test
- public void unregisterListener() {
- mService.setBaseState(DEFAULT_DEVICE_STATE);
+ public void unregisterCallback() {
+ DeviceStateCallback callback = mock(DeviceStateCallback.class);
- TestDeviceStateListener listener = new TestDeviceStateListener();
-
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
- mDeviceStateManagerGlobal.unregisterDeviceStateListener(listener);
+ // Verify initial callbacks
+ verify(callback).onSupportedStatesChanged(eq(mService.getSupportedStates()));
+ verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
+ verify(callback).onStateChanged(eq(mService.getMergedState()));
+ Mockito.reset(callback);
+
+ mDeviceStateManagerGlobal.unregisterDeviceStateCallback(callback);
+ mService.setSupportedStates(new int[]{OTHER_DEVICE_STATE});
mService.setBaseState(OTHER_DEVICE_STATE);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+ verifyZeroInteractions(callback);
}
@Test
- public void submittingRequestRegisteredCallback() {
+ public void submittingRequestRegistersCallback() {
assertTrue(mService.mCallbacks.isEmpty());
DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
@@ -104,37 +142,22 @@ public final class DeviceStateManagerGlobalTest {
@Test
public void submitRequest() {
- mService.setBaseState(DEFAULT_DEVICE_STATE);
-
- TestDeviceStateListener listener = new TestDeviceStateListener();
- mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+ DeviceStateCallback callback = mock(DeviceStateCallback.class);
+ mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+ verify(callback).onStateChanged(eq(mService.getBaseState()));
+ Mockito.reset(callback);
DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
- assertEquals(OTHER_DEVICE_STATE, listener.getLastReportedState().intValue());
+ verify(callback).onStateChanged(eq(OTHER_DEVICE_STATE));
+ Mockito.reset(callback);
mDeviceStateManagerGlobal.cancelRequest(request);
- assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
- }
-
- private final class TestDeviceStateListener implements DeviceStateManager.DeviceStateListener {
- @Nullable
- private Integer mLastReportedDeviceState;
-
- @Override
- public void onDeviceStateChanged(int deviceState) {
- mLastReportedDeviceState = deviceState;
- }
-
- @Nullable
- public Integer getLastReportedState() {
- return mLastReportedDeviceState;
- }
+ verify(callback).onStateChanged(eq(mService.getBaseState()));
}
private static final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
@@ -150,12 +173,34 @@ public final class DeviceStateManagerGlobalTest {
}
}
+ private int[] mSupportedStates = new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
private int mBaseState = DEFAULT_DEVICE_STATE;
- private int mMergedState = DEFAULT_DEVICE_STATE;
private ArrayList<Request> mRequests = new ArrayList<>();
private Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
+ private DeviceStateInfo getInfo() {
+ final int mergedState = mRequests.isEmpty()
+ ? mBaseState : mRequests.get(mRequests.size() - 1).state;
+ return new DeviceStateInfo(mSupportedStates, mBaseState, mergedState);
+ }
+
+ private void notifyDeviceStateInfoChanged() {
+ final DeviceStateInfo info = getInfo();
+ for (IDeviceStateManagerCallback callback : mCallbacks) {
+ try {
+ callback.onDeviceStateInfoChanged(info);
+ } catch (RemoteException e) {
+ // Do nothing. Should never happen.
+ }
+ }
+ }
+
+ @Override
+ public DeviceStateInfo getDeviceStateInfo() {
+ return getInfo();
+ }
+
@Override
public void registerCallback(IDeviceStateManagerCallback callback) {
if (mCallbacks.contains(callback)) {
@@ -163,16 +208,6 @@ public final class DeviceStateManagerGlobalTest {
}
mCallbacks.add(callback);
- try {
- callback.onDeviceStateChanged(mMergedState);
- } catch (RemoteException e) {
- // Do nothing. Should never happen.
- }
- }
-
- @Override
- public int[] getSupportedDeviceStates() {
- return new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
}
@Override
@@ -190,7 +225,7 @@ public final class DeviceStateManagerGlobalTest {
final Request request = new Request(token, state, flags);
mRequests.add(request);
- notifyStateChangedIfNeeded();
+ notifyDeviceStateInfoChanged();
for (IDeviceStateManagerCallback callback : mCallbacks) {
try {
@@ -223,32 +258,29 @@ public final class DeviceStateManagerGlobalTest {
// Do nothing. Should never happen.
}
}
- notifyStateChangedIfNeeded();
+ notifyDeviceStateInfoChanged();
+ }
+
+ public void setSupportedStates(int[] states) {
+ mSupportedStates = states;
+ notifyDeviceStateInfoChanged();
+ }
+
+ public int[] getSupportedStates() {
+ return mSupportedStates;
}
public void setBaseState(int state) {
mBaseState = state;
- notifyStateChangedIfNeeded();
+ notifyDeviceStateInfoChanged();
}
- private void notifyStateChangedIfNeeded() {
- final int originalMergedState = mMergedState;
-
- if (!mRequests.isEmpty()) {
- mMergedState = mRequests.get(mRequests.size() - 1).state;
- } else {
- mMergedState = mBaseState;
- }
+ public int getBaseState() {
+ return mBaseState;
+ }
- if (mMergedState != originalMergedState) {
- for (IDeviceStateManagerCallback callback : mCallbacks) {
- try {
- callback.onDeviceStateChanged(mMergedState);
- } catch (RemoteException e) {
- // Do nothing. Should never happen.
- }
- }
- }
+ public int getMergedState() {
+ return getInfo().currentState;
}
}
}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index b3a6f263953f..835b4688dd4e 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -25,6 +25,7 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.IDeviceStateManager;
import android.hardware.devicestate.IDeviceStateManagerCallback;
@@ -47,6 +48,7 @@ import com.android.server.policy.DeviceStatePolicyImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Optional;
/**
@@ -76,6 +78,9 @@ import java.util.Optional;
public final class DeviceStateManagerService extends SystemService {
private static final String TAG = "DeviceStateManagerService";
private static final boolean DEBUG = false;
+ // The device state to use as a placeholder before callback from the DeviceStateProvider occurs.
+ private static final DeviceState UNSPECIFIED_DEVICE_STATE =
+ new DeviceState(MINIMUM_DEVICE_STATE, "UNSPECIFIED");
private final Object mLock = new Object();
@NonNull
@@ -87,11 +92,11 @@ public final class DeviceStateManagerService extends SystemService {
@GuardedBy("mLock")
private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();
- // The current committed device state. The default of UNSET will be replaced by
- // the current state after the initial callback from the DeviceStateProvider.
+ // The current committed device state. The default of UNSPECIFIED_DEVICE_STATE will be replaced
+ // by the current state after the initial callback from the DeviceStateProvider.
@GuardedBy("mLock")
@NonNull
- private DeviceState mCommittedState = new DeviceState(MINIMUM_DEVICE_STATE, "UNSET");
+ private DeviceState mCommittedState = UNSPECIFIED_DEVICE_STATE;
// The device state that is currently awaiting callback from the policy to be committed.
@GuardedBy("mLock")
@NonNull
@@ -103,7 +108,7 @@ public final class DeviceStateManagerService extends SystemService {
// The device state that is set by the device state provider.
@GuardedBy("mLock")
@NonNull
- private Optional<DeviceState> mBaseState = Optional.empty();
+ private DeviceState mBaseState = UNSPECIFIED_DEVICE_STATE;
// List of processes registered to receive notifications about changes to device state and
// request status indexed by process id.
@@ -166,7 +171,7 @@ public final class DeviceStateManagerService extends SystemService {
* @see #getOverrideState()
*/
@NonNull
- Optional<DeviceState> getBaseState() {
+ DeviceState getBaseState() {
synchronized (mLock) {
return mBaseState;
}
@@ -203,33 +208,47 @@ public final class DeviceStateManagerService extends SystemService {
/** Returns the list of currently supported device state identifiers. */
private int[] getSupportedStateIdentifiers() {
synchronized (mLock) {
- int[] supportedStates = new int[mDeviceStates.size()];
- for (int i = 0; i < supportedStates.length; i++) {
- supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
- }
- return supportedStates;
+ return getSupportedStateIdentifiersLocked();
}
}
+ /** Returns the list of currently supported device state identifiers. */
+ private int[] getSupportedStateIdentifiersLocked() {
+ int[] supportedStates = new int[mDeviceStates.size()];
+ for (int i = 0; i < supportedStates.length; i++) {
+ supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
+ }
+ return supportedStates;
+ }
+
+ @NonNull
+ private DeviceStateInfo getDeviceStateInfoLocked() {
+ final int[] supportedStates = getSupportedStateIdentifiersLocked();
+ final int baseState = mBaseState.getIdentifier();
+ final int currentState = mCommittedState.getIdentifier();
+
+ return new DeviceStateInfo(supportedStates, baseState, currentState);
+ }
+
@VisibleForTesting
IDeviceStateManager getBinderService() {
return mBinderService;
}
private void updateSupportedStates(DeviceState[] supportedDeviceStates) {
+ boolean updatedPendingState;
synchronized (mLock) {
+ final int[] oldStateIdentifiers = getSupportedStateIdentifiersLocked();
+
mDeviceStates.clear();
for (int i = 0; i < supportedDeviceStates.length; i++) {
DeviceState state = supportedDeviceStates[i];
mDeviceStates.put(state.getIdentifier(), state);
}
- if (mBaseState.isPresent()
- && !isSupportedStateLocked(mBaseState.get().getIdentifier())) {
- // The current base state is no longer valid. We'll clear it here, though
- // we won't actually update the current state until a callback comes from the
- // provider with the most recent state.
- mBaseState = Optional.empty();
+ final int[] newStateIdentifiers = getSupportedStateIdentifiersLocked();
+ if (Arrays.equals(oldStateIdentifiers, newStateIdentifiers)) {
+ return;
}
final int requestSize = mRequestRecords.size();
@@ -240,7 +259,14 @@ public final class DeviceStateManagerService extends SystemService {
}
}
- updatePendingStateLocked();
+ updatedPendingState = updatePendingStateLocked();
+ }
+
+ if (!updatedPendingState) {
+ // If the change in the supported states didn't result in a change of the pending state
+ // commitPendingState() will never be called and the callbacks will never be notified
+ // of the change.
+ notifyDeviceStateInfoChanged();
}
notifyRequestsOfStatusChangeIfNeeded();
@@ -265,23 +291,25 @@ public final class DeviceStateManagerService extends SystemService {
}
/**
- * Requests to set the base state. The request may not be honored under certain conditions, for
- * example if the provided state is not supported.
+ * Sets the base state.
+ *
+ * @throws IllegalArgumentException if the {@code identifier} is not a supported state.
*
* @see #isSupportedStateLocked(int)
*/
private void setBaseState(int identifier) {
+ boolean updatedPendingState;
synchronized (mLock) {
- if (mBaseState.isPresent() && mBaseState.get().getIdentifier() == identifier) {
- // Base state hasn't changed. Nothing to do.
- return;
- }
-
- final Optional<DeviceState> baseState = getStateLocked(identifier);
- if (!baseState.isPresent()) {
+ final Optional<DeviceState> baseStateOptional = getStateLocked(identifier);
+ if (!baseStateOptional.isPresent()) {
throw new IllegalArgumentException("Base state is not supported");
}
+ final DeviceState baseState = baseStateOptional.get();
+ if (mBaseState.equals(baseState)) {
+ // Base state hasn't changed. Nothing to do.
+ return;
+ }
mBaseState = baseState;
final int requestSize = mRequestRecords.size();
@@ -292,7 +320,14 @@ public final class DeviceStateManagerService extends SystemService {
}
}
- updatePendingStateLocked();
+ updatedPendingState = updatePendingStateLocked();
+ }
+
+ if (!updatedPendingState) {
+ // If the change in base state didn't result in a change of the pending state
+ // commitPendingState() will never be called and the callbacks will never be notified
+ // of the change.
+ notifyDeviceStateInfoChanged();
}
notifyRequestsOfStatusChangeIfNeeded();
@@ -303,32 +338,39 @@ public final class DeviceStateManagerService extends SystemService {
* Tries to update the current pending state with the current requested state. Must call
* {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being
* changed.
+ *
+ * @return {@code true} if the pending state has changed as a result of this call, {@code false}
+ * otherwise.
*/
- private void updatePendingStateLocked() {
+ private boolean updatePendingStateLocked() {
if (mPendingState.isPresent()) {
// Have pending state, can not configure a new state until the state is committed.
- return;
+ return false;
}
final DeviceState stateToConfigure;
if (!mRequestRecords.isEmpty()) {
stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
+ } else if (isSupportedStateLocked(mBaseState.getIdentifier())) {
+ // Base state could have recently become unsupported after a change in supported states.
+ stateToConfigure = mBaseState;
} else {
- stateToConfigure = mBaseState.orElse(null);
+ stateToConfigure = null;
}
if (stateToConfigure == null) {
// No currently requested state.
- return;
+ return false;
}
- if (stateToConfigure == mCommittedState) {
+ if (stateToConfigure.equals(mCommittedState)) {
// The state requesting to be committed already matches the current committed state.
- return;
+ return false;
}
mPendingState = Optional.of(stateToConfigure);
mIsPolicyWaitingForState = true;
+ return true;
}
/**
@@ -374,13 +416,11 @@ public final class DeviceStateManagerService extends SystemService {
*/
private void commitPendingState() {
// Update the current state.
- int newState;
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "Committing state: " + mPendingState);
}
mCommittedState = mPendingState.get();
- newState = mCommittedState.getIdentifier();
if (!mRequestRecords.isEmpty()) {
final OverrideRequestRecord topRequest =
@@ -393,7 +433,7 @@ public final class DeviceStateManagerService extends SystemService {
}
// Notify callbacks of a change.
- notifyDeviceStateChanged(newState);
+ notifyDeviceStateInfoChanged();
// Notify the top request that it's active.
notifyRequestsOfStatusChangeIfNeeded();
@@ -402,14 +442,15 @@ public final class DeviceStateManagerService extends SystemService {
notifyPolicyIfNeeded();
}
- private void notifyDeviceStateChanged(int deviceState) {
+ private void notifyDeviceStateInfoChanged() {
if (Thread.holdsLock(mLock)) {
throw new IllegalStateException(
"Attempting to notify callbacks with service lock held.");
}
- // Grab the lock and copy the process records.
+ // Grab the lock and copy the process records and the current info.
ArrayList<ProcessRecord> registeredProcesses;
+ DeviceStateInfo info;
synchronized (mLock) {
if (mProcessRecords.size() == 0) {
return;
@@ -419,11 +460,13 @@ public final class DeviceStateManagerService extends SystemService {
for (int i = 0; i < mProcessRecords.size(); i++) {
registeredProcesses.add(mProcessRecords.valueAt(i));
}
+
+ info = getDeviceStateInfoLocked();
}
// After releasing the lock, send the notifications out.
for (int i = 0; i < registeredProcesses.size(); i++) {
- registeredProcesses.get(i).notifyDeviceStateAsync(deviceState);
+ registeredProcesses.get(i).notifyDeviceStateInfoAsync(info);
}
}
@@ -454,28 +497,20 @@ public final class DeviceStateManagerService extends SystemService {
}
private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
- int currentState;
- ProcessRecord record;
- // Grab the lock to register the callback and get the current state.
synchronized (mLock) {
if (mProcessRecords.contains(pid)) {
throw new SecurityException("The calling process has already registered an"
+ " IDeviceStateManagerCallback.");
}
- record = new ProcessRecord(callback, pid);
+ ProcessRecord record = new ProcessRecord(callback, pid);
try {
callback.asBinder().linkToDeath(record, 0);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
-
mProcessRecords.put(pid, record);
- currentState = mCommittedState.getIdentifier();
}
-
- // Notify the callback of the state at registration.
- record.notifyDeviceStateAsync(currentState);
}
private void handleProcessDied(ProcessRecord processRecord) {
@@ -626,9 +661,9 @@ public final class DeviceStateManagerService extends SystemService {
handleProcessDied(this);
}
- public void notifyDeviceStateAsync(int devicestate) {
+ public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) {
try {
- mCallback.onDeviceStateChanged(devicestate);
+ mCallback.onDeviceStateInfoChanged(info);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.",
ex);
@@ -752,6 +787,13 @@ public final class DeviceStateManagerService extends SystemService {
/** Implementation of {@link IDeviceStateManager} published as a binder service. */
private final class BinderService extends IDeviceStateManager.Stub {
@Override // Binder call
+ public DeviceStateInfo getDeviceStateInfo() {
+ synchronized (mLock) {
+ return getDeviceStateInfoLocked();
+ }
+ }
+
+ @Override // Binder call
public void registerCallback(IDeviceStateManagerCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("Device state callback must not be null.");
@@ -767,16 +809,6 @@ public final class DeviceStateManagerService extends SystemService {
}
@Override // Binder call
- public int[] getSupportedDeviceStates() {
- final long token = Binder.clearCallingIdentity();
- try {
- return getSupportedStateIdentifiers();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override // Binder call
public void requestState(IBinder token, int state, int flags) {
getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
"Permission required to request device state.");
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index 6cc55a6c4774..f3466006bd30 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -64,13 +64,13 @@ public class DeviceStateManagerShellCommand extends ShellCommand {
private void printState(PrintWriter pw) {
DeviceState committedState = mService.getCommittedState();
- Optional<DeviceState> baseState = mService.getBaseState();
+ DeviceState baseState = mService.getBaseState();
Optional<DeviceState> overrideState = mService.getOverrideState();
pw.println("Committed state: " + committedState);
if (overrideState.isPresent()) {
pw.println("----------------------");
- pw.println("Base state: " + baseState.orElse(null));
+ pw.println("Base state: " + baseState);
pw.println("Override state: " + overrideState.get());
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c62dd72ada70..52149ee3a4dd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -532,7 +532,7 @@ public final class DisplayManagerService extends SystemService {
DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class);
- deviceStateManager.addDeviceStateListener(new HandlerExecutor(mHandler),
+ deviceStateManager.registerCallback(new HandlerExecutor(mHandler),
new DeviceStateListener());
scheduleTraversalLocked(false);
@@ -2974,9 +2974,9 @@ public final class DisplayManagerService extends SystemService {
/**
* Listens to changes in device state and reports the state to LogicalDisplayMapper.
*/
- class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+ class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
@Override
- public void onDeviceStateChanged(int deviceState) {
+ public void onStateChanged(int deviceState) {
synchronized (mSyncRoot) {
mLogicalDisplayMapper.setDeviceStateLocked(deviceState);
}
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index 82fc22c51afc..0e12584f80a1 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -74,7 +74,7 @@ class DisplayFoldController {
mHandler = handler;
DeviceStateManager deviceStateManager = context.getSystemService(DeviceStateManager.class);
- deviceStateManager.addDeviceStateListener(new HandlerExecutor(handler),
+ deviceStateManager.registerCallback(new HandlerExecutor(handler),
new DeviceStateListener(context));
}
@@ -208,7 +208,7 @@ class DisplayFoldController {
* matches the value in the {@link com.android.internal.R.integer.config_foldedDeviceState}
* resource.
*/
- private class DeviceStateListener implements DeviceStateManager.DeviceStateListener {
+ private class DeviceStateListener implements DeviceStateManager.DeviceStateCallback {
private final int[] mFoldedDeviceStates;
DeviceStateListener(Context context) {
@@ -217,7 +217,7 @@ class DisplayFoldController {
}
@Override
- public void onDeviceStateChanged(int deviceState) {
+ public void onStateChanged(int deviceState) {
boolean folded = false;
for (int i = 0; i < mFoldedDeviceStates.length; i++) {
if (deviceState == mFoldedDeviceStates[i]) {
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index a078a77b4498..26a549d77664 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -21,8 +21,10 @@ import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STA
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertThrows;
+import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.DeviceStateRequest;
import android.hardware.devicestate.IDeviceStateManagerCallback;
import android.os.Binder;
@@ -33,10 +35,13 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Optional;
@@ -70,14 +75,14 @@ public final class DeviceStateManagerServiceTest {
public void baseStateChanged() {
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
}
@@ -89,21 +94,21 @@ public final class DeviceStateManagerServiceTest {
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
mPolicy.resumeConfigure();
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@@ -116,7 +121,7 @@ public final class DeviceStateManagerServiceTest {
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@@ -129,16 +134,19 @@ public final class DeviceStateManagerServiceTest {
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
- public void supportedStatesChanged() {
+ public void supportedStatesChanged() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
@@ -146,27 +154,44 @@ public final class DeviceStateManagerServiceTest {
// supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
+
+ assertArrayEquals(callback.getLastNotifiedInfo().supportedStates,
+ new int[] { DEFAULT_DEVICE_STATE.getIdentifier() });
}
@Test
- public void supportedStatesChanged_unsupportedBaseState() {
+ public void supportedStatesChanged_statesRemainSame() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
- mProvider.notifySupportedDeviceStates(new DeviceState[]{ OTHER_DEVICE_STATE });
+ mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
+ OTHER_DEVICE_STATE });
- // The current requested state is cleared because it is no longer supported.
+ // The current committed and requests states do not change because the current state remains
+ // supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState(), Optional.empty());
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
- mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+ // The callback wasn't notified about a change in supported states as the states have not
+ // changed.
+ assertNull(callback.getLastNotifiedInfo());
+ }
- assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ @Test
+ public void getDeviceStateInfo() throws RemoteException {
+ DeviceStateInfo info = mService.getBinderService().getDeviceStateInfo();
+ assertNotNull(info);
+ assertArrayEquals(info.supportedStates,
+ new int[] { DEFAULT_DEVICE_STATE.getIdentifier(),
+ OTHER_DEVICE_STATE.getIdentifier() });
+ assertEquals(info.baseState, DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(info.currentState, DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
@@ -175,41 +200,33 @@ public final class DeviceStateManagerServiceTest {
mService.getBinderService().registerCallback(callback);
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
- assertNotNull(callback.getLastNotifiedValue());
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ OTHER_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
OTHER_DEVICE_STATE.getIdentifier());
mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
DEFAULT_DEVICE_STATE.getIdentifier());
mPolicy.blockConfigure();
mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
// The callback should not have been notified of the state change as the policy is still
// pending callback.
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
DEFAULT_DEVICE_STATE.getIdentifier());
mPolicy.resumeConfigure();
// Now that the policy is finished processing the callback should be notified of the state
// change.
- assertEquals(callback.getLastNotifiedValue().intValue(),
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ OTHER_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
OTHER_DEVICE_STATE.getIdentifier());
- }
-
- @Test
- public void registerCallback_emitsInitialValue() throws RemoteException {
- TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
- mService.getBinderService().registerCallback(callback);
- assertNotNull(callback.getLastNotifiedValue());
- assertEquals(callback.getLastNotifiedValue().intValue(),
- DEFAULT_DEVICE_STATE.getIdentifier());
- }
-
- @Test
- public void getSupportedDeviceStates() throws RemoteException {
- final int[] expectedStates = new int[] { 0, 1 };
- assertEquals(mService.getBinderService().getSupportedDeviceStates(), expectedStates);
}
@Test
@@ -228,11 +245,16 @@ public final class DeviceStateManagerServiceTest {
TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
+ assertNotNull(callback.getLastNotifiedInfo());
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
+ OTHER_DEVICE_STATE.getIdentifier());
mService.getBinderService().cancelRequest(token);
@@ -240,10 +262,15 @@ public final class DeviceStateManagerServiceTest {
TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state once the override is cleared.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertFalse(mService.getOverrideState().isPresent());
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
+
+ assertEquals(callback.getLastNotifiedInfo().baseState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(callback.getLastNotifiedInfo().currentState,
+ DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
@@ -263,7 +290,7 @@ public final class DeviceStateManagerServiceTest {
// Committed state changes as there is a requested override.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
@@ -275,7 +302,7 @@ public final class DeviceStateManagerServiceTest {
TestDeviceStateManagerCallback.STATUS_CANCELED);
// Committed state is set back to the requested state once the override is cleared.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), OTHER_DEVICE_STATE);
assertFalse(mService.getOverrideState().isPresent());
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
@@ -297,7 +324,7 @@ public final class DeviceStateManagerServiceTest {
TestDeviceStateManagerCallback.STATUS_ACTIVE);
// Committed state changes as there is a requested override.
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
@@ -310,7 +337,7 @@ public final class DeviceStateManagerServiceTest {
// Committed state is set back to the requested state as the override state is no longer
// supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
- assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState(), DEFAULT_DEVICE_STATE);
assertFalse(mService.getOverrideState().isPresent());
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
@@ -348,6 +375,10 @@ public final class DeviceStateManagerServiceTest {
});
}
+ private static void assertArrayEquals(int[] expected, int[] actual) {
+ Assert.assertTrue(Arrays.equals(expected, actual));
+ }
+
private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
private final DeviceStateProvider mProvider;
private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
@@ -429,12 +460,14 @@ public final class DeviceStateManagerServiceTest {
public static final int STATUS_SUSPENDED = 2;
public static final int STATUS_CANCELED = 3;
- private Integer mLastNotifiedValue;
+ @Nullable
+ private DeviceStateInfo mLastNotifiedInfo;
+ private boolean mNotifiedOfChangeInSupportedStates;
private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
@Override
- public void onDeviceStateChanged(int deviceState) {
- mLastNotifiedValue = deviceState;
+ public void onDeviceStateInfoChanged(DeviceStateInfo info) {
+ mLastNotifiedInfo = info;
}
@Override
@@ -453,8 +486,8 @@ public final class DeviceStateManagerServiceTest {
}
@Nullable
- Integer getLastNotifiedValue() {
- return mLastNotifiedValue;
+ DeviceStateInfo getLastNotifiedInfo() {
+ return mLastNotifiedInfo;
}
int getLastNotifiedStatus(IBinder requestToken) {