1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 19 import android.graphics.Matrix; 20 import android.os.Handler; 21 import android.os.IBinder; 22 import android.os.Looper; 23 import android.os.RemoteException; 24 import android.util.Log; 25 import android.view.accessibility.IAccessibilityEmbeddedConnection; 26 27 import java.lang.ref.WeakReference; 28 29 class RemoteAccessibilityController { 30 private static final String TAG = "RemoteAccessibilityController"; 31 private int mHostId; 32 private RemoteAccessibilityEmbeddedConnection mConnectionWrapper; 33 private Matrix mWindowMatrixForEmbeddedHierarchy = new Matrix(); 34 private final float[] mMatrixValues = new float[9]; 35 private View mHostView; 36 RemoteAccessibilityController(View v)37 RemoteAccessibilityController(View v) { 38 mHostView = v; 39 } 40 runOnUiThread(Runnable runnable)41 private void runOnUiThread(Runnable runnable) { 42 final Handler h = mHostView.getHandler(); 43 if (h != null && h.getLooper() != Looper.myLooper()) { 44 h.post(runnable); 45 } else { 46 runnable.run(); 47 } 48 } 49 assosciateHierarchy(IAccessibilityEmbeddedConnection connection, IBinder leashToken, int hostId)50 void assosciateHierarchy(IAccessibilityEmbeddedConnection connection, 51 IBinder leashToken, int hostId) { 52 mHostId = hostId; 53 54 try { 55 leashToken = connection.associateEmbeddedHierarchy( 56 leashToken, mHostId); 57 setRemoteAccessibilityEmbeddedConnection(connection, leashToken); 58 } catch (RemoteException e) { 59 Log.d(TAG, "Error in associateEmbeddedHierarchy " + e); 60 } 61 } 62 disassosciateHierarchy()63 void disassosciateHierarchy() { 64 setRemoteAccessibilityEmbeddedConnection(null, null); 65 } 66 alreadyAssociated(IAccessibilityEmbeddedConnection connection)67 boolean alreadyAssociated(IAccessibilityEmbeddedConnection connection) { 68 if (mConnectionWrapper == null) { 69 return false; 70 } 71 return mConnectionWrapper.mConnection.equals(connection); 72 } 73 connected()74 boolean connected() { 75 return mConnectionWrapper != null; 76 } 77 getLeashToken()78 IBinder getLeashToken() { 79 return mConnectionWrapper.getLeashToken(); 80 } 81 82 /** 83 * Wrapper of accessibility embedded connection for embedded view hierarchy. 84 */ 85 private static final class RemoteAccessibilityEmbeddedConnection 86 implements IBinder.DeathRecipient { 87 private final WeakReference<RemoteAccessibilityController> mController; 88 private final IAccessibilityEmbeddedConnection mConnection; 89 private final IBinder mLeashToken; 90 RemoteAccessibilityEmbeddedConnection( RemoteAccessibilityController controller, IAccessibilityEmbeddedConnection connection, IBinder leashToken)91 RemoteAccessibilityEmbeddedConnection( 92 RemoteAccessibilityController controller, 93 IAccessibilityEmbeddedConnection connection, 94 IBinder leashToken) { 95 mController = new WeakReference<>(controller); 96 mConnection = connection; 97 mLeashToken = leashToken; 98 } 99 getConnection()100 IAccessibilityEmbeddedConnection getConnection() { 101 return mConnection; 102 } 103 getLeashToken()104 IBinder getLeashToken() { 105 return mLeashToken; 106 } 107 linkToDeath()108 void linkToDeath() throws RemoteException { 109 mConnection.asBinder().linkToDeath(this, 0); 110 } 111 unlinkToDeath()112 void unlinkToDeath() { 113 mConnection.asBinder().unlinkToDeath(this, 0); 114 } 115 116 @Override binderDied()117 public void binderDied() { 118 unlinkToDeath(); 119 RemoteAccessibilityController controller = mController.get(); 120 if (controller == null) { 121 return; 122 } 123 controller.runOnUiThread(() -> { 124 if (controller.mConnectionWrapper == this) { 125 controller.mConnectionWrapper = null; 126 } 127 }); 128 } 129 } 130 setRemoteAccessibilityEmbeddedConnection( IAccessibilityEmbeddedConnection connection, IBinder leashToken)131 private void setRemoteAccessibilityEmbeddedConnection( 132 IAccessibilityEmbeddedConnection connection, IBinder leashToken) { 133 try { 134 if (mConnectionWrapper != null) { 135 mConnectionWrapper.getConnection() 136 .disassociateEmbeddedHierarchy(); 137 mConnectionWrapper.unlinkToDeath(); 138 mConnectionWrapper = null; 139 } 140 if (connection != null && leashToken != null) { 141 mConnectionWrapper = 142 new RemoteAccessibilityEmbeddedConnection(this, connection, leashToken); 143 mConnectionWrapper.linkToDeath(); 144 } 145 } catch (RemoteException e) { 146 Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e); 147 } 148 } 149 getRemoteAccessibilityEmbeddedConnection()150 private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() { 151 return mConnectionWrapper; 152 } 153 setWindowMatrix(Matrix m, boolean force)154 void setWindowMatrix(Matrix m, boolean force) { 155 // If the window matrix doesn't change, do nothing. 156 if (!force && m.equals(mWindowMatrixForEmbeddedHierarchy)) { 157 return; 158 } 159 160 try { 161 final RemoteAccessibilityEmbeddedConnection wrapper = 162 getRemoteAccessibilityEmbeddedConnection(); 163 if (wrapper == null) { 164 return; 165 } 166 m.getValues(mMatrixValues); 167 wrapper.getConnection().setWindowMatrix(mMatrixValues); 168 mWindowMatrixForEmbeddedHierarchy.set(m); 169 } catch (RemoteException e) { 170 Log.d(TAG, "Error while setScreenMatrix " + e); 171 } 172 } 173 174 175 176 177 178 179 } 180