Merge "Remove dock divider surface when it's not visible."
diff --git a/Android.mk b/Android.mk
index f5d5a11..d22273c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -261,6 +261,7 @@
 	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 0000000..a7d5cda
--- /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 64a046e..bd65532 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -29,6 +29,7 @@
 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 @@
     /**
      * 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 @@
      * 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 57338be..568b601 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1877,6 +1877,11 @@
     <permission android:name="android.permission.MANAGE_APP_TOKENS"
         android:protectionLevel="signature" />
 
+    <!-- Allows System UI to register listeners for events from Window Manager.
+         @hide -->
+    <permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS"
+        android:protectionLevel="signature" />
+
     <!-- @hide Allows the application to temporarily freeze the screen for a
          full-screen transition. -->
     <permission android:name="android.permission.FREEZE_SCREEN"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6fda2c6..2f79adf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -87,6 +87,7 @@
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS" />
     <uses-permission android:name="android.permission.SET_ORIENTATION" />
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
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 55d983b..2b20c07 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.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;
@@ -851,4 +852,15 @@
             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 50e010f..6ff7a3e 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 @@
     private int mDividerWindowWidth;
     private DividerWindowManager mWindowManager;
     private DividerView mView;
+    private DockDividerVisibilityListener mDockDividerVisibilityListener;
+    private boolean mVisible = false;
 
     @Override
     public void start() {
@@ -41,6 +47,9 @@
                 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 @@
     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 @@
         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 ae6874f..639753a 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 @@
                 }
             }
         } 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 6b62467..df8d5d6 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 @@
 
 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 @@
     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 @@
     }
 
     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 @@
         }
         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 ac90daf..395962c 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.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 @@
                     // 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 @@
         // 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 @@
         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 064b412..29cadf3 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 @@
             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 6951ede..eea254b 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -541,4 +541,8 @@
     @Override
     public void endProlongedAnimations() {
     }
+
+    @Override
+    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    }
 }