Improve the windows register and unregister mechanism am: 31eaf452ad

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14637424

Change-Id: If7b01817b2d76d2b7e4512278f853ba5875d3c4d
This commit is contained in:
Jacky Kao
2021-05-19 08:46:35 +00:00
committed by Automerger Merge Worker
4 changed files with 83 additions and 29 deletions

View File

@@ -373,6 +373,20 @@ public class AccessibilityWindowManager {
}
}
/**
* Called when the display is reparented and becomes an embedded
* display.
*
* @param embeddedDisplayId The embedded display Id.
*/
@Override
public void onDisplayReparented(int embeddedDisplayId) {
// Removes the un-used window observer for the embedded display.
synchronized (mLock) {
mDisplayWindowsObservers.remove(embeddedDisplayId);
}
}
private boolean shouldUpdateWindowsLocked(boolean forceSend,
@NonNull List<WindowInfo> windows) {
if (forceSend) {

View File

@@ -90,6 +90,7 @@ import android.view.animation.Interpolator;
import com.android.internal.R;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.TraceBuffer;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
@@ -172,11 +173,15 @@ final class AccessibilityController {
/**
* Sets a callback for observing which windows are touchable for the purposes
* of accessibility on specified display.
* of accessibility on specified display. When a display is reparented and becomes
* an embedded one, the {@link WindowsForAccessibilityCallback#onDisplayReparented(int)}
* will notify the accessibility framework to remove the un-used window observer of
* this embedded display.
*
* @param displayId The logical display id.
* @param callback The callback.
* @return {@code false} if display id is not valid or an embedded display.
* @return {@code false} if display id is not valid or an embedded display when the callback
* isn't null.
*/
boolean setWindowsForAccessibilityCallback(int displayId,
WindowsForAccessibilityCallback callback) {
@@ -185,12 +190,13 @@ final class AccessibilityController {
TAG + ".setWindowsForAccessibilityCallback",
"displayId=" + displayId + "; callback={" + callback + "}");
}
final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
if (dc == null) {
return false;
}
if (callback != null) {
final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
if (dc == null) {
return false;
}
WindowsForAccessibilityObserver observer =
mWindowsForAccessibilityObserver.get(displayId);
if (isEmbeddedDisplay(dc)) {
@@ -209,21 +215,13 @@ final class AccessibilityController {
if (Build.IS_DEBUGGABLE) {
throw new IllegalStateException(errorMessage);
}
removeObserverOfEmbeddedDisplay(observer);
removeObserversForEmbeddedChildDisplays(observer);
mWindowsForAccessibilityObserver.remove(displayId);
}
observer = new WindowsForAccessibilityObserver(mService, displayId, callback);
mWindowsForAccessibilityObserver.put(displayId, observer);
mAllObserversInitialized &= observer.mInitialized;
} else {
if (isEmbeddedDisplay(dc)) {
// If this display is an embedded one, its window observer should be removed along
// with the window observer of its parent display removed because the window
// observer of the embedded display and its parent display is the same, and would
// be removed together when stopping the window tracking of its parent display. So
// here don't need to do removing window observer of the embedded display again.
return true;
}
final WindowsForAccessibilityObserver windowsForA11yObserver =
mWindowsForAccessibilityObserver.get(displayId);
if (windowsForA11yObserver == null) {
@@ -234,7 +232,7 @@ final class AccessibilityController {
throw new IllegalStateException(errorMessage);
}
}
removeObserverOfEmbeddedDisplay(windowsForA11yObserver);
removeObserversForEmbeddedChildDisplays(windowsForA11yObserver);
mWindowsForAccessibilityObserver.remove(displayId);
}
return true;
@@ -507,22 +505,34 @@ final class AccessibilityController {
if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
return;
}
// Finds the parent display of this embedded display
final int parentDisplayId;
WindowState candidate = parentWindow;
while (candidate != null) {
parentWindow = candidate;
candidate = parentWindow.getDisplayContent().getParentWindow();
mService.mH.sendMessage(PooledLambda.obtainMessage(
AccessibilityController::updateWindowObserverOfEmbeddedDisplay,
this, embeddedDisplayId, parentWindow));
}
private void updateWindowObserverOfEmbeddedDisplay(int embeddedDisplayId,
WindowState parentWindow) {
final WindowsForAccessibilityObserver windowsForA11yObserver;
synchronized (mService.mGlobalLock) {
// Finds the parent display of this embedded display
WindowState candidate = parentWindow;
while (candidate != null) {
parentWindow = candidate;
candidate = parentWindow.getDisplayContent().getParentWindow();
}
final int parentDisplayId = parentWindow.getDisplayId();
// Uses the observer of parent display
windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId);
}
parentDisplayId = parentWindow.getDisplayId();
// Uses the observer of parent display
final WindowsForAccessibilityObserver windowsForA11yObserver =
mWindowsForAccessibilityObserver.get(parentDisplayId);
if (windowsForA11yObserver != null) {
windowsForA11yObserver.notifyDisplayReparented(embeddedDisplayId);
windowsForA11yObserver.addEmbeddedDisplay(embeddedDisplayId);
// Replaces the observer of embedded display to the one of parent display
mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
synchronized (mService.mGlobalLock) {
// Replaces the observer of embedded display to the one of parent display
mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
}
}
}
@@ -555,7 +565,7 @@ final class AccessibilityController {
+ "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver);
}
private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver
private void removeObserversForEmbeddedChildDisplays(WindowsForAccessibilityObserver
observerOfParentDisplay) {
final IntArray embeddedDisplayIdList =
observerOfParentDisplay.getAndClearEmbeddedDisplayIdList();
@@ -1541,6 +1551,13 @@ final class AccessibilityController {
mEmbeddedDisplayIdList.add(displayId);
}
void notifyDisplayReparented(int embeddedDisplayId) {
// Notifies the A11y framework the display is reparented and
// becomes an embedded display for removing the un-used
// displayWindowObserver of this embedded one.
mCallback.onDisplayReparented(embeddedDisplayId);
}
/**
* Check if windows have changed, and send them to the accessibility subsystem if they have.
*

View File

@@ -115,6 +115,16 @@ public abstract class WindowManagerInternal {
*/
void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows);
/**
* Called when the display is reparented and becomes an embedded
* display. The {@link WindowsForAccessibilityCallback} with the given embedded
* display will be replaced by the {@link WindowsForAccessibilityCallback}
* associated with its parent display at the same time.
*
* @param embeddedDisplayId The embedded display Id.
*/
void onDisplayReparented(int embeddedDisplayId);
}
/**

View File

@@ -834,6 +834,19 @@ public class AccessibilityWindowManagerTest {
assertNull(token);
}
@Test
public void onDisplayReparented_shouldRemoveObserver() throws RemoteException {
// Starts tracking window of second display.
startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
// Notifies the second display is an embedded one of the default display.
final WindowsForAccessibilityCallback callbacks =
mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
callbacks.onDisplayReparented(SECONDARY_DISPLAY_ID);
// Makes sure the observer of the second display is removed.
assertFalse(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
}
private void registerLeashedTokenAndWindowId() {
mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);