diff options
6 files changed, 125 insertions, 1 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 47ee52e25116..3faaf3669f96 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -555,6 +555,25 @@ public interface WindowManager extends ViewManager {           */          public static final int LAST_SYSTEM_WINDOW      = 2999; +        /** +         * Return true if the window type is an alert window. +         * +         * @param type The window type. +         * @return If the window type is an alert window. +         * @hide +         */ +        public static boolean isSystemAlertWindowType(int type) { +            switch (type) { +                case TYPE_PHONE: +                case TYPE_PRIORITY_PHONE: +                case TYPE_SYSTEM_ALERT: +                case TYPE_SYSTEM_ERROR: +                case TYPE_SYSTEM_OVERLAY: +                    return true; +            } +            return false; +        } +          /** @deprecated this is ignored, this value is set automatically when needed. */          @Deprecated          public static final int MEMORY_TYPE_NORMAL = 0; @@ -1116,6 +1135,15 @@ public interface WindowManager extends ViewManager {          public static final int PRIVATE_FLAG_KEYGUARD = 0x00000400;          /** +         * Flag to indicate that any window added by an application process that is of type +         * {@link #TYPE_TOAST} or that requires +         * {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when +         * this window is visible. +         * @hide +         */ +        public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000; + +        /**           * Control flags that are private to the platform.           * @hide           */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 26d870f922d3..9f033927c5b1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2059,6 +2059,15 @@          android:description="@string/permdesc_internalSystemWindow"          android:protectionLevel="signature" /> +    <!-- Allows an application to use +        {@link android.view.WindowManager.LayoutsParams#PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS} +        to hide non-system-overlay windows. +        <p>Not for use by third-party applications. +        @hide +    --> +    <permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" +        android:protectionLevel="signature" /> +      <!-- Allows an application to manage (create, destroy,           Z-order) application tokens in the window manager.           <p>Not for use by third-party applications. --> diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index d737e7f1563d..1a4abc793e91 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -16,6 +16,10 @@  package com.android.server.wm; +import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +  import android.view.IWindowId;  import android.view.IWindowSessionCallback;  import com.android.internal.view.IInputContext; @@ -61,6 +65,8 @@ final class Session extends IWindowSession.Stub      final int mUid;      final int mPid;      final String mStringName; +    final boolean mCanAddInternalSystemWindow; +    final boolean mCanHideNonSystemOverlayWindows;      SurfaceSession mSurfaceSession;      int mNumWindow = 0;      boolean mClientDead = false; @@ -74,6 +80,10 @@ final class Session extends IWindowSession.Stub          mInputContext = inputContext;          mUid = Binder.getCallingUid();          mPid = Binder.getCallingPid(); +        mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission( +                INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED; +        mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission( +                HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED;          mLastReportedAnimatorScale = service.getCurrentAnimatorScale();          StringBuilder sb = new StringBuilder();          sb.append("Session{"); @@ -525,4 +535,4 @@ final class Session extends IWindowSession.Stub      public String toString() {          return mStringName;      } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 837672aaa146..34789684bbb4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -417,6 +417,9 @@ public class WindowManagerService extends IWindowManager.Stub       */      ArrayList<WindowState> mForceRemoves; +    /** List of window currently causing non-system overlay windows to be hidden. */ +    private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<WindowState>(); +      /**       * Windows that clients are waiting to have drawn.       */ @@ -2434,6 +2437,9 @@ public class WindowManagerService extends IWindowManager.Stub                  }              } +            final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty(); +            win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows); +              if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {                  token.appWindowToken.startingWindow = win;                  if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken @@ -2683,6 +2689,7 @@ public class WindowManagerService extends IWindowManager.Stub          mPendingRemove.remove(win);          mResizingWindows.remove(win); +        updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);          mWindowsChanged = true;          if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win); @@ -11480,6 +11487,36 @@ public class WindowManagerService extends IWindowManager.Stub          return mWindowMap;      } +    void updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown) { +        if (!win.hideNonSystemOverlayWindowsWhenVisible()) { +            return; +        } +        final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty(); +        if (surfaceShown) { +            if (!mHidingNonSystemOverlayWindows.contains(win)) { +                mHidingNonSystemOverlayWindows.add(win); +            } +        } else { +            mHidingNonSystemOverlayWindows.remove(win); +        } + +        final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty(); + +        if (systemAlertWindowsHidden == hideSystemAlertWindows) { +            return; +        } + +        final int numDisplays = mDisplayContents.size(); +        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { +            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); +            final int numWindows = windows.size(); +            for (int winNdx = 0; winNdx < numWindows; ++winNdx) { +                final WindowState w = windows.get(winNdx); +                w.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows); +            } +        } +    } +      private final class LocalService extends WindowManagerInternal {          @Override          public void requestTraversalFromDisplayManager() { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b4a7f04272d9..3bd75e2fadac 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -25,11 +25,14 @@ import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;  import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;  import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;  import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;  import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;  import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_TOAST;  import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;  import android.app.AppOpsManager;  import android.os.Debug; @@ -82,6 +85,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {      final int mAppOp;      // UserId and appId of the owner. Don't display windows of non-current user.      final int mOwnerUid; +    final boolean mOwnerCanAddInternalSystemWindow;      final IWindowId mWindowId;      WindowToken mToken;      WindowToken mRootToken; @@ -107,6 +111,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {      boolean mPolicyVisibility = true;      boolean mPolicyVisibilityAfterAnim = true;      boolean mAppOpVisibility = true; +    // This is a non-system overlay window that is currently force hidden. +    private boolean mForceHideNonSystemOverlayWindow;      boolean mAppFreezing;      boolean mAttachedHidden;    // is our parent window hidden?      boolean mWallpaperVisible;  // for wallpaper, what was last vis report? @@ -333,6 +339,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {          mAppOp = appOp;          mToken = token;          mOwnerUid = s.mUid; +        mOwnerCanAddInternalSystemWindow = s.mCanAddInternalSystemWindow;          mWindowId = new IWindowId.Stub() {              @Override              public void registerFocusObserver(IWindowFocusObserver observer) { @@ -1153,6 +1160,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {              // Being hidden due to app op request.              return false;          } +        if (mForceHideNonSystemOverlayWindow) { +            // This is an alert window that is currently force hidden. +            return false; +        }          if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {              // Already showing.              return false; @@ -1226,6 +1237,22 @@ final class WindowState implements WindowManagerPolicy.WindowState {          return true;      } +    void setForceHideNonSystemOverlayWindowIfNeeded(boolean forceHide) { +        if (mOwnerCanAddInternalSystemWindow +                || (!isSystemAlertWindowType(mAttrs.type) && mAttrs.type != TYPE_TOAST)) { +            return; +        } +        if (mForceHideNonSystemOverlayWindow == forceHide) { +            return; +        } +        mForceHideNonSystemOverlayWindow = forceHide; +        if (forceHide) { +            hideLw(true /* doAnimation */, true /* requestAnim */); +        } else { +            showLw(true /* doAnimation */, true /* requestAnim */); +        } +    } +      public void setAppOpVisibilityLw(boolean state) {          if (mAppOpVisibility != state) {              mAppOpVisibility = state; @@ -1599,6 +1626,17 @@ final class WindowState implements WindowManagerPolicy.WindowState {          }      } +    /** +     * Returns true if any window added by an application process that if of type +     * {@link android.view.WindowManager.LayoutParams#TYPE_TOAST} or that requires that requires +     * {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when +     * this window is visible. +     */ +    boolean hideNonSystemOverlayWindowsWhenVisible() { +        return (mAttrs.privateFlags & PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0 +                && mSession.mCanHideNonSystemOverlayWindows; +    } +      String makeInputChannelName() {          return Integer.toHexString(System.identityHashCode(this))              + " " + mAttrs.getTitle(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 0c727f33172e..610efedf791e 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -462,6 +462,7 @@ class WindowStateAnimator {                      "HIDE (performLayout)", null);              if (mSurfaceControl != null) {                  mSurfaceShown = false; +                mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mWin, false);                  try {                      mSurfaceControl.hide();                  } catch (RuntimeException e) { @@ -1732,6 +1733,7 @@ class WindowStateAnimator {              if (mSurfaceControl != null) {                  mSurfaceShown = true;                  mSurfaceControl.show(); +                mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mWin, true);                  if (mWin.mTurnOnScreen) {                      if (DEBUG_VISIBILITY) Slog.v(TAG,                              "Show surface turning screen on: " + mWin);  |