From 7570cac60e36a8b4c49e7932a41a9cb9214f1cf3 Mon Sep 17 00:00:00 2001 From: lumark Date: Thu, 7 Mar 2019 22:14:38 +0800 Subject: [PATCH] Propogate per-display IME status to SysUI CL [1] introduced SystemUI to support updating IME window status per display. (i.e. IStatusBarService#setImeWindowStatus left TODO item to add displayId parameter to select the target display.) For IMMS, we applied this API base on current token's displayId, and refined the code flow in Sysui to reset IME window state for non-target display's NavBar when single IME switch to another display case. And make sure some cases in IMMS should reset IME window status: - When current method unbind. - When current top window focus display is not same as current token's display. (That means the input session may connected but IME window not yet attached. Note that it doesn't include external display without system decoration and show IME window on default display case since it is intentional behavior and we still need to update status for this case.) Also added testSetImeWindowStatusWhenImeSwitchOnDisplay in NavigationBarFragmentTest to enhance the ability of verifying external navigation bar. [1]: 24e7a9fdb51978a47ce29f3816338da04a49d6ca Bug: 127309955 Bug: 117478341 Test: atest NavigationBarFragmentTest Test: manual as below steps: - Pre-condition: 1. Enable desktop mode. 2. Create simulated display. - Use case 1): 1. Launch an activity with input field on simulated display. 2. Bring up the IME there, expect back key icon on external NavBar will changed when IME bring up. 3. Tap on primary display or launch an activity there. (or pressing home key) 4. Expect IME will hide & back key icon on external NavBar will set back. - Use case 2): 1. Launch activity with input field on default display. 2. Tapping EditText in activity on default display. 3. Expect IME will bring up here and back key icon on default display will changed when IME bring up. 4. Launch activity without input field in external display. (i.e. clock app) 5. Expect Both Default & external display's nav bar back key icon will set back. Change-Id: Ia414b8aea631e295cccd6f6da44d04bad16545c7 --- .../internal/statusbar/IStatusBarService.aidl | 3 +- .../systemui/statusbar/CommandQueue.java | 42 ++++- .../phone/NavigationBarFragment.java | 5 + .../phone/NavigationBarFragmentTest.java | 170 +++++++++++++++++- .../InputMethodManagerService.java | 36 +++- .../statusbar/StatusBarManagerService.java | 14 +- .../server/wm/WindowManagerInternal.java | 5 + .../server/wm/WindowManagerService.java | 7 + .../src/android/testing/BaseFragmentTest.java | 2 +- 9 files changed, 254 insertions(+), 30 deletions(-) diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 5fee2c9bbdd38..8f8e4d8dc1087 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -48,8 +48,7 @@ interface IStatusBarService void setIconVisibility(String slot, boolean visible); @UnsupportedAppUsage void removeIcon(String slot); - // TODO(b/117478341): support back button change when IME is showing on a external display. - void setImeWindowStatus(in IBinder token, int vis, int backDisposition, + void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition, boolean showImeSwitcher); void expandSettingsPanel(String subPanel); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 2f99cf311eec5..d5849598342fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -18,7 +18,10 @@ package com.android.systemui.statusbar; import static android.app.StatusBarManager.DISABLE2_NONE; import static android.app.StatusBarManager.DISABLE_NONE; +import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; +import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS; @@ -40,6 +43,7 @@ import android.os.Looper; import android.os.Message; import android.util.Pair; import android.util.SparseArray; +import android.view.inputmethod.InputMethodSystemProperty; import androidx.annotation.VisibleForTesting; @@ -127,6 +131,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private Handler mHandler = new H(Looper.getMainLooper()); /** A map of display id - disable flag pair */ private SparseArray> mDisplayDisabled = new SparseArray<>(); + /** + * The last ID of the display where IME window for which we received setImeWindowStatus + * event. + */ + private int mLastUpdatedImeDisplayId = INVALID_DISPLAY; /** * These methods are called back on the main thread. @@ -785,6 +794,32 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } + private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition, + boolean showImeSwitcher) { + if (displayId == INVALID_DISPLAY) return; + + if (!InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED + && mLastUpdatedImeDisplayId != displayId + && mLastUpdatedImeDisplayId != INVALID_DISPLAY) { + // Set previous NavBar's IME window status as invisible when IME + // window switched to another display for single-session IME case. + sendImeInvisibleStatusForPrevNavBar(); + } + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setImeWindowStatus(displayId, token, vis, backDisposition, + showImeSwitcher); + } + mLastUpdatedImeDisplayId = displayId; + } + + private void sendImeInvisibleStatusForPrevNavBar() { + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).setImeWindowStatus(mLastUpdatedImeDisplayId, + null /* token */, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, + false /* showImeSwitcher */); + } + } + private final class H extends Handler { private H(Looper l) { super(l); @@ -852,10 +887,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< break; case MSG_SHOW_IME_BUTTON: args = (SomeArgs) msg.obj; - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).setImeWindowStatus(args.argi1, (IBinder) args.arg1, - args.argi2, args.argi3, args.argi4 != 0 /* showImeSwitcher */); - } + handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */, + args.argi2 /* vis */, args.argi3 /* backDisposition */, + args.argi4 != 0 /* showImeSwitcher */); break; case MSG_SHOW_RECENT_APPS: for (int i = 0; i < mCallbacks.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 591b1b48ddc28..083b3dfb9b652 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -1064,4 +1064,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback context.getSystemService(WindowManager.class).addView(navigationBarView, lp); return navigationBarView; } + + @VisibleForTesting + int getNavigationIconHints() { + return mNavigationIconHints; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index 6a0d61dc13c97..3ae57e391005b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -14,18 +14,38 @@ package com.android.systemui.statusbar.phone; +import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; +import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; +import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; +import static android.inputmethodservice.InputMethodService.IME_VISIBLE; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.annotation.LayoutRes; +import android.annotation.Nullable; import android.app.Fragment; +import android.app.FragmentController; +import android.app.FragmentHostCallback; import android.content.Context; +import android.hardware.display.DisplayManagerGlobal; import android.os.Bundle; +import android.os.Handler; import android.os.Looper; import android.testing.AndroidTestingRunner; import android.testing.LeakCheck.Tracker; +import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.Display; +import android.view.DisplayInfo; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; @@ -34,6 +54,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.systemui.Dependency; import com.android.systemui.SysuiBaseFragmentTest; +import com.android.systemui.SysuiTestableContext; import com.android.systemui.assist.AssistManager; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; @@ -50,9 +71,16 @@ import org.junit.runner.RunWith; @RunWithLooper() @SmallTest public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { + private static final int EXTERNAL_DISPLAY_ID = 2; + private static final int NAV_BAR_VIEW_ID = 43; + private Fragment mFragmentExternalDisplay; + private FragmentController mControllerExternalDisplay; + + private SysuiTestableContext mSysuiTestableContextExternal; private OverviewProxyService mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class); + private CommandQueue mCommandQueue; private AccessibilityManagerWrapper mAccessibilityWrapper = new AccessibilityManagerWrapper(mContext) { Tracker mTracker = mLeakCheck.getTracker("accessibility_manager"); @@ -73,15 +101,51 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { } protected void createRootView() { - mView = new NavigationBarFrame(mContext); + mView = new NavigationBarFrame(mSysuiContext); + mView.setId(NAV_BAR_VIEW_ID); } @Before - public void setup() { - mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class)); + public void setupFragment() throws Exception { + setupSysuiDependency(); + createRootView(); + TestableLooper.get(this).runWithLooper(() -> { + mHandler = new Handler(); + + mFragment = instantiate(mSysuiContext, NavigationBarFragment.class.getName(), null); + mFragments = FragmentController.createController( + new HostCallbacksForExternalDisplay(mSysuiContext)); + mFragments.attachHost(null); + mFragments.getFragmentManager().beginTransaction() + .replace(NAV_BAR_VIEW_ID, mFragment) + .commit(); + mControllerExternalDisplay = FragmentController.createController( + new HostCallbacksForExternalDisplay(mSysuiTestableContextExternal)); + mControllerExternalDisplay.attachHost(null); + mFragmentExternalDisplay = instantiate(mSysuiTestableContextExternal, + NavigationBarFragment.class.getName(), null); + mControllerExternalDisplay.getFragmentManager().beginTransaction() + .replace(NAV_BAR_VIEW_ID, mFragmentExternalDisplay) + .commit(); + }); + } + + private void setupSysuiDependency() { + mCommandQueue = new CommandQueue(mContext); + mSysuiContext.putComponent(CommandQueue.class, mCommandQueue); mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class)); mSysuiContext.putComponent(Recents.class, mock(Recents.class)); mSysuiContext.putComponent(Divider.class, mock(Divider.class)); + + Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID, + new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS); + mSysuiTestableContextExternal = (SysuiTestableContext) mSysuiContext.createDisplayContext( + display); + mSysuiTestableContextExternal.putComponent(CommandQueue.class, mCommandQueue); + mSysuiTestableContextExternal.putComponent(StatusBar.class, mock(StatusBar.class)); + mSysuiTestableContextExternal.putComponent(Recents.class, mock(Recents.class)); + mSysuiTestableContextExternal.putComponent(Divider.class, mock(Divider.class)); + injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); WindowManager windowManager = mock(WindowManager.class); Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay(); @@ -102,15 +166,111 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { navigationBarFragment.onHomeLongClick(navigationBarFragment.getView()); } + @Test + public void testSetImeWindowStatusWhenImeSwitchOnDisplay() { + // Create default & external NavBar fragment. + NavigationBarFragment defaultNavBar = (NavigationBarFragment) mFragment; + NavigationBarFragment externalNavBar = (NavigationBarFragment) mFragmentExternalDisplay; + mFragments.dispatchCreate(); + processAllMessages(); + mFragments.dispatchResume(); + processAllMessages(); + mControllerExternalDisplay.dispatchCreate(); + processAllMessages(); + mControllerExternalDisplay.dispatchResume(); + processAllMessages(); + + // Set IME window status for default NavBar. + mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, + BACK_DISPOSITION_DEFAULT, true); + Handler.getMain().runWithScissors(() -> { }, 500); + + // Verify IME window state will be updated in default NavBar & external NavBar state reset. + assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, + defaultNavBar.getNavigationIconHints()); + assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); + assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); + + // Set IME window status for external NavBar. + mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, + IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true); + Handler.getMain().runWithScissors(() -> { }, 500); + + // Verify IME window state will be updated in external NavBar & default NavBar state reset. + assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, + externalNavBar.getNavigationIconHints()); + assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); + assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); + } + @Override protected Fragment instantiate(Context context, String className, Bundle arguments) { DeviceProvisionedController deviceProvisionedController = mock(DeviceProvisionedController.class); assertNotNull(mAccessibilityWrapper); - return new NavigationBarFragment(mAccessibilityWrapper, + return new NavigationBarFragment( + context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper + : mock(AccessibilityManagerWrapper.class), deviceProvisionedController, new MetricsLogger(), - new AssistManager(deviceProvisionedController, mContext), + mock(AssistManager.class), mOverviewProxyService); } + + private class HostCallbacksForExternalDisplay extends + FragmentHostCallback { + private Context mDisplayContext; + + HostCallbacksForExternalDisplay(Context context) { + super(context, mHandler, 0); + mDisplayContext = context; + } + + @Override + public NavigationBarFragmentTest onGetHost() { + return NavigationBarFragmentTest.this; + } + + @Override + public Fragment instantiate(Context context, String className, Bundle arguments) { + return NavigationBarFragmentTest.this.instantiate(context, className, arguments); + } + + @Override + public View onFindViewById(int id) { + return mView.findViewById(id); + } + + @Override + public LayoutInflater onGetLayoutInflater() { + return new LayoutInflaterWrapper(mDisplayContext); + } + } + + private static class LayoutInflaterWrapper extends LayoutInflater { + protected LayoutInflaterWrapper(Context context) { + super(context); + } + + @Override + public LayoutInflater cloneInContext(Context newContext) { + return null; + } + + @Override + public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, + boolean attachToRoot) { + NavigationBarView view = mock(NavigationBarView.class); + when(view.getDisplay()).thenReturn(mContext.getDisplay()); + when(view.getBackButton()).thenReturn(mock(ButtonDispatcher.class)); + when(view.getHomeButton()).thenReturn(mock(ButtonDispatcher.class)); + when(view.getRecentsButton()).thenReturn(mock(ButtonDispatcher.class)); + when(view.getAccessibilityButton()).thenReturn(mock(ButtonDispatcher.class)); + when(view.getRotateSuggestionButton()).thenReturn(mock(RotationContextButton.class)); + when(view.getBarTransitions()).thenReturn(mock(BarTransitions.class)); + when(view.getLightTransitionsController()).thenReturn( + mock(LightBarTransitionsController.class)); + return view; + } + } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index e88d62f585079..de2fd42d398c3 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -575,6 +575,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ int mCurTokenDisplayId = INVALID_DISPLAY; + /** + * The display ID of the input method indicates the fallback display which returned by + * {@link #computeImeDisplayIdForTarget}. + */ + private static final int FALLBACK_DISPLAY_ID = DEFAULT_DISPLAY; + final ImeDisplayValidator mImeDisplayValidator; /** @@ -625,7 +631,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * currently invisible. * * - * Do not update this value outside of setImeWindowStatus. + * Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and + * {@link #unbindCurrentMethodLocked()}. */ int mImeWindowVis; @@ -2124,12 +2131,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ static int computeImeDisplayIdForTarget(int displayId, @NonNull ImeDisplayValidator checker) { if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) { - // We always assume that the default display id suitable to show the IME window. - return DEFAULT_DISPLAY; + return FALLBACK_DISPLAY_ID; } - // Show IME in default display when the display with IME target doesn't support system - // decorations. - return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY; + // Show IME window on fallback display when the display is not allowed. + return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID; } @Override @@ -2198,6 +2203,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId); } catch (RemoteException e) { } + // Set IME window status as invisible when unbind current method. + mImeWindowVis = 0; + mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT; + updateSystemUiLocked(mImeWindowVis, mBackDisposition); mCurToken = null; mCurTokenDisplayId = INVALID_DISPLAY; } @@ -2399,10 +2408,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @SuppressWarnings("deprecation") private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) { + final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId(); + synchronized (mMethodMap) { if (!calledWithValidTokenLocked(token)) { return; } + // Skip update IME status when current token display is not same as focused display. + // Note that we still need to update IME status when focusing external display + // that does not support system decoration and fallback to show IME on default + // display since it is intentional behavior. + if (mCurTokenDisplayId != topFocusedDisplayId + && mCurTokenDisplayId != FALLBACK_DISPLAY_ID) { + return; + } mImeWindowVis = vis; mBackDisposition = backDisposition; updateSystemUiLocked(vis, backDisposition); @@ -2447,7 +2466,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) { Slog.d(TAG, "IME window vis: " + vis + " active: " + (vis & InputMethodService.IME_ACTIVE) - + " inv: " + (vis & InputMethodService.IME_INVISIBLE)); + + " inv: " + (vis & InputMethodService.IME_INVISIBLE) + + " displayId: " + mCurTokenDisplayId); } // TODO: Move this clearing calling identity block to setImeWindowStatus after making sure @@ -2461,7 +2481,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked(). final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis); if (mStatusBar != null) { - mStatusBar.setImeWindowStatus(mCurToken, vis, backDisposition, + mStatusBar.setImeWindowStatus(mCurTokenDisplayId, mCurToken, vis, backDisposition, needsToShowImeSwitcher); } final InputMethodInfo imi = mMethodMap.get(mCurMethodId); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index aaf3df39d4295..9cbf00b85e8bc 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -843,10 +843,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } } - // TODO(b/117478341): support back button change when IME is showing on a external display. @Override - public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition, - final boolean showImeSwitcher) { + public void setImeWindowStatus(int displayId, final IBinder token, final int vis, + final int backDisposition, final boolean showImeSwitcher) { enforceStatusBar(); if (SPEW) { @@ -857,18 +856,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // In case of IME change, we need to call up setImeWindowStatus() regardless of // mImeWindowVis because mImeWindowVis may not have been set to false when the // previous IME was destroyed. - // TODO(b/117478341): support back button change when IME is showing on a external - // display. - getUiState(DEFAULT_DISPLAY) - .setImeWindowState(vis, backDisposition, showImeSwitcher, token); + getUiState(displayId).setImeWindowState(vis, backDisposition, showImeSwitcher, token); mHandler.post(() -> { if (mBar == null) return; try { - // TODO(b/117478341): support back button change when IME is showing on a - // external display. mBar.setImeWindowStatus( - DEFAULT_DISPLAY, token, vis, backDisposition, showImeSwitcher); + displayId, token, vis, backDisposition, showImeSwitcher); } catch (RemoteException ex) { } }); } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 9d80425435efa..78c5dbddee41a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -475,6 +475,11 @@ public abstract class WindowManagerInternal { */ public abstract int getDisplayIdForWindow(IBinder windowToken); + /** + * @return The top focused display ID. + */ + public abstract int getTopFocusedDisplayId(); + /** * Checks whether this display should support showing system decorations. */ diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ce496f47be54f..0215b7556215d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7339,6 +7339,13 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public int getTopFocusedDisplayId() { + synchronized (mGlobalLock) { + return mRoot.getTopFocusedDisplayContent().getDisplayId(); + } + } + @Override public boolean shouldShowSystemDecorOnDisplay(int displayId) { synchronized (mGlobalLock) { diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java index 9f60cce61bcec..6cd88b51cb824 100644 --- a/tests/testables/src/android/testing/BaseFragmentTest.java +++ b/tests/testables/src/android/testing/BaseFragmentTest.java @@ -52,7 +52,7 @@ public abstract class BaseFragmentTest { private static final int VIEW_ID = 42; private final Class mCls; - private Handler mHandler; + protected Handler mHandler; protected FrameLayout mView; protected FragmentController mFragments; protected Fragment mFragment;