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 class RemoteAccessibilityController { 28 private static final String TAG = "RemoteAccessibilityController"; 29 private int mHostId; 30 private RemoteAccessibilityEmbeddedConnection mConnectionWrapper; 31 private Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix(); 32 private final float[] mMatrixValues = new float[9]; 33 private View mHostView; 34 RemoteAccessibilityController(View v)35 RemoteAccessibilityController(View v) { 36 mHostView = v; 37 } 38 runOnUiThread(Runnable runnable)39 private void runOnUiThread(Runnable runnable) { 40 final Handler h = mHostView.getHandler(); 41 if (h != null && h.getLooper() != Looper.myLooper()) { 42 h.post(runnable); 43 } else { 44 runnable.run(); 45 } 46 } 47 assosciateHierarchy(IAccessibilityEmbeddedConnection connection, IBinder leashToken, int hostId)48 void assosciateHierarchy(IAccessibilityEmbeddedConnection connection, 49 IBinder leashToken, int hostId) { 50 mHostId = hostId; 51 52 try { 53 leashToken = connection.associateEmbeddedHierarchy( 54 leashToken, mHostId); 55 setRemoteAccessibilityEmbeddedConnection(connection, leashToken); 56 } catch (RemoteException e) { 57 Log.d(TAG, "Error in associateEmbeddedHierarchy " + e); 58 } 59 } 60 disassosciateHierarchy()61 void disassosciateHierarchy() { 62 setRemoteAccessibilityEmbeddedConnection(null, null); 63 } 64 alreadyAssociated(IAccessibilityEmbeddedConnection connection)65 boolean alreadyAssociated(IAccessibilityEmbeddedConnection connection) { 66 if (mConnectionWrapper == null) { 67 return false; 68 } 69 return mConnectionWrapper.mConnection.equals(connection); 70 } 71 connected()72 boolean connected() { 73 return mConnectionWrapper != null; 74 } 75 getLeashToken()76 IBinder getLeashToken() { 77 return mConnectionWrapper.getLeashToken(); 78 } 79 80 /** 81 * Wrapper of accessibility embedded connection for embedded view hierarchy. 82 */ 83 private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient { 84 private final IAccessibilityEmbeddedConnection mConnection; 85 private final IBinder mLeashToken; 86 RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection, IBinder leashToken)87 RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection, 88 IBinder leashToken) { 89 mConnection = connection; 90 mLeashToken = leashToken; 91 } 92 getConnection()93 IAccessibilityEmbeddedConnection getConnection() { 94 return mConnection; 95 } 96 getLeashToken()97 IBinder getLeashToken() { 98 return mLeashToken; 99 } 100 linkToDeath()101 void linkToDeath() throws RemoteException { 102 mConnection.asBinder().linkToDeath(this, 0); 103 } 104 unlinkToDeath()105 void unlinkToDeath() { 106 mConnection.asBinder().unlinkToDeath(this, 0); 107 } 108 109 @Override binderDied()110 public void binderDied() { 111 unlinkToDeath(); 112 runOnUiThread(() -> { 113 if (mConnectionWrapper == this) { 114 mConnectionWrapper = null; 115 } 116 }); 117 } 118 } 119 setRemoteAccessibilityEmbeddedConnection( IAccessibilityEmbeddedConnection connection, IBinder leashToken)120 private void setRemoteAccessibilityEmbeddedConnection( 121 IAccessibilityEmbeddedConnection connection, IBinder leashToken) { 122 try { 123 if (mConnectionWrapper != null) { 124 mConnectionWrapper.getConnection() 125 .disassociateEmbeddedHierarchy(); 126 mConnectionWrapper.unlinkToDeath(); 127 mConnectionWrapper = null; 128 } 129 if (connection != null && leashToken != null) { 130 mConnectionWrapper = 131 new RemoteAccessibilityEmbeddedConnection(connection, leashToken); 132 mConnectionWrapper.linkToDeath(); 133 } 134 } catch (RemoteException e) { 135 Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e); 136 } 137 } 138 getRemoteAccessibilityEmbeddedConnection()139 private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() { 140 return mConnectionWrapper; 141 } 142 setScreenMatrix(Matrix m)143 void setScreenMatrix(Matrix m) { 144 // If the screen matrix is identity or doesn't change, do nothing. 145 if (m.isIdentity() || m.equals(mScreenMatrixForEmbeddedHierarchy)) { 146 return; 147 } 148 149 try { 150 final RemoteAccessibilityEmbeddedConnection wrapper = 151 getRemoteAccessibilityEmbeddedConnection(); 152 if (wrapper == null) { 153 return; 154 } 155 m.getValues(mMatrixValues); 156 wrapper.getConnection().setScreenMatrix(mMatrixValues); 157 mScreenMatrixForEmbeddedHierarchy.set(m); 158 } catch (RemoteException e) { 159 Log.d(TAG, "Error while setScreenMatrix " + e); 160 } 161 } 162 163 164 165 166 167 168 } 169