diff options
| author | 2021-03-01 22:22:06 +0000 | |
|---|---|---|
| committer | 2021-03-01 22:22:06 +0000 | |
| commit | e72cce52353e6f4c12dfa04d28bcc8e4d37a2bee (patch) | |
| tree | 1d39f2fc819ad25e8d2d68b08b137bf7a54d4e41 | |
| parent | a25f62e2a24b253d3878ea314d7d7f581b9ad72e (diff) | |
| parent | 2c35bdf90173c3c11c1a5c05f66be53945631bc9 (diff) | |
Merge "Add callbacks for change in supported device states and non-override state." into sc-dev
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) { |