From 64cdc1458bcf0d09781463a6e421b9b870b09687 Mon Sep 17 00:00:00 2001 From: Filip Gruszczynski Date: Sun, 29 Nov 2015 21:10:07 -0800 Subject: Remove dock divider surface when it's not visible. We achieve the removal by notifying System UI about the visibility of the dock divider. This way System UI can change visibility of the root view, which in turn will cause the WMS to destroy or create the surface as necessary. Bug: 25844096 Bug: 25683717 Change-Id: Idbc33368db697a059af49106dfadb80c3d7d06c1 --- Android.mk | 1 + .../view/IDockDividerVisibilityListener.aidl | 27 ++++++++++++++++++ core/java/android/view/IWindowManager.aidl | 10 +++++-- core/res/AndroidManifest.xml | 5 ++++ packages/SystemUI/AndroidManifest.xml | 1 + .../systemui/recents/misc/SystemServicesProxy.java | 12 ++++++++ .../com/android/systemui/stackdivider/Divider.java | 29 ++++++++++++++++++++ .../android/server/policy/PhoneWindowManager.java | 2 +- .../server/wm/DockedStackDividerController.java | 32 ++++++++++++++++++---- .../android/server/wm/WindowManagerService.java | 29 ++++++++++++++++++-- .../java/com/android/server/wm/WindowState.java | 2 +- .../src/android/view/IWindowManagerImpl.java | 4 +++ 12 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 core/java/android/view/IDockDividerVisibilityListener.aidl diff --git a/Android.mk b/Android.mk index f5d5a113ff0a..d22273c6b75d 100644 --- a/Android.mk +++ b/Android.mk @@ -261,6 +261,7 @@ LOCAL_SRC_FILES += \ core/java/android/view/IApplicationToken.aidl \ core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \ core/java/android/view/IAssetAtlas.aidl \ + core/java/android/view/IDockDividerVisibilityListener.aidl \ core/java/android/view/IGraphicsStats.aidl \ core/java/android/view/IInputFilter.aidl \ core/java/android/view/IInputFilterHost.aidl \ diff --git a/core/java/android/view/IDockDividerVisibilityListener.aidl b/core/java/android/view/IDockDividerVisibilityListener.aidl new file mode 100644 index 000000000000..a7d5cda9b44f --- /dev/null +++ b/core/java/android/view/IDockDividerVisibilityListener.aidl @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +/** + * Listener for showing/hiding of the dock divider. Will fire when an app is shown in side by side + * mode and a divider should be shown. + * + * @hide + */ +oneway interface IDockDividerVisibilityListener { + void onDockDividerVisibilityChanged(boolean visible); +} diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 64a046ec7c06..bd6553297929 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -29,6 +29,7 @@ import android.os.Bundle; import android.os.IRemoteCallback; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; +import android.view.IDockDividerVisibilityListener; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; import android.view.IWindowSession; @@ -290,10 +291,10 @@ interface IWindowManager /** * Create a screenshot of the applications currently displayed. * - * @param frameScale the scale to apply to the frame, only used when width = -1 and + * @param frameScale the scale to apply to the frame, only used when width = -1 and * height = -1 */ - Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight, + Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight, float frameScale); /** @@ -348,4 +349,9 @@ interface IWindowManager * stack size. */ void setDockedStackResizing(boolean resizing); + + /** + * Registers a listener that will be called when the dock divider changes its visibility. + */ + void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 57338bee6366..568b60162875 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1877,6 +1877,11 @@ + + + + diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index de40a37bf8a1..59fb6cf00e7c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -56,6 +56,7 @@ import android.util.Log; import android.util.MutableBoolean; import android.util.Pair; import android.view.Display; +import android.view.IDockDividerVisibilityListener; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; @@ -847,4 +848,15 @@ public class SystemServicesProxy { e.printStackTrace(); } } + + public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) { + if (mWm == null) return; + + try { + WindowManagerGlobal.getWindowManagerService().registerDockDividerVisibilityListener( + listener); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 50e010fc2928..6ff7a3e08159 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -17,10 +17,14 @@ package com.android.systemui.stackdivider; import android.content.res.Configuration; +import android.view.IDockDividerVisibilityListener; import android.view.LayoutInflater; +import android.view.View; import com.android.systemui.R; import com.android.systemui.SystemUI; +import com.android.systemui.recents.Recents; +import com.android.systemui.recents.misc.SystemServicesProxy; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; @@ -33,6 +37,8 @@ public class Divider extends SystemUI { private int mDividerWindowWidth; private DividerWindowManager mWindowManager; private DividerView mView; + private DockDividerVisibilityListener mDockDividerVisibilityListener; + private boolean mVisible = false; @Override public void start() { @@ -41,6 +47,9 @@ public class Divider extends SystemUI { com.android.internal.R.dimen.docked_stack_divider_thickness); update(mContext.getResources().getConfiguration()); putComponent(Divider.class, this); + mDockDividerVisibilityListener = new DockDividerVisibilityListener(); + SystemServicesProxy ssp = Recents.getSystemServices(); + ssp.registerDockDividerVisibilityListener(mDockDividerVisibilityListener); } @Override @@ -56,6 +65,7 @@ public class Divider extends SystemUI { private void addDivider(Configuration configuration) { mView = (DividerView) LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null); + mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE); final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE; final int width = landscape ? mDividerWindowWidth : MATCH_PARENT; final int height = landscape ? MATCH_PARENT : mDividerWindowWidth; @@ -71,4 +81,23 @@ public class Divider extends SystemUI { removeDivider(); addDivider(configuration); } + + private void updateVisibility(final boolean visible) { + mView.post(new Runnable() { + @Override + public void run() { + if (mVisible != visible) { + mVisible = visible; + mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + } + } + }); + } + + class DockDividerVisibilityListener extends IDockDividerVisibilityListener.Stub { + @Override + public void onDockDividerVisibilityChanged(boolean visible) { + updateVisibility(visible); + } + } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index ae6874f720b1..639753a13b16 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2533,7 +2533,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) { - if (transit == TRANSIT_ENTER) { + if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { return R.anim.fade_in; } else if (transit == TRANSIT_EXIT) { return R.anim.fade_out; diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 6b6246760b39..df8d5d6f6e9b 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -18,7 +18,11 @@ package com.android.server.wm; import android.content.Context; import android.graphics.Rect; +import android.os.RemoteException; import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.view.IDockDividerVisibilityListener; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.view.WindowManager.DOCKED_BOTTOM; @@ -40,6 +44,8 @@ public class DockedStackDividerController { private WindowState mWindow; private final Rect mTmpRect = new Rect(); private final Rect mLastRect = new Rect(); + private IDockDividerVisibilityListener mListener; + private boolean mLastVisibility = false; DockedStackDividerController(Context context, DisplayContent displayContent) { mDisplayContent = displayContent; @@ -67,12 +73,21 @@ public class DockedStackDividerController { } void reevaluateVisibility() { - if (mWindow == null) return; + if (mWindow == null) { + return; + } TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID); - if (stack != null && stack.isVisibleLocked()) { - mWindow.showLw(true /* doAnimation */); - } else { - mWindow.hideLw(true /* doAnimation */); + final boolean visible = stack != null && stack.isVisibleLocked(); + if (mLastVisibility == visible) { + return; + } + mLastVisibility = visible; + if (mListener != null) { + try { + mListener.onDockDividerVisibilityChanged(visible); + } catch (RemoteException e) { + Slog.e(TAG, "visibility call failed: " + e); + } } } @@ -110,4 +125,11 @@ public class DockedStackDividerController { } mLastRect.set(frame); } + + public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) { + if (mListener != null && listener != null) { + throw new IllegalStateException("Dock divider visibility listener already set!"); + } + mListener = listener; + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ac90daf97b90..395962c920ae 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -121,6 +121,7 @@ import android.view.DropPermissionHolder; import android.view.Gravity; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; +import android.view.IDockDividerVisibilityListener; import android.view.IInputFilter; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; @@ -2689,8 +2690,7 @@ public class WindowManagerService extends IWindowManager.Stub // need to see about starting one. final boolean notExitingOrAnimating = !win.mExiting && !win.isAnimatingWithSavedSurface(); - result |= notExitingOrAnimating - ? RELAYOUT_RES_SURFACE_CHANGED : 0; + result |= notExitingOrAnimating ? RELAYOUT_RES_SURFACE_CHANGED : 0; if (notExitingOrAnimating) { focusMayChange = tryStartingAnimation(win, winAnimator, isDefaultDisplay, focusMayChange); @@ -3075,7 +3075,7 @@ public class WindowManagerService extends IWindowManager.Stub // TODO: } - boolean checkCallingPermission(String permission, String func) { + private boolean checkCallingPermission(String permission, String func) { // Quick check: if the calling permission is me, it's all okay. if (Binder.getCallingPid() == Process.myPid()) { return true; @@ -10211,6 +10211,29 @@ public class WindowManagerService extends IWindowManager.Stub mDestroySurface.add(win); } + @Override + public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) { + if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS, + "registerDockDividerVisibilityListener()")) { + return; + } + // TODO(multi-display): The listener is registered on the default display only. + final DockedStackDividerController controller = + getDefaultDisplayContentLocked().getDockedDividerController(); + controller.registerDockDividerVisibilityListener(listener); + try { + listener.asBinder().linkToDeath(new IBinder.DeathRecipient() { + @Override + public void binderDied() { + getDefaultDisplayContentLocked().getDockedDividerController() + .registerDockDividerVisibilityListener(null); + } + }, 0); + } catch (RemoteException e) { + controller.registerDockDividerVisibilityListener(null); + } + } + 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 064b4128a2ce..29cadf3e67c4 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -730,7 +730,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mVisibleFrame.set(mContentFrame); mStableFrame.set(mContentFrame); } else if (mAttrs.type == TYPE_DOCK_DIVIDER) { - if (isVisibleLw()) { + if (isVisibleLw() || mWinAnimator.isAnimating()) { // We don't adjust the dock divider frame for reasons other than performance. The // real reason is that if it gets adjusted before it is shown for the first time, // it would get size (0, 0). This causes a problem when we finally show the dock diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 6951ede681e1..eea254bb8fcf 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -541,4 +541,8 @@ public class IWindowManagerImpl implements IWindowManager { @Override public void endProlongedAnimations() { } + + @Override + public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) { + } } -- cgit v1.2.3-59-g8ed1b