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

Commit 85441622 authored by Chris Li's avatar Chris Li
Browse files

Add seq to relayout infos

Keep track of the seq of last reported window infos.

Bug: 339380439
Test: atest FrameworksCoreTests:SequenceUtilsTest
Flag: com.android.window.flags.insets_control_seq
Change-Id: I15cab03ac83ecad0ce4fee4334894a0f933c7366
parent 36276e8c
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.util;

/**
 * Utilities to manage an info change seq id to ensure the update is in sync between client and
 * system server. This should be used for info that can be updated though multiple IPC channel.
 *
 * To use it:
 * 1. The system server should store the current seq as the source of truth, with initializing to
 * {@link #getInitSeq}.
 * 2. Whenever a newer info needs to be sent to the client side, the system server should first
 * update its seq with {@link #getNextSeq}, then send the new info with the new seq to the client.
 * 3. On the client side, when receiving a new info, it should only consume it if it is newer than
 * the last received info seq by checking {@link #isIncomingSeqNewer}.
 *
 * @hide
 */
public final class SequenceUtils {

    private SequenceUtils() {
    }

    /**
     * Returns {@code true} if the incomingSeq is newer than the curSeq.
     */
    public static boolean isIncomingSeqNewer(int curSeq, int incomingSeq) {
        // Convert to long for comparison.
        final long diff = (long) incomingSeq - curSeq;
        // If there has been a sufficiently large jump, assume the sequence has wrapped around.
        // For example, when the last seq is MAX_VALUE, the incoming seq will be MIN_VALUE + 1.
        // diff = MIN_VALUE + 1 - MAX_VALUE. It is smaller than 0, but should be treated as newer.
        return diff > 0 || diff < Integer.MIN_VALUE;
    }

    /** Returns the initial seq. */
    public static int getInitSeq() {
        return Integer.MIN_VALUE;
    }

    /** Returns the next seq. */
    public static int getNextSeq(int seq) {
        return seq == Integer.MAX_VALUE
                // Skip the initial seq, so that when the app process is relaunched, the incoming
                // seq from the server is always treated as newer.
                ? getInitSeq() + 1
                : ++seq;
    }
}
+16 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view;

import static android.graphics.PointProto.X;
import static android.graphics.PointProto.Y;
import static android.util.SequenceUtils.getInitSeq;
import static android.view.InsetsSourceControlProto.LEASH;
import static android.view.InsetsSourceControlProto.POSITION;
import static android.view.InsetsSourceControlProto.TYPE_NUMBER;
@@ -266,6 +267,9 @@ public class InsetsSourceControl implements Parcelable {

        private @Nullable InsetsSourceControl[] mControls;

        /** To make sure the info update between client and system server is in order. */
        private int mSeq = getInitSeq();

        public Array() {
        }

@@ -280,9 +284,18 @@ public class InsetsSourceControl implements Parcelable {
            readFromParcel(in);
        }

        public int getSeq() {
            return mSeq;
        }

        public void setSeq(int seq) {
            mSeq = seq;
        }

        /** Updates the current Array to the given Array. */
        public void setTo(@NonNull Array other, boolean copyControls) {
            set(other.mControls, copyControls);
            mSeq = other.mSeq;
        }

        /** Updates the current controls to the given controls. */
@@ -336,11 +349,13 @@ public class InsetsSourceControl implements Parcelable {

        public void readFromParcel(Parcel in) {
            mControls = in.createTypedArray(InsetsSourceControl.CREATOR);
            mSeq = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            out.writeTypedArray(mControls, flags);
            out.writeInt(mSeq);
        }

        public static final @NonNull Creator<Array> CREATOR = new Creator<>() {
@@ -362,6 +377,7 @@ public class InsetsSourceControl implements Parcelable {
                return false;
            }
            final InsetsSourceControl.Array other = (InsetsSourceControl.Array) o;
            // mSeq is for internal bookkeeping only.
            return Arrays.equals(mControls, other.mControls);
        }

+17 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.view;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.util.SequenceUtils.getInitSeq;
import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
@@ -95,6 +96,9 @@ public class InsetsState implements Parcelable {
    /** The display shape */
    private DisplayShape mDisplayShape = DisplayShape.NONE;

    /** To make sure the info update between client and system server is in order. */
    private int mSeq = getInitSeq();

    public InsetsState() {
        mSources = new SparseArray<>();
    }
@@ -586,6 +590,14 @@ public class InsetsState implements Parcelable {
        }
    }

    public int getSeq() {
        return mSeq;
    }

    public void setSeq(int seq) {
        mSeq = seq;
    }

    public void set(InsetsState other) {
        set(other, false /* copySources */);
    }
@@ -597,6 +609,7 @@ public class InsetsState implements Parcelable {
        mRoundedCornerFrame.set(other.mRoundedCornerFrame);
        mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
        mDisplayShape = other.getDisplayShape();
        mSeq = other.mSeq;
        mSources.clear();
        for (int i = 0, size = other.mSources.size(); i < size; i++) {
            final InsetsSource otherSource = other.mSources.valueAt(i);
@@ -620,6 +633,7 @@ public class InsetsState implements Parcelable {
        mRoundedCornerFrame.set(other.mRoundedCornerFrame);
        mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
        mDisplayShape = other.getDisplayShape();
        mSeq = other.mSeq;
        if (types == 0) {
            return;
        }
@@ -705,6 +719,7 @@ public class InsetsState implements Parcelable {
                || !mRoundedCornerFrame.equals(state.mRoundedCornerFrame)
                || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)
                || !mDisplayShape.equals(state.mDisplayShape)) {
            // mSeq is for internal bookkeeping only.
            return false;
        }

@@ -778,6 +793,7 @@ public class InsetsState implements Parcelable {
        mRoundedCornerFrame.writeToParcel(dest, flags);
        dest.writeTypedObject(mPrivacyIndicatorBounds, flags);
        dest.writeTypedObject(mDisplayShape, flags);
        dest.writeInt(mSeq);
        final int size = mSources.size();
        dest.writeInt(size);
        for (int i = 0; i < size; i++) {
@@ -803,6 +819,7 @@ public class InsetsState implements Parcelable {
        mRoundedCornerFrame.readFromParcel(in);
        mPrivacyIndicatorBounds = in.readTypedObject(PrivacyIndicatorBounds.CREATOR);
        mDisplayShape = in.readTypedObject(DisplayShape.CREATOR);
        mSeq = in.readInt();
        final int size = in.readInt();
        final SparseArray<InsetsSource> sources;
        if (mSources == null) {
+9 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.window;

import static android.util.SequenceUtils.getInitSeq;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -53,6 +55,9 @@ public class ClientWindowFrames implements Parcelable {

    public float compatScale = 1f;

    /** To make sure the info update between client and system server is in order. */
    public int seq = getInitSeq();

    public ClientWindowFrames() {
    }

@@ -74,6 +79,7 @@ public class ClientWindowFrames implements Parcelable {
        }
        isParentFrameClippedByDisplayCutout = other.isParentFrameClippedByDisplayCutout;
        compatScale = other.compatScale;
        seq = other.seq;
    }

    /** Needed for AIDL out parameters. */
@@ -84,6 +90,7 @@ public class ClientWindowFrames implements Parcelable {
        attachedFrame = in.readTypedObject(Rect.CREATOR);
        isParentFrameClippedByDisplayCutout = in.readBoolean();
        compatScale = in.readFloat();
        seq = in.readInt();
    }

    @Override
@@ -94,6 +101,7 @@ public class ClientWindowFrames implements Parcelable {
        dest.writeTypedObject(attachedFrame, flags);
        dest.writeBoolean(isParentFrameClippedByDisplayCutout);
        dest.writeFloat(compatScale);
        dest.writeInt(seq);
    }

    @Override
@@ -116,6 +124,7 @@ public class ClientWindowFrames implements Parcelable {
            return false;
        }
        final ClientWindowFrames other = (ClientWindowFrames) o;
        // seq is for internal bookkeeping only.
        return frame.equals(other.frame)
                && displayFrame.equals(other.displayFrame)
                && parentFrame.equals(other.parentFrame)
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.util;


import static android.util.SequenceUtils.getInitSeq;
import static android.util.SequenceUtils.getNextSeq;
import static android.util.SequenceUtils.isIncomingSeqNewer;

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

import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.annotations.Presubmit;
import android.platform.test.ravenwood.RavenwoodRule;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Tests for subtypes of {@link SequenceUtils}.
 *
 * Build/Install/Run:
 *  atest FrameworksCoreTests:SequenceUtilsTest
 */
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
@DisabledOnRavenwood(blockedBy = SequenceUtils.class)
public class SequenceUtilsTest {

    // This is needed to disable the test in Ravenwood test, because SequenceUtils hasn't opted in
    // for Ravenwood, which is still in experiment.
    @Rule
    public final RavenwoodRule mRavenwood = new RavenwoodRule();

    @Test
    public void testNextSeq() {
        assertEquals(getInitSeq() + 1, getNextSeq(getInitSeq()));
        assertEquals(getInitSeq() + 1, getNextSeq(Integer.MAX_VALUE));
    }

    @Test
    public void testIsIncomingSeqNewer() {
        assertTrue(isIncomingSeqNewer(getInitSeq() + 1, getInitSeq() + 10));
        assertFalse(isIncomingSeqNewer(getInitSeq() + 10, getInitSeq() + 1));
        assertTrue(isIncomingSeqNewer(-100, 100));
        assertFalse(isIncomingSeqNewer(100, -100));
        assertTrue(isIncomingSeqNewer(1, 2));
        assertFalse(isIncomingSeqNewer(2, 1));

        // Possible incoming seq are all newer than the initial seq.
        assertTrue(isIncomingSeqNewer(getInitSeq(), getInitSeq() + 1));
        assertTrue(isIncomingSeqNewer(getInitSeq(), -100));
        assertTrue(isIncomingSeqNewer(getInitSeq(), 0));
        assertTrue(isIncomingSeqNewer(getInitSeq(), 100));
        assertTrue(isIncomingSeqNewer(getInitSeq(), Integer.MAX_VALUE));
        assertTrue(isIncomingSeqNewer(getInitSeq(), getNextSeq(Integer.MAX_VALUE)));

        // False for the same seq.
        assertFalse(isIncomingSeqNewer(getInitSeq(), getInitSeq()));
        assertFalse(isIncomingSeqNewer(100, 100));
        assertFalse(isIncomingSeqNewer(Integer.MAX_VALUE, Integer.MAX_VALUE));

        // True when there is a large jump (overflow).
        assertTrue(isIncomingSeqNewer(Integer.MAX_VALUE, getInitSeq() + 1));
        assertTrue(isIncomingSeqNewer(Integer.MAX_VALUE, getInitSeq() + 100));
        assertTrue(isIncomingSeqNewer(Integer.MAX_VALUE, getNextSeq(Integer.MAX_VALUE)));
    }
}
Loading