Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1fe0c4b authored by Kenneth Ford's avatar Kenneth Ford Committed by Automerger Merge Worker
Browse files

Merge changes from topic "base-state-api" into tm-qpr-dev am: d3955eaa

parents a9228bfc d3955eaa
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1156,9 +1156,11 @@ package android.hardware.camera2 {
package android.hardware.devicestate {

  public final class DeviceStateManager {
    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelBaseStateOverride();
    method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void cancelStateRequest();
    method @NonNull public int[] getSupportedStates();
    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 requestBaseStateOverride(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
    method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) 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
+47 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.hardware.devicestate;

import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -114,6 +115,52 @@ public final class DeviceStateManager {
        mGlobal.cancelStateRequest();
    }

    /**
     * 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.
     *
+70 −15
Original line number Diff line number Diff line
@@ -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) {
@@ -165,6 +162,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.
     *
@@ -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.");
            }
        }
    }
}
+44 −1
Original line number Diff line number Diff line
@@ -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();
}
+122 −26
Original line number Diff line number Diff line
@@ -16,11 +16,12 @@

package android.hardware.devicestate;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;

@@ -36,7 +37,6 @@ 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.HashSet;
import java.util.Set;
@@ -59,6 +59,7 @@ public final class DeviceStateManagerGlobalTest {
    public void setUp() {
        mService = new TestDeviceStateManagerService();
        mDeviceStateManagerGlobal = new DeviceStateManagerGlobal(mService);
        assertFalse(mService.mCallbacks.isEmpty());
    }

    @Test
@@ -79,8 +80,8 @@ public final class DeviceStateManagerGlobalTest {
        verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
        verify(callback2).onStateChanged(eq(mService.getMergedState()));

        Mockito.reset(callback1);
        Mockito.reset(callback2);
        reset(callback1);
        reset(callback2);

        // Change the supported states and verify callback
        mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE });
@@ -88,8 +89,8 @@ public final class DeviceStateManagerGlobalTest {
        verify(callback2).onSupportedStatesChanged(eq(mService.getSupportedStates()));
        mService.setSupportedStates(new int[]{ DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE });

        Mockito.reset(callback1);
        Mockito.reset(callback2);
        reset(callback1);
        reset(callback2);

        // Change the base state and verify callback
        mService.setBaseState(OTHER_DEVICE_STATE);
@@ -98,8 +99,8 @@ public final class DeviceStateManagerGlobalTest {
        verify(callback2).onBaseStateChanged(eq(mService.getBaseState()));
        verify(callback2).onStateChanged(eq(mService.getMergedState()));

        Mockito.reset(callback1);
        Mockito.reset(callback2);
        reset(callback1);
        reset(callback2);

        // Change the requested state and verify callback
        DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
@@ -120,7 +121,7 @@ public final class DeviceStateManagerGlobalTest {
        verify(callback).onSupportedStatesChanged(eq(mService.getSupportedStates()));
        verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
        verify(callback).onStateChanged(eq(mService.getMergedState()));
        Mockito.reset(callback);
        reset(callback);

        mDeviceStateManagerGlobal.unregisterDeviceStateCallback(callback);

@@ -130,33 +131,86 @@ public final class DeviceStateManagerGlobalTest {
    }

    @Test
    public void submittingRequestRegistersCallback() {
        assertTrue(mService.mCallbacks.isEmpty());
    public void submitRequest() {
        DeviceStateCallback callback = mock(DeviceStateCallback.class);
        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
                ConcurrentUtils.DIRECT_EXECUTOR);

        DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
        verify(callback).onStateChanged(eq(mService.getBaseState()));
        reset(callback);

        DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
        mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);

        assertFalse(mService.mCallbacks.isEmpty());
        verify(callback).onStateChanged(eq(OTHER_DEVICE_STATE));
        reset(callback);

        mDeviceStateManagerGlobal.cancelStateRequest();

        verify(callback).onStateChanged(eq(mService.getBaseState()));
    }

    @Test
    public void submitRequest() {
    public void submitBaseStateOverrideRequest() {
        DeviceStateCallback callback = mock(DeviceStateCallback.class);
        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
                ConcurrentUtils.DIRECT_EXECUTOR);

        verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
        verify(callback).onStateChanged(eq(mService.getBaseState()));
        Mockito.reset(callback);
        reset(callback);

        DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
        mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
        mDeviceStateManagerGlobal.requestBaseStateOverride(request, null /* executor */,
                null /* callback */);

        verify(callback).onBaseStateChanged(eq(OTHER_DEVICE_STATE));
        verify(callback).onStateChanged(eq(OTHER_DEVICE_STATE));
        Mockito.reset(callback);
        reset(callback);

        mDeviceStateManagerGlobal.cancelStateRequest();
        mDeviceStateManagerGlobal.cancelBaseStateOverride();

        verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
        verify(callback).onStateChanged(eq(mService.getBaseState()));
    }

    @Test
    public void submitBaseAndEmulatedStateOverride() {
        DeviceStateCallback callback = mock(DeviceStateCallback.class);
        mDeviceStateManagerGlobal.registerDeviceStateCallback(callback,
                ConcurrentUtils.DIRECT_EXECUTOR);

        verify(callback).onBaseStateChanged(eq(mService.getBaseState()));
        verify(callback).onStateChanged(eq(mService.getBaseState()));
        reset(callback);

        DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
        mDeviceStateManagerGlobal.requestBaseStateOverride(request, null /* executor */,
                null /* callback */);

        verify(callback).onBaseStateChanged(eq(OTHER_DEVICE_STATE));
        verify(callback).onStateChanged(eq(OTHER_DEVICE_STATE));
        assertEquals(OTHER_DEVICE_STATE, mService.getBaseState());
        reset(callback);

        DeviceStateRequest secondRequest = DeviceStateRequest.newBuilder(
                DEFAULT_DEVICE_STATE).build();

        mDeviceStateManagerGlobal.requestState(secondRequest, null, null);

        assertEquals(OTHER_DEVICE_STATE, mService.getBaseState());
        verify(callback).onStateChanged(eq(DEFAULT_DEVICE_STATE));
        reset(callback);

        mDeviceStateManagerGlobal.cancelStateRequest();

        verify(callback).onStateChanged(OTHER_DEVICE_STATE);
        reset(callback);

        mDeviceStateManagerGlobal.cancelBaseStateOverride();

        verify(callback).onBaseStateChanged(DEFAULT_DEVICE_STATE);
        verify(callback).onStateChanged(DEFAULT_DEVICE_STATE);
    }

    @Test
@@ -169,7 +223,7 @@ public final class DeviceStateManagerGlobalTest {
                callback /* callback */);

        verify(callback).onRequestActivated(eq(request));
        Mockito.reset(callback);
        reset(callback);

        mDeviceStateManagerGlobal.cancelStateRequest();

@@ -203,13 +257,16 @@ public final class DeviceStateManagerGlobalTest {
        private int[] mSupportedStates = new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
        private int mBaseState = DEFAULT_DEVICE_STATE;
        private Request mRequest;
        private Request mBaseStateRequest;

        private Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();

        private DeviceStateInfo getInfo() {
            final int mergedBaseState = mBaseStateRequest == null
                    ? mBaseState : mBaseStateRequest.state;
            final int mergedState = mRequest == null
                    ? mBaseState : mRequest.state;
            return new DeviceStateInfo(mSupportedStates, mBaseState, mergedState);
                    ? mergedBaseState : mRequest.state;
            return new DeviceStateInfo(mSupportedStates, mergedBaseState, mergedState);
        }

        private void notifyDeviceStateInfoChanged() {
@@ -238,7 +295,7 @@ public final class DeviceStateManagerGlobalTest {
            try {
                callback.onDeviceStateInfoChanged(getInfo());
            } catch (RemoteException e) {
                // Do nothing. Should never happen.
                e.rethrowFromSystemServer();
            }
        }

@@ -249,7 +306,7 @@ public final class DeviceStateManagerGlobalTest {
                    try {
                        callback.onRequestCanceled(mRequest.token);
                    } catch (RemoteException e) {
                        // Do nothing. Should never happen.
                        e.rethrowFromSystemServer();
                    }
                }
            }
@@ -262,7 +319,7 @@ public final class DeviceStateManagerGlobalTest {
                try {
                    callback.onRequestActive(token);
                } catch (RemoteException e) {
                    // Do nothing. Should never happen.
                    e.rethrowFromSystemServer();
                }
            }
        }
@@ -275,7 +332,46 @@ public final class DeviceStateManagerGlobalTest {
                try {
                    callback.onRequestCanceled(token);
                } catch (RemoteException e) {
                    // Do nothing. Should never happen.
                    e.rethrowFromSystemServer();
                }
            }
            notifyDeviceStateInfoChanged();
        }

        @Override
        public void requestBaseStateOverride(IBinder token, int state, int flags) {
            if (mBaseStateRequest != null) {
                for (IDeviceStateManagerCallback callback : mCallbacks) {
                    try {
                        callback.onRequestCanceled(mBaseStateRequest.token);
                    } catch (RemoteException e) {
                        e.rethrowFromSystemServer();
                    }
                }
            }

            final Request request = new Request(token, state, flags);
            mBaseStateRequest = request;
            notifyDeviceStateInfoChanged();

            for (IDeviceStateManagerCallback callback : mCallbacks) {
                try {
                    callback.onRequestActive(token);
                } catch (RemoteException e) {
                    e.rethrowFromSystemServer();
                }
            }
        }

        @Override
        public void cancelBaseStateOverride() throws RemoteException {
            IBinder token = mBaseStateRequest.token;
            mBaseStateRequest = null;
            for (IDeviceStateManagerCallback callback : mCallbacks) {
                try {
                    callback.onRequestCanceled(token);
                } catch (RemoteException e) {
                    e.rethrowFromSystemServer();
                }
            }
            notifyDeviceStateInfoChanged();
@@ -296,7 +392,7 @@ public final class DeviceStateManagerGlobalTest {
        }

        public int getBaseState() {
            return mBaseState;
            return getInfo().baseState;
        }

        public int getMergedState() {
Loading