diff options
Diffstat (limited to 'core/java')
3 files changed, 161 insertions, 16 deletions
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java index 30aa4db938da..bdd45e6df448 100644 --- a/core/java/android/hardware/devicestate/DeviceStateManager.java +++ b/core/java/android/hardware/devicestate/DeviceStateManager.java @@ -16,6 +16,7 @@ package android.hardware.devicestate; +import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; @@ -115,6 +116,52 @@ public final class DeviceStateManager { } /** + * Submits a {@link DeviceStateRequest request} to override the base state of the device. This + * should only be used for testing, where you want to simulate the physical change to the + * device state. + * <p> + * By default, the request is kept active until one of the following occurs: + * <ul> + * <li>The physical state of the device changes</li> + * <li>The system deems the request can no longer be honored, for example if the requested + * state becomes unsupported. + * <li>A call to {@link #cancelBaseStateOverride}. + * <li>Another processes submits a request succeeding this request in which case the request + * will be canceled. + * </ul> + * + * Submitting a base state override request may not cause any change in the presentation + * of the system if there is an emulated request made through {@link #requestState}, as the + * emulated override requests take priority. + * + * @throws IllegalArgumentException if the requested state is unsupported. + * @throws SecurityException if the caller does not hold the + * {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission. + * + * @see DeviceStateRequest + */ + @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) + public void requestBaseStateOverride(@NonNull DeviceStateRequest request, + @Nullable @CallbackExecutor Executor executor, + @Nullable DeviceStateRequest.Callback callback) { + mGlobal.requestBaseStateOverride(request, executor, callback); + } + + /** + * Cancels the active {@link DeviceStateRequest} previously submitted with a call to + * {@link #requestBaseStateOverride(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}. + * <p> + * This method is noop if there is no base state request currently active. + * + * @throws SecurityException if the caller does not hold the + * {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission. + */ + @RequiresPermission(Manifest.permission.CONTROL_DEVICE_STATE) + public void cancelBaseStateOverride() { + mGlobal.cancelBaseStateOverride(); + } + + /** * Registers a callback to receive notifications about changes in device state. * * @param executor the executor to process notifications. diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java index aba538f51043..738045dafdf1 100644 --- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java +++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java @@ -18,6 +18,7 @@ package android.hardware.devicestate; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.content.Context; import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback; import android.os.Binder; @@ -81,6 +82,7 @@ public final class DeviceStateManagerGlobal { @VisibleForTesting public DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) { mDeviceStateManager = deviceStateManager; + registerCallbackIfNeededLocked(); } /** @@ -116,27 +118,22 @@ public final class DeviceStateManagerGlobal { * DeviceStateRequest.Callback) * @see DeviceStateRequest */ + @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE, + conditional = true) public void requestState(@NonNull DeviceStateRequest request, @Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) { - if (callback == null && executor != null) { - throw new IllegalArgumentException("Callback must be supplied with executor."); - } else if (executor == null && callback != null) { - throw new IllegalArgumentException("Executor must be supplied with callback."); - } - + DeviceStateRequestWrapper requestWrapper = new DeviceStateRequestWrapper(request, callback, + executor); synchronized (mLock) { - registerCallbackIfNeededLocked(); - if (findRequestTokenLocked(request) != null) { // This request has already been submitted. return; } - // Add the request wrapper to the mRequests array before requesting the state as the // callback could be triggered immediately if the mDeviceStateManager IBinder is in the // same process as this instance. IBinder token = new Binder(); - mRequests.put(token, new DeviceStateRequestWrapper(request, callback, executor)); + mRequests.put(token, requestWrapper); try { mDeviceStateManager.requestState(token, request.getState(), request.getFlags()); @@ -153,10 +150,10 @@ public final class DeviceStateManagerGlobal { * * @see DeviceStateManager#cancelStateRequest */ + @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE, + conditional = true) public void cancelStateRequest() { synchronized (mLock) { - registerCallbackIfNeededLocked(); - try { mDeviceStateManager.cancelStateRequest(); } catch (RemoteException ex) { @@ -166,6 +163,56 @@ public final class DeviceStateManagerGlobal { } /** + * Submits a {@link DeviceStateRequest request} to modify the base state of the device. + * + * @see DeviceStateManager#requestBaseStateOverride(DeviceStateRequest, Executor, + * DeviceStateRequest.Callback) + * @see DeviceStateRequest + */ + @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) + public void requestBaseStateOverride(@NonNull DeviceStateRequest request, + @Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) { + DeviceStateRequestWrapper requestWrapper = new DeviceStateRequestWrapper(request, callback, + executor); + synchronized (mLock) { + if (findRequestTokenLocked(request) != null) { + // This request has already been submitted. + return; + } + // Add the request wrapper to the mRequests array before requesting the state as the + // callback could be triggered immediately if the mDeviceStateManager IBinder is in the + // same process as this instance. + IBinder token = new Binder(); + mRequests.put(token, requestWrapper); + + try { + mDeviceStateManager.requestBaseStateOverride(token, request.getState(), + request.getFlags()); + } catch (RemoteException ex) { + mRequests.remove(token); + throw ex.rethrowFromSystemServer(); + } + } + } + + /** + * Cancels a {@link DeviceStateRequest request} previously submitted with a call to + * {@link #requestBaseStateOverride(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}. + * + * @see DeviceStateManager#cancelBaseStateOverride + */ + @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) + public void cancelBaseStateOverride() { + synchronized (mLock) { + try { + mDeviceStateManager.cancelBaseStateOverride(); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + } + + /** * Registers a callback to receive notifications about changes in device state. * * @see DeviceStateManager#registerCallback(Executor, DeviceStateCallback) @@ -179,9 +226,6 @@ public final class DeviceStateManagerGlobal { // This callback is already registered. return; } - - registerCallbackIfNeededLocked(); - // Add the callback wrapper to the mCallbacks array after registering the callback as // the callback could be triggered immediately if the mDeviceStateManager IBinder is in // the same process as this instance. @@ -357,6 +401,8 @@ public final class DeviceStateManagerGlobal { DeviceStateRequestWrapper(@NonNull DeviceStateRequest request, @Nullable DeviceStateRequest.Callback callback, @Nullable Executor executor) { + validateRequestWrapperParameters(callback, executor); + mRequest = request; mCallback = callback; mExecutor = executor; @@ -377,5 +423,14 @@ public final class DeviceStateManagerGlobal { mExecutor.execute(() -> mCallback.onRequestCanceled(mRequest)); } + + private void validateRequestWrapperParameters( + @Nullable DeviceStateRequest.Callback callback, @Nullable Executor executor) { + if (callback == null && executor != null) { + throw new IllegalArgumentException("Callback must be supplied with executor."); + } else if (executor == null && callback != null) { + throw new IllegalArgumentException("Executor must be supplied with callback."); + } + } } } diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl index e450e42497a0..7175eae58a26 100644 --- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl +++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl @@ -41,6 +41,10 @@ interface IDeviceStateManager { * previously registered with {@link #registerCallback(IDeviceStateManagerCallback)} before a * call to this method. * + * Requesting a state does not cancel a base state override made through + * {@link #requestBaseStateOverride}, but will still attempt to put the device into the + * supplied {@code state}. + * * @param token the request token provided * @param state the state of device the request is asking for * @param flags any flags that correspond to the request @@ -50,14 +54,53 @@ interface IDeviceStateManager { * @throws IllegalStateException if the supplied {@code token} has already been registered. * @throws IllegalArgumentException if the supplied {@code state} is not supported. */ + @JavaPassthrough(annotation= + "@android.annotation.RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true)") void requestState(IBinder token, int state, int flags); /** * Cancels the active request previously submitted with a call to - * {@link #requestState(IBinder, int, int)}. + * {@link #requestState(IBinder, int, int)}. Will have no effect on any base state override that + * was previously requested with {@link #requestBaseStateOverride}. * * @throws IllegalStateException if a callback has not yet been registered for the calling * process. */ + @JavaPassthrough(annotation= + "@android.annotation.RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true)") void cancelStateRequest(); + + /** + * Requests that the device's base state be overridden to the supplied {@code state}. A callback + * <b>MUST</b> have been previously registered with + * {@link #registerCallback(IDeviceStateManagerCallback)} before a call to this method. + * + * This method should only be used for testing, when you want to simulate the device physically + * changing states. If you are looking to change device state for a feature, where the system + * should still be aware that the physical state is different than the emulated state, use + * {@link #requestState}. + * + * @param token the request token provided + * @param state the state of device the request is asking for + * @param flags any flags that correspond to the request + * + * @throws IllegalStateException if a callback has not yet been registered for the calling + * process. + * @throws IllegalStateException if the supplied {@code token} has already been registered. + * @throws IllegalArgumentException if the supplied {@code state} is not supported. + */ + @JavaPassthrough(annotation= + "@android.annotation.RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)") + void requestBaseStateOverride(IBinder token, int state, int flags); + + /** + * Cancels the active base state request previously submitted with a call to + * {@link #overrideBaseState(IBinder, int, int)}. + * + * @throws IllegalStateException if a callback has not yet been registered for the calling + * process. + */ + @JavaPassthrough(annotation= + "@android.annotation.RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)") + void cancelBaseStateOverride(); } |
