Fix AccessibilityService#getWindows time out
In our design, we computes the windows for each display. Ideally the window list is initialized when the window observer is created.However, if the top focus window is null, the window list won't beupdated unless there is the windows change on that display. In general case, most of non-default displays don't have windows, so their window list won't be initialized. It affects that the callee needs to wait 5 seconds for time out mechanism. To fix it, we collects the window observers that don't receive the callback when it is constructed. Then sending the callback to them when the window foucs is available next time. Bug: 169542227 Test: manually check if windows reports correctly. Change-Id: I1a3dc780de5873062b220bd1588c855138aa3657
This commit is contained in:
@@ -69,6 +69,7 @@ import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallba
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -92,6 +93,9 @@ final class AccessibilityController {
|
||||
private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
|
||||
new SparseArray<>();
|
||||
|
||||
// Set to true if initializing window population complete.
|
||||
private boolean mAllObserversInitialized = true;
|
||||
|
||||
public boolean setMagnificationCallbacksLocked(int displayId,
|
||||
MagnificationCallbacks callbacks) {
|
||||
boolean result = false;
|
||||
@@ -110,7 +114,7 @@ final class AccessibilityController {
|
||||
}
|
||||
} else {
|
||||
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
|
||||
if (displayMagnifier == null) {
|
||||
if (displayMagnifier == null) {
|
||||
throw new IllegalStateException("Magnification callbacks already cleared!");
|
||||
}
|
||||
displayMagnifier.destroyLocked();
|
||||
@@ -150,8 +154,10 @@ final class AccessibilityController {
|
||||
"Windows for accessibility callback of display "
|
||||
+ displayId + " already set!");
|
||||
}
|
||||
mWindowsForAccessibilityObserver.put(displayId,
|
||||
new WindowsForAccessibilityObserver(mService, displayId, callback));
|
||||
final WindowsForAccessibilityObserver 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
|
||||
@@ -275,6 +281,41 @@ final class AccessibilityController {
|
||||
if (observer != null) {
|
||||
observer.performComputeChangedWindowsNotLocked(false);
|
||||
}
|
||||
// Since we abandon initializing observers if no window has focus, make sure all observers
|
||||
// are initialized.
|
||||
sendCallbackToUninitializedObserversIfNeeded();
|
||||
}
|
||||
|
||||
private void sendCallbackToUninitializedObserversIfNeeded() {
|
||||
List<WindowsForAccessibilityObserver> unInitializedObservers;
|
||||
synchronized (mService.mGlobalLock) {
|
||||
if (mAllObserversInitialized) {
|
||||
return;
|
||||
}
|
||||
if (mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus == null) {
|
||||
return;
|
||||
}
|
||||
unInitializedObservers = new ArrayList<>();
|
||||
for (int i = mWindowsForAccessibilityObserver.size() - 1; i >= 0; --i) {
|
||||
final WindowsForAccessibilityObserver observer =
|
||||
mWindowsForAccessibilityObserver.valueAt(i);
|
||||
if (!observer.mInitialized) {
|
||||
unInitializedObservers.add(observer);
|
||||
}
|
||||
}
|
||||
// Reset the flag to record the new added observer.
|
||||
mAllObserversInitialized = true;
|
||||
}
|
||||
|
||||
boolean areAllObserversInitialized = true;
|
||||
for (int i = unInitializedObservers.size() - 1; i >= 0; --i) {
|
||||
final WindowsForAccessibilityObserver observer = unInitializedObservers.get(i);
|
||||
observer.performComputeChangedWindowsNotLocked(true);
|
||||
areAllObserversInitialized &= observer.mInitialized;
|
||||
}
|
||||
synchronized (mService.mGlobalLock) {
|
||||
mAllObserversInitialized &= areAllObserversInitialized;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,6 +402,8 @@ final class AccessibilityController {
|
||||
+ "Magnification display# " + mDisplayMagnifiers.keyAt(i));
|
||||
}
|
||||
}
|
||||
pw.println(prefix
|
||||
+ "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver);
|
||||
}
|
||||
|
||||
private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver
|
||||
@@ -1214,6 +1257,9 @@ final class AccessibilityController {
|
||||
|
||||
private final IntArray mEmbeddedDisplayIdList = new IntArray(0);
|
||||
|
||||
// Set to true if initializing window population complete.
|
||||
private boolean mInitialized;
|
||||
|
||||
public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
|
||||
int displayId,
|
||||
WindowsForAccessibilityCallback callback) {
|
||||
@@ -1272,10 +1318,17 @@ final class AccessibilityController {
|
||||
// the window manager is still looking for where to put it.
|
||||
// We will do the work when we get a focus change callback.
|
||||
final WindowState topFocusedWindowState = getTopFocusWindow();
|
||||
if (topFocusedWindowState == null) return;
|
||||
if (topFocusedWindowState == null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(LOG_TAG, "top focused window is null, compute it again later");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
|
||||
if (dc == null) {
|
||||
//It should not happen because it is created while adding the callback.
|
||||
Slog.w(LOG_TAG, "display content is null, should be created later");
|
||||
return;
|
||||
}
|
||||
final Display display = dc.getDisplay();
|
||||
@@ -1362,6 +1415,7 @@ final class AccessibilityController {
|
||||
|
||||
// Recycle the windows as we do not need them.
|
||||
clearAndRecycleWindows(windows);
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
private boolean windowMattersToAccessibility(WindowState windowState,
|
||||
@@ -1547,6 +1601,16 @@ final class AccessibilityController {
|
||||
return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WindowsForAccessibilityObserver{"
|
||||
+ "mDisplayId=" + mDisplayId
|
||||
+ ", mEmbeddedDisplayIdList="
|
||||
+ Arrays.toString(mEmbeddedDisplayIdList.toArray())
|
||||
+ ", mInitialized=" + mInitialized
|
||||
+ '}';
|
||||
}
|
||||
|
||||
private class MyHandler extends Handler {
|
||||
public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user