Use different asset when docked stack exists

- Add the ability to add a listener when the existence of the
docked stack changes.
- Register SystemUI as such a listener and switch the recents
button asset when docked stack exists.

Change-Id: I05350878c5adc7ad9f0399f0c42d8d1615d44d02
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8f3d3e3..dd8774f 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -18,9 +18,10 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.view.WindowManager.DOCKED_BOTTOM;
@@ -44,9 +45,9 @@
     private WindowState mWindow;
     private final Rect mTmpRect = new Rect();
     private final Rect mLastRect = new Rect();
-    private IDockDividerVisibilityListener mListener;
     private boolean mLastVisibility = false;
-    private boolean mForceVisibilityReevaluation;
+    private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
+            = new RemoteCallbackList<>();
 
     DockedStackDividerController(Context context, DisplayContent displayContent) {
         mDisplayContent = displayContent;
@@ -83,13 +84,11 @@
             return;
         }
         mLastVisibility = visible;
-        if (mListener != null) {
-            try {
-                mListener.onDockDividerVisibilityChanged(visible);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "visibility call failed: " + e);
-            }
-        }
+        notifyDockedDividerVisibilityChanged(visible);
+    }
+
+    boolean wasVisible() {
+        return mLastVisibility;
     }
 
     void positionDockedStackedDivider(Rect frame) {
@@ -127,11 +126,36 @@
         mLastRect.set(frame);
     }
 
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
-        if (mListener != null && listener != null) {
-            throw new IllegalStateException("Dock divider visibility listener already set!");
+    void notifyDockedDividerVisibilityChanged(boolean visible) {
+        final int size = mDockedStackListeners.beginBroadcast();
+        for (int i = 0; i < size; ++i) {
+            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+            try {
+                listener.onDividerVisibilityChanged(visible);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
+            }
         }
-        mListener = listener;
-        reevaluateVisibility(true);
+        mDockedStackListeners.finishBroadcast();
+    }
+
+    void notifyDockedStackExistsChanged(boolean exists) {
+        final int size = mDockedStackListeners.beginBroadcast();
+        for (int i = 0; i < size; ++i) {
+            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+            try {
+                listener.onDockedStackExistsChanged(exists);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
+            }
+        }
+        mDockedStackListeners.finishBroadcast();
+    }
+
+    void registerDockedStackListener(IDockedStackListener listener) {
+        mDockedStackListeners.register(listener);
+        notifyDockedDividerVisibilityChanged(wasVisible());
+        notifyDockedStackExistsChanged(
+                mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index be75335..155d37d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -20,6 +20,7 @@
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
@@ -56,6 +57,7 @@
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -83,7 +85,7 @@
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IApplicationToken;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -4653,6 +4655,10 @@
                         if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
                         stack = new TaskStack(this, stackId);
                         mStackIdToStack.put(stackId, stack);
+                        if (stackId == DOCKED_STACK_ID) {
+                            getDefaultDisplayContentLocked().mDividerControllerLocked
+                                    .notifyDockedStackExistsChanged(true);
+                        }
                     }
                     stack.attachDisplayContent(displayContent);
                     displayContent.attachStack(stack, onTop);
@@ -4678,6 +4684,10 @@
     void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
         displayContent.detachStack(stack);
         stack.detachDisplay();
+        if (stack.mStackId == DOCKED_STACK_ID) {
+            getDefaultDisplayContentLocked().mDividerControllerLocked
+                    .notifyDockedStackExistsChanged(false);
+        }
     }
 
     public void detachStack(int stackId) {
@@ -10169,7 +10179,8 @@
         synchronized (mWindowMap) {
             appWindowToken = findAppWindowToken(token);
             if (appWindowToken == null || !appWindowToken.isVisible()) {
-                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token);
+                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+                        + token);
                 return;
             }
             appWindowToken.setReplacingWindows(animate);
@@ -10216,26 +10227,14 @@
     }
 
     @Override
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    public void registerDockedStackListener(IDockedStackListener listener) {
         if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
-                "registerDockDividerVisibilityListener()")) {
+                "registerDockedStackListener()")) {
             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);
-        }
+        getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener(
+                listener);
     }
 
     private final class LocalService extends WindowManagerInternal {