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

Commit 4e2e8a3e authored by Jackal Guo's avatar Jackal Guo Committed by Android (Google) Code Review
Browse files

Merge "Support accessibility on embedded hierarchies (3/n)"

parents 45c350c0 ac234d66
Loading
Loading
Loading
Loading
+22 −4
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.view.accessibility.IAccessibilityEmbeddedConnection;


/**
/**
 * Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
 * Utility class for adding a View hierarchy to a {@link SurfaceControl}. The View hierarchy
@@ -40,6 +41,7 @@ public class SurfaceControlViewHost {
    private WindowlessWindowManager mWm;
    private WindowlessWindowManager mWm;


    private SurfaceControl mSurfaceControl;
    private SurfaceControl mSurfaceControl;
    private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;


    /**
    /**
     * Package encapsulating a Surface hierarchy which contains interactive view
     * Package encapsulating a Surface hierarchy which contains interactive view
@@ -49,15 +51,18 @@ public class SurfaceControlViewHost {
     */
     */
    public static final class SurfacePackage implements Parcelable {
    public static final class SurfacePackage implements Parcelable {
        private final SurfaceControl mSurfaceControl;
        private final SurfaceControl mSurfaceControl;
        // TODO: Accessibility ID goes here
        private final IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;


        SurfacePackage(SurfaceControl sc) {
        SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection) {
            mSurfaceControl = sc;
            mSurfaceControl = sc;
            mAccessibilityEmbeddedConnection = connection;
        }
        }


        private SurfacePackage(Parcel in) {
        private SurfacePackage(Parcel in) {
            mSurfaceControl = new SurfaceControl();
            mSurfaceControl = new SurfaceControl();
            mSurfaceControl.readFromParcel(in);
            mSurfaceControl.readFromParcel(in);
            mAccessibilityEmbeddedConnection = IAccessibilityEmbeddedConnection.Stub.asInterface(
                    in.readStrongBinder());
        }
        }


        /**
        /**
@@ -69,6 +74,16 @@ public class SurfaceControlViewHost {
            return mSurfaceControl;
            return mSurfaceControl;
        }
        }


        /**
         * Gets an accessibility embedded connection interface for this SurfaceControlViewHost.
         *
         * @return {@link IAccessibilityEmbeddedConnection} interface.
         * @hide
         */
        public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
            return mAccessibilityEmbeddedConnection;
        }

        @Override
        @Override
        public int describeContents() {
        public int describeContents() {
            return 0;
            return 0;
@@ -77,6 +92,7 @@ public class SurfaceControlViewHost {
        @Override
        @Override
        public void writeToParcel(@NonNull Parcel out, int flags) {
        public void writeToParcel(@NonNull Parcel out, int flags) {
            mSurfaceControl.writeToParcel(out, flags);
            mSurfaceControl.writeToParcel(out, flags);
            out.writeStrongBinder(mAccessibilityEmbeddedConnection.asBinder());
        }
        }


        public static final @NonNull Creator<SurfacePackage> CREATOR
        public static final @NonNull Creator<SurfacePackage> CREATOR
@@ -95,6 +111,7 @@ public class SurfaceControlViewHost {
            @NonNull WindowlessWindowManager wwm) {
            @NonNull WindowlessWindowManager wwm) {
        mWm = wwm;
        mWm = wwm;
        mViewRoot = new ViewRootImpl(c, d, mWm);
        mViewRoot = new ViewRootImpl(c, d, mWm);
        mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
    }
    }


    /**
    /**
@@ -118,6 +135,7 @@ public class SurfaceControlViewHost {
        mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
        mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
                mSurfaceControl, hostToken);
                mSurfaceControl, hostToken);
        mViewRoot = new ViewRootImpl(context, display, mWm);
        mViewRoot = new ViewRootImpl(context, display, mWm);
        mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
    }
    }


    /**
    /**
@@ -128,8 +146,8 @@ public class SurfaceControlViewHost {
     * are linked.
     * are linked.
     */
     */
    public @Nullable SurfacePackage getSurfacePackage() {
    public @Nullable SurfacePackage getSurfacePackage() {
        if (mSurfaceControl != null) {
        if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
            return new SurfacePackage(mSurfaceControl);
            return new SurfacePackage(mSurfaceControl, mAccessibilityEmbeddedConnection);
        } else {
        } else {
            return null;
            return null;
        }
        }
+127 −16
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.res.CompatibilityInfo.Translator;
import android.graphics.BlendMode;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff;
@@ -38,12 +39,14 @@ import android.os.Build;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Log;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceControlViewHost;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IAccessibilityEmbeddedConnection;


import com.android.internal.view.SurfaceCallbackHelper;
import com.android.internal.view.SurfaceCallbackHelper;


@@ -203,8 +206,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
    private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
    private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
    private int mParentSurfaceGenerationId;
    private int mParentSurfaceGenerationId;


    // The token of embedded windowless view hierarchy.
    private RemoteAccessibilityEmbeddedConnection mRemoteAccessibilityEmbeddedConnection;
    private IBinder mEmbeddedViewHierarchy;

    private final Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
    private final Matrix mTmpMatrix = new Matrix();
    private final float[] mMatrixValues = new float[9];

    SurfaceControlViewHost.SurfacePackage mSurfacePackage;
    SurfaceControlViewHost.SurfacePackage mSurfacePackage;


    public SurfaceView(Context context) {
    public SurfaceView(Context context) {
@@ -923,6 +930,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                    }
                    }


                    mTmpTransaction.apply();
                    mTmpTransaction.apply();
                    updateScreenMatrixForEmbeddedHierarchy();


                    if (sizeChanged || creating) {
                    if (sizeChanged || creating) {
                        redrawNeeded = true;
                        redrawNeeded = true;
@@ -1510,6 +1518,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
    @Override
    @Override
    public void surfaceDestroyed() {
    public void surfaceDestroyed() {
        setWindowStopped(true);
        setWindowStopped(true);
        setRemoteAccessibilityEmbeddedConnection(null, null);
    }
    }


    /**
    /**
@@ -1568,31 +1577,133 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall


    private void reparentSurfacePackage(SurfaceControl.Transaction t,
    private void reparentSurfacePackage(SurfaceControl.Transaction t,
            SurfaceControlViewHost.SurfacePackage p) {
            SurfaceControlViewHost.SurfacePackage p) {
        // TODO: Link accessibility IDs here.
        initEmbeddedHierarchyForAccessibility(p);
        final SurfaceControl sc = p.getSurfaceControl();
        final SurfaceControl sc = p.getSurfaceControl();
        t.reparent(sc, mSurfaceControl).show(sc);
        t.reparent(sc, mSurfaceControl).show(sc);
    }
    }


    /**
     * Add the token of embedded view hierarchy. Set {@code null} to clear the embedded view
     * hierarchy.
     *
     * @param token IBinder token.
     * @hide
     */
    public void setEmbeddedViewHierarchy(IBinder token) {
        mEmbeddedViewHierarchy = token;
    }

    /** @hide */
    /** @hide */
    @Override
    @Override
    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfoInternal(info);
        super.onInitializeAccessibilityNodeInfoInternal(info);
        if (mEmbeddedViewHierarchy == null) {
        final RemoteAccessibilityEmbeddedConnection wrapper =
                getRemoteAccessibilityEmbeddedConnection();
        if (wrapper == null) {
            return;
            return;
        }
        }
        // Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
        // Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
        // leashed child would return the root node in the embedded hierarchy
        // leashed child would return the root node in the embedded hierarchy
        info.addChild(mEmbeddedViewHierarchy);
        info.addChild(wrapper.getLeashToken());
    }

    private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
        final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
        final RemoteAccessibilityEmbeddedConnection wrapper =
                getRemoteAccessibilityEmbeddedConnection();

        // Do nothing if package is embedding the same view hierarchy.
        if (wrapper != null && wrapper.getConnection().equals(connection)) {
            return;
        }

        // If this SurfaceView embeds a different view hierarchy, unlink the previous one first.
        setRemoteAccessibilityEmbeddedConnection(null, null);

        try {
            final IBinder leashToken = connection.associateEmbeddedHierarchy(
                    getViewRootImpl().mLeashToken, getAccessibilityViewId());
            setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
        } catch (RemoteException e) {
            Log.d(TAG, "Error while associateEmbeddedHierarchy " + e);
        }
        updateScreenMatrixForEmbeddedHierarchy();
    }

    private void setRemoteAccessibilityEmbeddedConnection(
            IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
        try {
            if (mRemoteAccessibilityEmbeddedConnection != null) {
                mRemoteAccessibilityEmbeddedConnection.getConnection()
                        .disassociateEmbeddedHierarchy();
                mRemoteAccessibilityEmbeddedConnection.unlinkToDeath();
                mRemoteAccessibilityEmbeddedConnection = null;
            }
            if (connection != null && leashToken != null) {
                mRemoteAccessibilityEmbeddedConnection =
                        new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
                mRemoteAccessibilityEmbeddedConnection.linkToDeath();
            }
        } catch (RemoteException e) {
            Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
        }
    }

    private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
        return mRemoteAccessibilityEmbeddedConnection;
    }

    private void updateScreenMatrixForEmbeddedHierarchy() {
        mTmpMatrix.reset();
        mTmpMatrix.setTranslate(mScreenRect.left, mScreenRect.top);
        mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
                mScreenRect.height() / (float) mSurfaceHeight);

        // If the screen matrix is identity or doesn't change, do nothing.
        if (mTmpMatrix.isIdentity() || mTmpMatrix.equals(mScreenMatrixForEmbeddedHierarchy)) {
            return;
        }

        try {
            final RemoteAccessibilityEmbeddedConnection wrapper =
                    getRemoteAccessibilityEmbeddedConnection();
            if (wrapper == null) {
                return;
            }
            mTmpMatrix.getValues(mMatrixValues);
            wrapper.getConnection().setScreenMatrix(mMatrixValues);
            mScreenMatrixForEmbeddedHierarchy.set(mTmpMatrix);
        } catch (RemoteException e) {
            Log.d(TAG, "Error while setScreenMatrix " + e);
        }
    }

    /**
     * Wrapper of accessibility embedded connection for embedded view hierarchy.
     */
    private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
        private final IAccessibilityEmbeddedConnection mConnection;
        private final IBinder mLeashToken;

        RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
                IBinder leashToken) {
            mConnection = connection;
            mLeashToken = leashToken;
        }

        IAccessibilityEmbeddedConnection getConnection() {
            return mConnection;
        }

        IBinder getLeashToken() {
            return mLeashToken;
        }

        void linkToDeath() throws RemoteException {
            mConnection.asBinder().linkToDeath(this, 0);
        }

        void unlinkToDeath() {
            mConnection.asBinder().unlinkToDeath(this, 0);
        }

        @Override
        public void binderDied() {
            unlinkToDeath();
            runOnUiThread(() -> {
                if (mRemoteAccessibilityEmbeddedConnection == this) {
                    mRemoteAccessibilityEmbeddedConnection = null;
                }
            });
        }
    }
    }
}
}
+6 −5
Original line number Original line Diff line number Diff line
@@ -655,7 +655,7 @@ public final class ViewRootImpl implements ViewParent,


    private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();
    private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker();


    private IAccessibilityEmbeddedConnection mEmbeddedConnection;
    private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;


    static final class SystemUiVisibilityInfo {
    static final class SystemUiVisibilityInfo {
        int seq;
        int seq;
@@ -9370,11 +9370,12 @@ public final class ViewRootImpl implements ViewParent,
     * Gets an accessibility embedded connection interface for this ViewRootImpl.
     * Gets an accessibility embedded connection interface for this ViewRootImpl.
     * @hide
     * @hide
     */
     */
    public IAccessibilityEmbeddedConnection getEmbeddedConnection() {
    public IAccessibilityEmbeddedConnection getAccessibilityEmbeddedConnection() {
        if (mEmbeddedConnection == null) {
        if (mAccessibilityEmbeddedConnection == null) {
            mEmbeddedConnection = new AccessibilityEmbeddedConnection(ViewRootImpl.this);
            mAccessibilityEmbeddedConnection = new AccessibilityEmbeddedConnection(
                    ViewRootImpl.this);
        }
        }
        return mEmbeddedConnection;
        return mAccessibilityEmbeddedConnection;
    }
    }


    private class SendWindowContentChangedAccessibilityEvent implements Runnable {
    private class SendWindowContentChangedAccessibilityEvent implements Runnable {