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

Commit ae00abf8 authored by Rob Carr's avatar Rob Carr Committed by Android (Google) Code Review
Browse files

Merge changes I0333ab33,I7ae7b27f,If20185ce

* changes:
  SurfaceView Cleanup (3/n): Extract RemoteAccessibilityController
  SurfaceView Cleanup (2/n): Cleanup visible = mVisible
  SurfaceView Cleanup (1/n): Breakup updateSurface()
parents 25993ef6 60370aad
Loading
Loading
Loading
Loading
+168 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.view;

import android.graphics.Matrix;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.IAccessibilityEmbeddedConnection;

class RemoteAccessibilityController {
    private static final String TAG = "RemoteAccessibilityController";
    private int mHostId;
    private RemoteAccessibilityEmbeddedConnection mConnectionWrapper;
    private Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
    private final float[] mMatrixValues = new float[9];
    private View mHostView;

    RemoteAccessibilityController(View v) {
        mHostView = v;
    }

    private void runOnUiThread(Runnable runnable) {
        final Handler h = mHostView.getHandler();
        if (h != null && h.getLooper() != Looper.myLooper()) {
            h.post(runnable);
        } else {
            runnable.run();
        }
    }

    void assosciateHierarchy(IAccessibilityEmbeddedConnection connection,
        IBinder leashToken, int hostId) {
        mHostId = hostId;

        try {
            leashToken = connection.associateEmbeddedHierarchy(
                leashToken, mHostId);
            setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
        } catch (RemoteException e) {
            Log.d(TAG, "Error in associateEmbeddedHierarchy " + e);
        }
    }

    void disassosciateHierarchy() {
        setRemoteAccessibilityEmbeddedConnection(null, null);
    }

    boolean alreadyAssociated(IAccessibilityEmbeddedConnection connection) {
        if (mConnectionWrapper == null) {
            return false;
        }
        return mConnectionWrapper.mConnection.equals(connection);
    }

    boolean connected() {
      return mConnectionWrapper != null;
    }

    IBinder getLeashToken() {
        return mConnectionWrapper.getLeashToken();
    }

    /**
     * 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 (mConnectionWrapper == this) {
                    mConnectionWrapper = null;
                }
            });
        }
    }

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

    private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
        return mConnectionWrapper;
    }

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

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






}
+130 −217
Original line number Diff line number Diff line
@@ -227,9 +227,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
    private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
    private int mParentSurfaceGenerationId;

    private RemoteAccessibilityEmbeddedConnection mRemoteAccessibilityEmbeddedConnection;
    private RemoteAccessibilityController mRemoteAccessibilityController =
        new RemoteAccessibilityController(this);

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

@@ -927,98 +927,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
        }
    }

    /** @hide */
    protected void updateSurface() {
        if (!mHaveFrame) {
            if (DEBUG) {
                Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
            }
            return;
        }
        final ViewRootImpl viewRoot = getViewRootImpl();

        if (viewRoot == null) {
            return;
        }

        if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
            notifySurfaceDestroyed();
            tryReleaseSurfaces();
            return;
        }

        final Translator translator = viewRoot.mTranslator;
        if (translator != null) {
            mSurface.setCompatibilityTranslator(translator);
        }

        int myWidth = mRequestedWidth;
        if (myWidth <= 0) myWidth = getWidth();
        int myHeight = mRequestedHeight;
        if (myHeight <= 0) myHeight = getHeight();

        final float alpha = getFixedAlpha();
        final boolean formatChanged = mFormat != mRequestedFormat;
        final boolean visibleChanged = mVisible != mRequestedVisible;
        final boolean alphaChanged = mSurfaceAlpha != alpha;
        final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
                && mRequestedVisible;
        final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
        final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
        boolean redrawNeeded = false;
        getLocationInSurface(mLocation);
        final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
            || mWindowSpaceTop != mLocation[1];
        final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
            || getHeight() != mScreenRect.height();


        if (creating || formatChanged || sizeChanged || visibleChanged ||
                (mUseAlpha && alphaChanged) || windowVisibleChanged ||
                positionChanged || layoutSizeChanged) {
            getLocationInWindow(mLocation);

            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
                    + "Changes: creating=" + creating
                    + " format=" + formatChanged + " size=" + sizeChanged
                    + " visible=" + visibleChanged + " alpha=" + alphaChanged
                    + " mUseAlpha=" + mUseAlpha
                    + " visible=" + visibleChanged
                    + " left=" + (mWindowSpaceLeft != mLocation[0])
                    + " top=" + (mWindowSpaceTop != mLocation[1]));

            try {
                final boolean visible = mVisible = mRequestedVisible;
                mWindowSpaceLeft = mLocation[0];
                mWindowSpaceTop = mLocation[1];
                mSurfaceWidth = myWidth;
                mSurfaceHeight = myHeight;
                mFormat = mRequestedFormat;
                mLastWindowVisibility = mWindowVisibility;

                mScreenRect.left = mWindowSpaceLeft;
                mScreenRect.top = mWindowSpaceTop;
                mScreenRect.right = mWindowSpaceLeft + getWidth();
                mScreenRect.bottom = mWindowSpaceTop + getHeight();
                if (translator != null) {
                    translator.translateRectInAppWindowToScreen(mScreenRect);
                }

                final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
                mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);

                if (creating) {
                    updateOpaqueFlag();
                    mDeferredDestroySurfaceControl = createSurfaceControls(viewRoot);
                } else if (mSurfaceControl == null) {
                    return;
                }

    private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
        boolean creating, boolean sizeChanged, boolean needBLASTSync) {
        boolean realSizeChanged = false;

        mSurfaceLock.lock();
        try {
                    mDrawingStopped = !visible;
            mDrawingStopped = !mVisible;

            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
                    + "Cur surface: " + mSurface);
@@ -1047,6 +962,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
            updateBackgroundVisibility(mTmpTransaction);
            updateBackgroundColor(mTmpTransaction);
            if (mUseAlpha) {
                float alpha = getFixedAlpha();
                mTmpTransaction.setAlpha(mSurfaceControl, alpha);
                mSurfaceAlpha = alpha;
            }
@@ -1076,8 +992,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                    mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
                            mSurfaceHeight);
                }
                    } else if ((layoutSizeChanged || positionChanged || visibleChanged) &&
                            viewRoot.useBLAST()) {
            } else if (needBLASTSync) {
                viewRoot.setUseBLASTSyncTransaction();
            }
            mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
@@ -1086,11 +1001,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
            }

            mTmpTransaction.apply();
                    updateScreenMatrixForEmbeddedHierarchy();

                    if (sizeChanged || creating) {
                        redrawNeeded = true;
                    }
            updateEmbeddedAccessibilityMatrix();

            mSurfaceFrame.left = 0;
            mSurfaceFrame.top = 0;
@@ -1102,7 +1013,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
                mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
            }

            final int surfaceWidth = mSurfaceFrame.right;
            final int surfaceHeight = mSurfaceFrame.bottom;
            realSizeChanged = mLastSurfaceWidth != surfaceWidth
@@ -1112,21 +1022,115 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
        } finally {
            mSurfaceLock.unlock();
        }
        return realSizeChanged;
    }

    /** @hide */
    protected void updateSurface() {
        if (!mHaveFrame) {
            if (DEBUG) {
                Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
            }
            return;
        }
        final ViewRootImpl viewRoot = getViewRootImpl();

        if (viewRoot == null) {
            return;
        }

        if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
            notifySurfaceDestroyed();
            tryReleaseSurfaces();
            return;
        }

        final Translator translator = viewRoot.mTranslator;
        if (translator != null) {
            mSurface.setCompatibilityTranslator(translator);
        }

        int myWidth = mRequestedWidth;
        if (myWidth <= 0) myWidth = getWidth();
        int myHeight = mRequestedHeight;
        if (myHeight <= 0) myHeight = getHeight();

        final float alpha = getFixedAlpha();
        final boolean formatChanged = mFormat != mRequestedFormat;
        final boolean visibleChanged = mVisible != mRequestedVisible;
        final boolean alphaChanged = mSurfaceAlpha != alpha;
        final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
                && mRequestedVisible;
        final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
        final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
        getLocationInSurface(mLocation);
        final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
            || mWindowSpaceTop != mLocation[1];
        final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
            || getHeight() != mScreenRect.height();


        if (creating || formatChanged || sizeChanged || visibleChanged ||
                (mUseAlpha && alphaChanged) || windowVisibleChanged ||
                positionChanged || layoutSizeChanged) {
            getLocationInWindow(mLocation);

            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
                    + "Changes: creating=" + creating
                    + " format=" + formatChanged + " size=" + sizeChanged
                    + " visible=" + visibleChanged + " alpha=" + alphaChanged
                    + " mUseAlpha=" + mUseAlpha
                    + " visible=" + visibleChanged
                    + " left=" + (mWindowSpaceLeft != mLocation[0])
                    + " top=" + (mWindowSpaceTop != mLocation[1]));

            try {
                    redrawNeeded |= visible && !mDrawFinished;
                mVisible = mRequestedVisible;
                mWindowSpaceLeft = mLocation[0];
                mWindowSpaceTop = mLocation[1];
                mSurfaceWidth = myWidth;
                mSurfaceHeight = myHeight;
                mFormat = mRequestedFormat;
                mLastWindowVisibility = mWindowVisibility;

                mScreenRect.left = mWindowSpaceLeft;
                mScreenRect.top = mWindowSpaceTop;
                mScreenRect.right = mWindowSpaceLeft + getWidth();
                mScreenRect.bottom = mWindowSpaceTop + getHeight();
                if (translator != null) {
                    translator.translateRectInAppWindowToScreen(mScreenRect);
                }

                final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
                mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);

                if (creating) {
                    updateOpaqueFlag();
                    mDeferredDestroySurfaceControl = createSurfaceControls(viewRoot);
                } else if (mSurfaceControl == null) {
                    return;
                }

                final boolean needBLASTSync =
                    (layoutSizeChanged || positionChanged || visibleChanged) &&
                        viewRoot.useBLAST();
                final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
                    translator, creating, sizeChanged, needBLASTSync);
                final boolean redrawNeeded = sizeChanged || creating ||
                    (mVisible && !mDrawFinished);

                try {
                    SurfaceHolder.Callback[] callbacks = null;

                    final boolean surfaceChanged = creating;
                    if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
                    if (mSurfaceCreated && (surfaceChanged || (!mVisible && visibleChanged))) {
                        mSurfaceCreated = false;
                        notifySurfaceDestroyed();
                    }

                    copySurface(creating /* surfaceControlCreated */, sizeChanged);

                    if (visible && mSurface.isValid()) {
                    if (mVisible && mSurface.isValid()) {
                        if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
                            mSurfaceCreated = true;
                            mIsCreating = true;
@@ -1754,7 +1758,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
    @Override
    public void surfaceDestroyed() {
        setWindowStopped(true);
        setRemoteAccessibilityEmbeddedConnection(null, null);
        mRemoteAccessibilityController.disassosciateHierarchy();
    }

    /**
@@ -1834,14 +1838,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
    @Override
    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfoInternal(info);
        final RemoteAccessibilityEmbeddedConnection wrapper =
                getRemoteAccessibilityEmbeddedConnection();
        if (wrapper == null) {
        if (!mRemoteAccessibilityController.connected()) {
            return;
        }
        // Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
        // leashed child would return the root node in the embedded hierarchy
        info.addChild(wrapper.getLeashToken());
        info.addChild(mRemoteAccessibilityController.getLeashToken());
    }

    @Override
@@ -1850,7 +1852,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
        // If developers explicitly set the important mode for it, don't change the mode.
        // Only change the mode to important when this SurfaceView isn't explicitly set and has
        // an embedded hierarchy.
        if (mRemoteAccessibilityEmbeddedConnection == null
        if (!mRemoteAccessibilityController.connected()
                || mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
            return mode;
        }
@@ -1859,74 +1861,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall

    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)) {
        if (mRemoteAccessibilityController.alreadyAssociated(connection)) {
            return;
        }

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

        try {
            final IBinder leashToken = connection.associateEmbeddedHierarchy(
        mRemoteAccessibilityController.assosciateHierarchy(connection,
            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() {
        getBoundsOnScreen(mTmpRect);
        mTmpMatrix.reset();
        mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.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);
        }
        updateEmbeddedAccessibilityMatrix();
    }

    private void notifySurfaceDestroyed() {
@@ -1954,6 +1895,18 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
        }
    }

    void updateEmbeddedAccessibilityMatrix() {
        if (!mRemoteAccessibilityController.connected()) {
            return;
        }
        getBoundsOnScreen(mTmpRect);
        mTmpMatrix.reset();
        mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
        mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
                mScreenRect.height() / (float) mSurfaceHeight);
        mRemoteAccessibilityController.setScreenMatrix(mTmpMatrix);
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
                                  @Nullable Rect previouslyFocusedRect) {
@@ -1970,44 +1923,4 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                    + "Exception requesting focus on embedded window", 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;
                }
            });
        }
    }
}