diff options
author | Selim Cinek <cinek@google.com> | 2015-05-19 18:08:14 -0700 |
---|---|---|
committer | Selim Cinek <cinek@google.com> | 2015-05-20 22:20:17 +0000 |
commit | f83e824216435e45f36a3587e269888f791b2a01 (patch) | |
tree | 9d78872ccd5ba140ef9a687f923c35685f56de51 | |
parent | 0e2d3f2f871ae11d642eb576173d73ada9dcc292 (diff) | |
download | frameworks_base-f83e824216435e45f36a3587e269888f791b2a01.zip frameworks_base-f83e824216435e45f36a3587e269888f791b2a01.tar.gz frameworks_base-f83e824216435e45f36a3587e269888f791b2a01.tar.bz2 |
Fixed that touches where incorrectly consumed when fullscreen
The fake window that was added when View.SYSTEM_UI_FULL_SCREEN was
set consumed all touches, even those going to the SystemUI and not
just those of windows below. The input consumer is now correctly
positioned in the window order to only capture the right touches.
Clicks to the volume panel and the heads up now correctly go to the
right place instead of just unhiding the SystemUI bars.
Bug: 21089476
Change-Id: Ib53dfc0b33b70084ca607d0f044db30b6e6c91d6
-rw-r--r-- | core/java/android/view/WindowManager.java | 7 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 17 | ||||
-rw-r--r-- | services/core/java/com/android/server/policy/PhoneWindowManager.java | 78 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/AccessibilityController.java | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/InputConsumerImpl.java (renamed from services/core/java/com/android/server/wm/FakeWindowImpl.java) | 38 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/InputMonitor.java | 24 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerService.java | 35 |
7 files changed, 91 insertions, 110 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 7976ca4..f0c86e5 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -218,7 +218,7 @@ public interface WindowManager extends ViewManager { @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR, to = "TYPE_NAVIGATION_BAR"), @ViewDebug.IntToString(from = TYPE_VOLUME_OVERLAY, to = "TYPE_VOLUME_OVERLAY"), @ViewDebug.IntToString(from = TYPE_BOOT_PROGRESS, to = "TYPE_BOOT_PROGRESS"), - @ViewDebug.IntToString(from = TYPE_HIDDEN_NAV_CONSUMER, to = "TYPE_HIDDEN_NAV_CONSUMER"), + @ViewDebug.IntToString(from = TYPE_INPUT_CONSUMER, to = "TYPE_INPUT_CONSUMER"), @ViewDebug.IntToString(from = TYPE_DREAM, to = "TYPE_DREAM"), @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL"), @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY"), @@ -490,12 +490,11 @@ public interface WindowManager extends ViewManager { public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21; /** - * Window type: Fake window to consume touch events when the navigation - * bar is hidden. + * Window type to consume input events when the systemUI bars are hidden. * In multiuser systems shows on all users' windows. * @hide */ - public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22; + public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22; /** * Window type: Dreams (screen saver) window, just above keyguard. diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 9199af1..1b759a3 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -373,12 +373,12 @@ public interface WindowManagerPolicy { } /** - * Representation of a "fake window" that the policy has added to the - * window manager to consume events. + * Representation of a input consumer that the policy has added to the + * window manager to consume input events going to windows below it. */ - public interface FakeWindow { + public interface InputConsumer { /** - * Remove the fake window from the window manager. + * Remove the input consumer from the window manager. */ void dismiss(); } @@ -402,13 +402,10 @@ public interface WindowManagerPolicy { public void reevaluateStatusBarVisibility(); /** - * Add a fake window to the window manager. This window sits - * at the top of the other windows and consumes events. + * Add a input consumer which will consume all input events going to any window below it. */ - public FakeWindow addFakeWindow(Looper looper, - InputEventReceiver.Factory inputEventReceiverFactory, - String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags, - boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen); + public InputConsumer addInputConsumer(Looper looper, + InputEventReceiver.Factory inputEventReceiverFactory); /** * Returns a code that describes the current state of the lid switch. diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index a4e9c68..9bb5e40 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -51,7 +51,6 @@ import android.media.IAudioService; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.session.MediaSessionLegacyHelper; -import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.FactoryTest; @@ -97,7 +96,6 @@ import com.android.internal.policy.PhoneWindow; import android.view.Surface; import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewRootImpl; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -458,7 +456,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // menu needs to be displayed. boolean mLastFocusNeedsMenu = false; - FakeWindow mHideNavFakeWindow = null; + InputConsumer mInputConsumer = null; static final Rect mTmpParentFrame = new Rect(); static final Rect mTmpDisplayFrame = new Rect(); @@ -1817,7 +1815,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_APPLICATION_STARTING: case TYPE_BOOT_PROGRESS: case TYPE_DISPLAY_OVERLAY: - case TYPE_HIDDEN_NAV_CONSUMER: + case TYPE_INPUT_CONSUMER: case TYPE_KEYGUARD_SCRIM: case TYPE_KEYGUARD_DIALOG: case TYPE_MAGNIFICATION_OVERLAY: @@ -1942,75 +1940,75 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_VOICE_INTERACTION: // voice interaction layer is almost immediately above apps. return 5; - case TYPE_SYSTEM_DIALOG: + case TYPE_INPUT_CONSUMER: return 6; + case TYPE_SYSTEM_DIALOG: + return 7; case TYPE_TOAST: // toasts and the plugged-in battery thing - return 7; + return 8; case TYPE_PRIORITY_PHONE: // SIM errors and unlock. Not sure if this really should be in a high layer. - return 8; + return 9; case TYPE_DREAM: // used for Dreams (screensavers with TYPE_DREAM windows) - return 9; + return 10; case TYPE_SYSTEM_ALERT: // like the ANR / app crashed dialogs - return 10; + return 11; case TYPE_INPUT_METHOD: // on-screen keyboards and other such input method user interfaces go here. - return 11; + return 12; case TYPE_INPUT_METHOD_DIALOG: // on-screen keyboards and other such input method user interfaces go here. - return 12; + return 13; case TYPE_KEYGUARD_SCRIM: // the safety window that shows behind keyguard while keyguard is starting - return 13; - case TYPE_STATUS_BAR_SUB_PANEL: return 14; - case TYPE_STATUS_BAR: + case TYPE_STATUS_BAR_SUB_PANEL: return 15; - case TYPE_STATUS_BAR_PANEL: + case TYPE_STATUS_BAR: return 16; - case TYPE_KEYGUARD_DIALOG: + case TYPE_STATUS_BAR_PANEL: return 17; + case TYPE_KEYGUARD_DIALOG: + return 18; case TYPE_VOLUME_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 18; + return 19; case TYPE_SYSTEM_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 19; + return 20; case TYPE_NAVIGATION_BAR: // the navigation bar, if available, shows atop most things - return 20; + return 21; case TYPE_NAVIGATION_BAR_PANEL: // some panels (e.g. search) need to show on top of the navigation bar - return 21; + return 22; case TYPE_SYSTEM_ERROR: // system-level error dialogs - return 22; + return 23; case TYPE_MAGNIFICATION_OVERLAY: // used to highlight the magnified portion of a display - return 23; + return 24; case TYPE_DISPLAY_OVERLAY: // used to simulate secondary display devices - return 24; + return 25; case TYPE_DRAG: // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - return 25; + return 26; case TYPE_ACCESSIBILITY_OVERLAY: // overlay put by accessibility services to intercept user interaction - return 26; - case TYPE_SECURE_SYSTEM_OVERLAY: return 27; - case TYPE_BOOT_PROGRESS: + case TYPE_SECURE_SYSTEM_OVERLAY: return 28; + case TYPE_BOOT_PROGRESS: + return 29; case TYPE_POINTER: // the (mouse) pointer layer - return 29; - case TYPE_HIDDEN_NAV_CONSUMER: return 30; } Log.e(TAG, "Unknown window type: " + type); @@ -3385,15 +3383,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { // detect when the user presses anywhere to bring back the nav // bar and ensure the application doesn't see the event. if (navVisible || navAllowedHidden) { - if (mHideNavFakeWindow != null) { - mHideNavFakeWindow.dismiss(); - mHideNavFakeWindow = null; + if (mInputConsumer != null) { + mInputConsumer.dismiss(); + mInputConsumer = null; } - } else if (mHideNavFakeWindow == null) { - mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow( - mHandler.getLooper(), mHideNavInputEventReceiverFactory, - "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 0, - 0, false, false, true); + } else if (mInputConsumer == null) { + mInputConsumer = mWindowManagerFuncs.addInputConsumer(mHandler.getLooper(), + mHideNavInputEventReceiverFactory); } // For purposes of positioning and showing the nav bar, if we have @@ -6311,7 +6307,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis); // prevent status bar interaction from clearing certain flags - boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR; + int type = win.getAttrs().type; + boolean statusBarHasFocus = type == TYPE_STATUS_BAR; if (statusBarHasFocus && !isStatusBarKeyguard()) { int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION @@ -6323,6 +6320,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } vis = (vis & ~flags) | (oldVis & flags); } + if (windowTypeToLayerLw(type) > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) { + // We can't get into fullscreen from this window otherwise the consumer would not get + // the input events. + vis = (vis & ~View.SYSTEM_UI_FLAG_FULLSCREEN); + } if (!areTranslucentBarsAllowed() && transWin != mStatusBar) { vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 482ae24..66ae9ef 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -1248,7 +1248,7 @@ final class AccessibilityController { && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY && windowType != WindowManager.LayoutParams.TYPE_DRAG - && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER + && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER && windowType != WindowManager.LayoutParams.TYPE_POINTER && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY diff --git a/services/core/java/com/android/server/wm/FakeWindowImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 1136ced..0581a16 100644 --- a/services/core/java/com/android/server/wm/FakeWindowImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -16,17 +16,18 @@ package com.android.server.wm; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; - import android.os.Looper; import android.os.Process; import android.view.Display; import android.view.InputChannel; import android.view.InputEventReceiver; +import android.view.WindowManager; import android.view.WindowManagerPolicy; -public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { +import com.android.server.input.InputApplicationHandle; +import com.android.server.input.InputWindowHandle; + +public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer { final WindowManagerService mService; final InputChannel mServerChannel, mClientChannel; final InputApplicationHandle mApplicationHandle; @@ -34,12 +35,9 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { final InputEventReceiver mInputEventReceiver; final int mWindowLayer; - boolean mTouchFullscreen; - - public FakeWindowImpl(WindowManagerService service, - Looper looper, InputEventReceiver.Factory inputEventReceiverFactory, - String name, int windowType, int layoutParamsFlags, - boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) { + public InputConsumerImpl(WindowManagerService service, Looper looper, + InputEventReceiver.Factory inputEventReceiverFactory) { + String name = "input consumer"; mService = service; InputChannel[] channels = InputChannel.openInputChannelPair(name); @@ -58,31 +56,25 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { mWindowHandle = new InputWindowHandle(mApplicationHandle, null, Display.DEFAULT_DISPLAY); mWindowHandle.name = name; mWindowHandle.inputChannel = mServerChannel; - mWindowLayer = getLayerLw(windowType); + mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; + mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType); mWindowHandle.layer = mWindowLayer; - mWindowHandle.layoutParamsFlags = layoutParamsFlags; - mWindowHandle.layoutParamsType = windowType; + mWindowHandle.layoutParamsFlags = 0; mWindowHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; mWindowHandle.visible = true; - mWindowHandle.canReceiveKeys = canReceiveKeys; - mWindowHandle.hasFocus = hasFocus; + mWindowHandle.canReceiveKeys = false; + mWindowHandle.hasFocus = false; mWindowHandle.hasWallpaper = false; mWindowHandle.paused = false; mWindowHandle.ownerPid = Process.myPid(); mWindowHandle.ownerUid = Process.myUid(); mWindowHandle.inputFeatures = 0; mWindowHandle.scaleFactor = 1.0f; - - mTouchFullscreen = touchFullscreen; } void layout(int dw, int dh) { - if (mTouchFullscreen) { - mWindowHandle.touchableRegion.set(0, 0, dw, dh); - } else { - mWindowHandle.touchableRegion.setEmpty(); - } + mWindowHandle.touchableRegion.set(0, 0, dw, dh); mWindowHandle.frameLeft = 0; mWindowHandle.frameTop = 0; mWindowHandle.frameRight = dw; @@ -92,7 +84,7 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { @Override public void dismiss() { synchronized (mService.mWindowMap) { - if (mService.removeFakeWindowLocked(this)) { + if (mService.removeInputConsumer()) { mInputEventReceiver.dispose(); mService.mInputManager.unregisterInputChannel(mServerChannel); mClientChannel.dispose(); diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index c24fcb3..ae442e5 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -16,10 +16,6 @@ package com.android.server.wm; -import com.android.server.input.InputManagerService; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; - import android.app.ActivityManagerNative; import android.graphics.Rect; import android.os.RemoteException; @@ -30,17 +26,21 @@ import android.view.InputChannel; import android.view.KeyEvent; import android.view.WindowManager; +import com.android.server.input.InputApplicationHandle; +import com.android.server.input.InputManagerService; +import com.android.server.input.InputWindowHandle; + import java.util.Arrays; final class InputMonitor implements InputManagerService.WindowManagerCallbacks { private final WindowManagerService mService; - + // Current window with input focus for keys and other non-touch events. May be null. private WindowState mInputFocus; - + // When true, prevents input dispatch from proceeding until set to false again. private boolean mInputDispatchFrozen; - + // When true, input dispatch proceeds normally. Otherwise all events are dropped. // Initially false, so that input does not get dispatched until boot is finished at // which point the ActivityManager will enable dispatching. @@ -256,10 +256,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } } - final int NFW = mService.mFakeWindows.size(); - for (int i = 0; i < NFW; i++) { - addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle); - } + boolean addInputConsumerHandle = mService.mInputConsumer != null; // Add all windows on the default display. final int numDisplays = mService.mDisplayContents.size(); @@ -273,6 +270,11 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { // Skip this window because it cannot possibly receive input. continue; } + if (addInputConsumerHandle + && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) { + addInputWindowHandleLw(mService.mInputConsumer.mWindowHandle); + addInputConsumerHandle = false; + } final int flags = child.mAttrs.flags; final int privateFlags = child.mAttrs.privateFlags; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d956d76..cebb909 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -108,7 +108,6 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; import android.view.WindowManagerInternal; import android.view.WindowManagerPolicy; -import android.view.WindowManagerPolicy.FakeWindow; import android.view.WindowManagerPolicy.PointerEventListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -382,10 +381,10 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>(); /** - * Fake windows added to the window manager. Note: ordered from top to - * bottom, opposite of mWindows. + * The input consumer added to the window manager which consumes input events to windows below + * it. */ - final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<>(); + InputConsumerImpl mInputConsumer; /** * Windows that are being resized. Used so we can tell the client about @@ -8966,9 +8965,8 @@ public class WindowManagerService extends IWindowManager.Stub final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; - final int NFW = mFakeWindows.size(); - for (int i=0; i<NFW; i++) { - mFakeWindows.get(i).layout(dw, dh); + if (mInputConsumer != null) { + mInputConsumer.layout(dw, dh); } final int N = windows.size(); @@ -10995,28 +10993,19 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public FakeWindow addFakeWindow(Looper looper, - InputEventReceiver.Factory inputEventReceiverFactory, - String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags, - boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) { + public InputConsumerImpl addInputConsumer(Looper looper, + InputEventReceiver.Factory inputEventReceiverFactory) { synchronized (mWindowMap) { - FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory, - name, windowType, layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen); - int i=0; - while (i<mFakeWindows.size()) { - if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) { - break; - } - } - mFakeWindows.add(i, fw); + mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory); mInputMonitor.updateInputWindowsLw(true); - return fw; + return mInputConsumer; } } - boolean removeFakeWindowLocked(FakeWindow window) { + boolean removeInputConsumer() { synchronized (mWindowMap) { - if (mFakeWindows.remove(window)) { + if (mInputConsumer != null) { + mInputConsumer = null; mInputMonitor.updateInputWindowsLw(true); return true; } |