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

Commit 9b348ee2 authored by Eric Lin's avatar Eric Lin Committed by Android (Google) Code Review
Browse files

Merge "Refactor DeviceStateManager service and tests." into main

parents b02f8680 bc9aec40
Loading
Loading
Loading
Loading
+32 −23
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.Executor;


/**
 * Information about the state of the device.
 *
@@ -63,11 +62,13 @@ public final class DeviceStateInfo implements Parcelable {
     * ignoring any override requests made through a call to {@link DeviceStateManager#requestState(
     * DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
     */
    @NonNull
    public final DeviceState baseState;

    /**
     * The state of the device.
     */
    @NonNull
    public final DeviceState currentState;

    /**
@@ -78,8 +79,9 @@ public final class DeviceStateInfo implements Parcelable {
     */
    // Using the specific types to avoid virtual method calls in binder transactions
    @SuppressWarnings("NonApiType")
    public DeviceStateInfo(@NonNull ArrayList<DeviceState> supportedStates, DeviceState baseState,
            DeviceState state) {
    public DeviceStateInfo(@NonNull ArrayList<DeviceState> supportedStates,
            @NonNull DeviceState baseState,
            @NonNull DeviceState state) {
        this.supportedStates = supportedStates;
        this.baseState = baseState;
        this.currentState = state;
@@ -97,7 +99,7 @@ public final class DeviceStateInfo implements Parcelable {
    public boolean equals(@Nullable Object other) {
        if (this == other) return true;
        if (other == null || (getClass() != other.getClass())) return false;
        DeviceStateInfo that = (DeviceStateInfo) other;
        final DeviceStateInfo that = (DeviceStateInfo) other;
        return baseState.equals(that.baseState)
                &&  currentState.equals(that.currentState)
                && Objects.equals(supportedStates, that.supportedStates);
@@ -126,8 +128,16 @@ public final class DeviceStateInfo implements Parcelable {
        return diff;
    }

    // Parcelable implementation

    @Override
    public int describeContents() {
        return 0;
    }

    /** Writes to Parcel. */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(supportedStates.size());
        for (int i = 0; i < supportedStates.size(); i++) {
            dest.writeTypedObject(supportedStates.get(i).getConfiguration(), flags);
@@ -137,28 +147,27 @@ public final class DeviceStateInfo implements Parcelable {
        dest.writeTypedObject(currentState.getConfiguration(), flags);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<>() {
        @Override
        public DeviceStateInfo createFromParcel(Parcel source) {
            final int numberOfSupportedStates = source.readInt();
    /** Reads from Parcel. */
    private DeviceStateInfo(@NonNull Parcel in) {
        final int numberOfSupportedStates = in.readInt();
        final ArrayList<DeviceState> supportedStates = new ArrayList<>(numberOfSupportedStates);
        for (int i = 0; i < numberOfSupportedStates; i++) {
                DeviceState.Configuration configuration = source.readTypedObject(
                        DeviceState.Configuration.CREATOR);
            final DeviceState.Configuration configuration =
                    Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR));
            supportedStates.add(i, new DeviceState(configuration));
        }
        this.supportedStates = supportedStates;

            final DeviceState baseState = new DeviceState(
                    source.readTypedObject(DeviceState.Configuration.CREATOR));
            final DeviceState currentState = new DeviceState(
                    source.readTypedObject(DeviceState.Configuration.CREATOR));
        this.baseState = new DeviceState(
                Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR)));
        this.currentState = new DeviceState(
                Objects.requireNonNull(in.readTypedObject(DeviceState.Configuration.CREATOR)));
    }

            return new DeviceStateInfo(supportedStates, baseState, currentState);
    public static final @NonNull Creator<DeviceStateInfo> CREATOR = new Creator<>() {
        @Override
        public DeviceStateInfo createFromParcel(@NonNull Parcel in) {
            return new DeviceStateInfo(in);
        }

        @Override
+37 −29
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import java.util.concurrent.Executor;
 */
@VisibleForTesting(visibility = Visibility.PACKAGE)
public final class DeviceStateManagerGlobal {
    @Nullable
    private static DeviceStateManagerGlobal sInstance;
    private static final String TAG = "DeviceStateManagerGlobal";
    private static final boolean DEBUG = Build.IS_DEBUGGABLE;
@@ -58,7 +59,7 @@ public final class DeviceStateManagerGlobal {
    public static DeviceStateManagerGlobal getInstance() {
        synchronized (DeviceStateManagerGlobal.class) {
            if (sInstance == null) {
                IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
                final IBinder b = ServiceManager.getService(Context.DEVICE_STATE_SERVICE);
                if (b != null) {
                    sInstance = new DeviceStateManagerGlobal(IDeviceStateManager
                            .Stub.asInterface(b));
@@ -94,6 +95,7 @@ public final class DeviceStateManagerGlobal {
     *
     * @see DeviceStateManager#getSupportedDeviceStates()
     */
    @NonNull
    public List<DeviceState> getSupportedDeviceStates() {
        synchronized (mLock) {
            final DeviceStateInfo currentInfo;
@@ -126,8 +128,8 @@ public final class DeviceStateManagerGlobal {
            conditional = true)
    public void requestState(@NonNull DeviceStateRequest request,
            @Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) {
        DeviceStateRequestWrapper requestWrapper = new DeviceStateRequestWrapper(request, callback,
                executor);
        final DeviceStateRequestWrapper requestWrapper =
                new DeviceStateRequestWrapper(request, callback, executor);
        synchronized (mLock) {
            if (findRequestTokenLocked(request) != null) {
                // This request has already been submitted.
@@ -136,7 +138,7 @@ public final class DeviceStateManagerGlobal {
            // 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();
            final IBinder token = new Binder();
            mRequests.put(token, requestWrapper);

            try {
@@ -176,8 +178,8 @@ public final class DeviceStateManagerGlobal {
    @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);
        final DeviceStateRequestWrapper requestWrapper =
                new DeviceStateRequestWrapper(request, callback, executor);
        synchronized (mLock) {
            if (findRequestTokenLocked(request) != null) {
                // This request has already been submitted.
@@ -186,7 +188,7 @@ public final class DeviceStateManagerGlobal {
            // 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();
            final IBinder token = new Binder();
            mRequests.put(token, requestWrapper);

            try {
@@ -225,7 +227,7 @@ public final class DeviceStateManagerGlobal {
    public void registerDeviceStateCallback(@NonNull DeviceStateCallback callback,
            @NonNull Executor executor) {
        synchronized (mLock) {
            int index = findCallbackLocked(callback);
            final int index = findCallbackLocked(callback);
            if (index != -1) {
                // This callback is already registered.
                return;
@@ -233,7 +235,8 @@ public final class DeviceStateManagerGlobal {
            // 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.
            DeviceStateCallbackWrapper wrapper = new DeviceStateCallbackWrapper(callback, executor);
            final DeviceStateCallbackWrapper wrapper =
                    new DeviceStateCallbackWrapper(callback, executor);
            mCallbacks.add(wrapper);

            if (mLastReceivedInfo != null) {
@@ -253,7 +256,7 @@ public final class DeviceStateManagerGlobal {
    @VisibleForTesting(visibility = Visibility.PACKAGE)
    public void unregisterDeviceStateCallback(@NonNull DeviceStateCallback callback) {
        synchronized (mLock) {
            int indexToRemove = findCallbackLocked(callback);
            final int indexToRemove = findCallbackLocked(callback);
            if (indexToRemove != -1) {
                mCallbacks.remove(indexToRemove);
            }
@@ -277,7 +280,10 @@ public final class DeviceStateManagerGlobal {
    }

    private void registerCallbackIfNeededLocked() {
        if (mCallback == null) {
        if (mCallback != null) {
            return;
        }

        mCallback = new DeviceStateManagerCallback();
        try {
            mDeviceStateManager.registerCallback(mCallback);
@@ -286,7 +292,6 @@ public final class DeviceStateManagerGlobal {
            throw ex.rethrowFromSystemServer();
        }
    }
    }

    private int findCallbackLocked(DeviceStateCallback callback) {
        for (int i = 0; i < mCallbacks.size(); i++) {
@@ -298,6 +303,7 @@ public final class DeviceStateManagerGlobal {
    }

    @Nullable
    @GuardedBy("mLock")
    private IBinder findRequestTokenLocked(@NonNull DeviceStateRequest request) {
        for (int i = 0; i < mRequests.size(); i++) {
            if (mRequests.valueAt(i).mRequest.equals(request)) {
@@ -309,8 +315,8 @@ public final class DeviceStateManagerGlobal {

    /** Handles a call from the server that the device state info has changed. */
    private void handleDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
        ArrayList<DeviceStateCallbackWrapper> callbacks;
        DeviceStateInfo oldInfo;
        final ArrayList<DeviceStateCallbackWrapper> callbacks;
        final DeviceStateInfo oldInfo;
        synchronized (mLock) {
            oldInfo = mLastReceivedInfo;
            mLastReceivedInfo = info;
@@ -335,8 +341,8 @@ public final class DeviceStateManagerGlobal {
     * Handles a call from the server that a request for the supplied {@code token} has become
     * active.
     */
    private void handleRequestActive(IBinder token) {
        DeviceStateRequestWrapper request;
    private void handleRequestActive(@NonNull IBinder token) {
        final DeviceStateRequestWrapper request;
        synchronized (mLock) {
            request = mRequests.get(token);
        }
@@ -349,8 +355,8 @@ public final class DeviceStateManagerGlobal {
     * Handles a call from the server that a request for the supplied {@code token} has become
     * canceled.
     */
    private void handleRequestCanceled(IBinder token) {
        DeviceStateRequestWrapper request;
    private void handleRequestCanceled(@NonNull IBinder token) {
        final DeviceStateRequestWrapper request;
        synchronized (mLock) {
            request = mRequests.remove(token);
        }
@@ -361,17 +367,17 @@ public final class DeviceStateManagerGlobal {

    private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
        @Override
        public void onDeviceStateInfoChanged(DeviceStateInfo info) {
        public void onDeviceStateInfoChanged(@NonNull DeviceStateInfo info) {
            handleDeviceStateInfoChanged(info);
        }

        @Override
        public void onRequestActive(IBinder token) {
        public void onRequestActive(@NonNull IBinder token) {
            handleRequestActive(token);
        }

        @Override
        public void onRequestCanceled(IBinder token) {
        public void onRequestCanceled(@NonNull IBinder token) {
            handleRequestCanceled(token);
        }
    }
@@ -388,7 +394,8 @@ public final class DeviceStateManagerGlobal {
            mExecutor = executor;
        }

        void notifySupportedDeviceStatesChanged(List<DeviceState> newSupportedDeviceStates) {
        void notifySupportedDeviceStatesChanged(
                @NonNull List<DeviceState> newSupportedDeviceStates) {
            mExecutor.execute(() ->
                    mDeviceStateCallback.onSupportedStatesChanged(newSupportedDeviceStates));
        }
@@ -398,7 +405,7 @@ public final class DeviceStateManagerGlobal {
                    () -> mDeviceStateCallback.onDeviceStateChanged(newDeviceState));
        }

        private void execute(String traceName, Runnable r) {
        private void execute(@NonNull String traceName, @NonNull Runnable r) {
            mExecutor.execute(() -> {
                if (DEBUG) {
                    Trace.beginSection(
@@ -416,6 +423,7 @@ public final class DeviceStateManagerGlobal {
    }

    private static final class DeviceStateRequestWrapper {
        @NonNull
        private final DeviceStateRequest mRequest;
        @Nullable
        private final DeviceStateRequest.Callback mCallback;
+2 −1
Original line number Diff line number Diff line
@@ -26,11 +26,12 @@ android_test {
    // Include all test java files
    srcs: ["src/**/*.java"],
    static_libs: [
        "androidx.test.ext.junit",
        "androidx.test.rules",
        "frameworks-base-testutils",
        "mockito-target-minus-junit4",
        "platform-test-annotations",
        "testng",
        "truth",
    ],
    libs: ["android.test.runner.stubs.system"],
    platform_apis: true,
+66 −47
Original line number Diff line number Diff line
@@ -22,21 +22,15 @@ import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWAR
import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN;
import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static com.google.common.truth.Truth.assertThat;

import android.os.Parcel;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.ArrayList;
import java.util.List;
@@ -44,13 +38,13 @@ import java.util.Set;

/**
 * Unit tests for {@link DeviceStateInfo}.
 * <p/>
 * Run with <code>atest DeviceStateInfoTest</code>.
 *
 * <p> Build/Install/Run:
 * atest FrameworksCoreDeviceStateManagerTests:DeviceStateInfoTest
 */
@RunWith(JUnit4.class)
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class DeviceStateInfoTest {

    private static final DeviceState DEVICE_STATE_0 = new DeviceState(
            new DeviceState.Configuration.Builder(0, "STATE_0")
                    .setSystemProperties(
@@ -74,88 +68,113 @@ public final class DeviceStateInfoTest {

    @Test
    public void create() {
        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final ArrayList<DeviceState> supportedStates =
                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final DeviceState baseState = DEVICE_STATE_0;
        final DeviceState currentState = DEVICE_STATE_2;

        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
        assertNotNull(info.supportedStates);
        assertEquals(supportedStates, info.supportedStates);
        assertEquals(baseState, info.baseState);
        assertEquals(currentState, info.currentState);
        final DeviceStateInfo info =
                new DeviceStateInfo(supportedStates, baseState, currentState);

        assertThat(info.supportedStates).containsExactlyElementsIn(supportedStates).inOrder();
        assertThat(info.baseState).isEqualTo(baseState);
        assertThat(info.currentState).isEqualTo(currentState);
    }

    @Test
    public void equals() {
        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final ArrayList<DeviceState> supportedStates =
                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final DeviceState baseState = DEVICE_STATE_0;
        final DeviceState currentState = DEVICE_STATE_2;

        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
        Assert.assertEquals(info, info);
        final DeviceStateInfo sameInstance = info;
        assertThat(info).isEqualTo(sameInstance);

        final DeviceStateInfo sameInfo = new DeviceStateInfo(supportedStates, baseState,
                currentState);
        Assert.assertEquals(info, sameInfo);
        final DeviceStateInfo sameInfo =
                new DeviceStateInfo(supportedStates, baseState, currentState);
        assertThat(info).isEqualTo(sameInfo);

        final DeviceStateInfo copiedInfo = new DeviceStateInfo(info);
        assertThat(info).isEqualTo(copiedInfo);

        final DeviceStateInfo differentInfo = new DeviceStateInfo(
                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_2)), baseState, currentState);
        assertNotEquals(info, differentInfo);
        assertThat(differentInfo).isNotEqualTo(info);
    }

    @Test
    public void hashCode_sameObject() {
        final ArrayList<DeviceState> supportedStates =
                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final DeviceState baseState = DEVICE_STATE_0;
        final DeviceState currentState = DEVICE_STATE_2;
        final DeviceStateInfo info =
                new DeviceStateInfo(supportedStates, baseState, currentState);
        final DeviceStateInfo copiedInfo = new DeviceStateInfo(info);

        assertThat(info.hashCode()).isEqualTo(copiedInfo.hashCode());
    }

    @Test
    public void diff_sameObject() {
        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final ArrayList<DeviceState> supportedStates =
                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final DeviceState baseState = DEVICE_STATE_0;
        final DeviceState currentState = DEVICE_STATE_2;

        final DeviceStateInfo info = new DeviceStateInfo(supportedStates, baseState, currentState);
        assertEquals(0, info.diff(info));

        assertThat(info.diff(info)).isEqualTo(0);
    }

    @Test
    public void diff_differentSupportedStates() {
        final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
                DEVICE_STATE_0, DEVICE_STATE_0);
        final DeviceStateInfo info = new DeviceStateInfo(
                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_0);
        final DeviceStateInfo otherInfo = new DeviceStateInfo(
                new ArrayList<>(List.of(DEVICE_STATE_2)), DEVICE_STATE_0, DEVICE_STATE_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);

        assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isGreaterThan(0);
        assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isEqualTo(0);
        assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isEqualTo(0);
    }

    @Test
    public void diff_differentNonOverrideState() {
        final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
                DEVICE_STATE_1, DEVICE_STATE_0);
        final DeviceStateInfo info = new DeviceStateInfo(
                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_1, DEVICE_STATE_0);
        final DeviceStateInfo otherInfo = new DeviceStateInfo(
                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_2, DEVICE_STATE_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);

        assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isEqualTo(0);
        assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isGreaterThan(0);
        assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isEqualTo(0);
    }

    @Test
    public void diff_differentState() {
        final DeviceStateInfo info = new DeviceStateInfo(new ArrayList<>(List.of(DEVICE_STATE_1)),
                DEVICE_STATE_0, DEVICE_STATE_1);
        final DeviceStateInfo info = new DeviceStateInfo(
                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_1);
        final DeviceStateInfo otherInfo = new DeviceStateInfo(
                new ArrayList<>(List.of(DEVICE_STATE_1)), DEVICE_STATE_0, DEVICE_STATE_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);

        assertThat(diff & DeviceStateInfo.CHANGED_SUPPORTED_STATES).isEqualTo(0);
        assertThat(diff & DeviceStateInfo.CHANGED_BASE_STATE).isEqualTo(0);
        assertThat(diff & DeviceStateInfo.CHANGED_CURRENT_STATE).isGreaterThan(0);
    }

    @Test
    public void writeToParcel() {
        final ArrayList<DeviceState> supportedStates = new ArrayList<>(
                List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final ArrayList<DeviceState> supportedStates =
                new ArrayList<>(List.of(DEVICE_STATE_0, DEVICE_STATE_1, DEVICE_STATE_2));
        final DeviceState nonOverrideState = DEVICE_STATE_0;
        final DeviceState state = DEVICE_STATE_2;
        final DeviceStateInfo originalInfo =
@@ -166,6 +185,6 @@ public final class DeviceStateInfoTest {
        parcel.setDataPosition(0);

        final DeviceStateInfo info = DeviceStateInfo.CREATOR.createFromParcel(parcel);
        assertEquals(originalInfo, info);
        assertThat(info).isEqualTo(originalInfo);
    }
}
+78 −68

File changed.

Preview size limit exceeded, changes collapsed.

Loading