Various fixes and improvements to window, activity.

- New meta-data you can add to a dock activity to have it launched by the
  home key when the device is in that dock.

- Fix a deadlock involving ActivityThread's internal content provider lock.

- New window flag to have a non-secure keyguard entirely dismissed when a
  window is displayed.

- New WindowManagerPolicy APIs to allow the policy to tell the system when
  a change it makes during layout may cause the wall paper or
  overall configuration to change.

- Fix a bug where an application token removed while one of its windows is
  animating could cause the animating window to get stuck on screen.

Change-Id: I6d33fd39edd796bb9bdfd9dd7e077b84ca62ea08
diff --git a/api/current.xml b/api/current.xml
index fa54a10..68a1c76 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -36906,6 +36906,17 @@
  visibility="public"
 >
 </field>
+<field name="METADATA_DOCK_HOME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.dock_home&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="URI_INTENT_SCHEME"
  type="int"
  transient="false"
@@ -160428,6 +160439,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_DISMISS_KEYGUARD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4194304"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_DITHER"
  type="int"
  transient="false"
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8142d1a..6acd665 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1765,6 +1765,7 @@
         public static final int CREATE_BACKUP_AGENT     = 128;
         public static final int DESTROY_BACKUP_AGENT    = 129;
         public static final int SUICIDE                 = 130;
+        public static final int REMOVE_PROVIDER         = 131;
         String codeToString(int code) {
             if (localLOGV) {
                 switch (code) {
@@ -1799,6 +1800,7 @@
                     case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
                     case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
                     case SUICIDE: return "SUICIDE";
+                    case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
                 }
             }
             return "(unknown)";
@@ -1911,9 +1913,10 @@
                     handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
                     break;
                 case SUICIDE:
-                    {
-                        Process.killProcess(Process.myPid());
-                    }
+                    Process.killProcess(Process.myPid());
+                    break;
+                case REMOVE_PROVIDER:
+                    completeRemoveProvider((IContentProvider)msg.obj);
                     break;
             }
         }
@@ -4029,15 +4032,28 @@
             } else {
                 prc.count--;
                 if(prc.count == 0) {
-                    mProviderRefCountMap.remove(jBinder);
-                    //invoke removeProvider to dereference provider
-                    removeProviderLocked(provider);
+                    // Schedule the actual remove asynchronously, since we
+                    // don't know the context this will be called in.
+                    Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
+                    mH.sendMessage(msg);
                 } //end if
             } //end else
         } //end synchronized
         return true;
     }
 
+    final void completeRemoveProvider(IContentProvider provider) {
+        IBinder jBinder = provider.asBinder();
+        synchronized(mProviderMap) {
+            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
+            if(prc != null && prc.count == 0) {
+                mProviderRefCountMap.remove(jBinder);
+                //invoke removeProvider to dereference provider
+                removeProviderLocked(provider);
+            }
+        }
+    }
+    
     public final void removeProviderLocked(IContentProvider provider) {
         if (provider == null) {
             return;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index f6ca50d..5fb5768 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1885,7 +1885,7 @@
             "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
     /**
      * An activity to run when device is inserted into a car dock.
-    * Used with {@link #ACTION_MAIN} to launch an activity.
+     * Used with {@link #ACTION_MAIN} to launch an activity.
      * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead.
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2056,6 +2056,12 @@
     public static final int EXTRA_DOCK_STATE_CAR = 2;
 
     /**
+     * Boolean that can be supplied as meta-data with a dock activity, to
+     * indicate that the dock should take over the home key when it is active.
+     */
+    public static final String METADATA_DOCK_HOME = "android.dock_home";
+    
+    /**
      * Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
      * the bug report.
      *
@@ -3605,7 +3611,7 @@
             }
         } else {
             ResolveInfo info = pm.resolveActivity(
-                this, PackageManager.MATCH_DEFAULT_ONLY);
+                this, PackageManager.MATCH_DEFAULT_ONLY | flags);
             if (info != null) {
                 ai = info.activityInfo;
             }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f67c4aa..396e380 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -488,7 +488,10 @@
          * is locked. This will let application windows take precedence over
          * key guard or any other lock screens. Can be used with
          * {@link #FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
-         * directly before showing the key guard window
+         * directly before showing the key guard window.  Can be used with
+         * {@link #FLAG_DISMISS_KEYGUARD} to automatically fully dismisss
+         * non-secure keyguards.  This flag only applies to the top-most
+         * full-screen window.
          */
         public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
 
@@ -506,6 +509,19 @@
          * up the device) to turn the screen on. */
         public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
         
+        /** Window flag: when set the window will cause the keyguard to
+         * be dismissed, only if it is not a secure lock keyguard.  Because such
+         * a keyguard is not needed for security, it will never re-appear if
+         * the user navigates to another window (in contrast to
+         * {@link #FLAG_SHOW_WHEN_LOCKED}, which will only temporarily
+         * hide both secure and non-secure keyguards but ensure they reappear
+         * when the user moves to another UI that doesn't hide them).
+         * If the keyguard is currently active and is secure (requires an
+         * unlock pattern) than the user will still need to confirm it before
+         * seeing this window, unless {@link #FLAG_SHOW_WHEN_LOCKED} has
+         * also been set. */
+        public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
+        
         /** Window flag: special flag to limit the size of the window to be
          * original size ([320x480] x density). Used to create window for applications
          * running under compatibility mode.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index cc5aeb1..1923743 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -602,11 +602,18 @@
      * returned, all windows given to layoutWindow() <em>must</em> have had a
      * frame assigned.
      *  
-     * @return Return true if layout state may have changed (so that another 
-     *         layout will be performed).
+     * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT}
+     * and {@link #FINISH_LAYOUT_REDO_CONFIG}.
      */
-    public boolean finishLayoutLw();
+    public int finishLayoutLw();
 
+    /** Layout state may have changed (so another layout will be performed) */
+    static final int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
+    /** Configuration state may have changed */
+    static final int FINISH_LAYOUT_REDO_CONFIG = 0x0002;
+    /** Wallpaper may need to move */
+    static final int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
+    
     /**
      * Called when animation of the windows is about to start.
      * 
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 8a4b45d..a70134d3 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -74,7 +74,8 @@
             if (category != null) {
                 intent = new Intent(Intent.ACTION_MAIN);
                 intent.addCategory(category);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                 try {
                     mContext.startActivity(intent);
                 } catch (ActivityNotFoundException e) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 3c76cf2..38d2304 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -143,6 +143,7 @@
     static final boolean DEBUG_REORDER = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean SHOW_TRANSACTIONS = false;
+    static final boolean HIDE_STACK_CRAWLS = true;
     static final boolean MEASURE_LATENCY = false;
     static private LatencyTimer lt;
 
@@ -622,7 +623,7 @@
 
     private void placeWindowAfter(Object pos, WindowState window) {
         final int i = mWindows.indexOf(pos);
-        if (localLOGV || DEBUG_FOCUS) Log.v(
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
             TAG, "Adding window " + window + " at "
             + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
         mWindows.add(i+1, window);
@@ -630,7 +631,7 @@
 
     private void placeWindowBefore(Object pos, WindowState window) {
         final int i = mWindows.indexOf(pos);
-        if (localLOGV || DEBUG_FOCUS) Log.v(
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
             TAG, "Adding window " + window + " at "
             + i + " of " + mWindows.size() + " (before " + pos + ")");
         mWindows.add(i, window);
@@ -687,6 +688,9 @@
                                 //apptoken note that the window could be a floating window
                                 //that was created later or a window at the top of the list of
                                 //windows associated with this token.
+                                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+                                        TAG, "Adding window " + win + " at "
+                                        + (newIdx+1) + " of " + N);
                                 localmWindows.add(newIdx+1, win);
                             }
                         }
@@ -766,9 +770,9 @@
                                     break;
                                 }
                             }
-                            if (localLOGV || DEBUG_FOCUS) Log.v(
-                                TAG, "Adding window " + win + " at "
-                                + i + " of " + N);
+                            if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+                                    TAG, "Adding window " + win + " at "
+                                    + i + " of " + N);
                             localmWindows.add(i, win);
                         }
                     }
@@ -783,9 +787,9 @@
                     }
                 }
                 if (i < 0) i = 0;
-                if (localLOGV || DEBUG_FOCUS) Log.v(
-                    TAG, "Adding window " + win + " at "
-                    + i + " of " + N);
+                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+                        TAG, "Adding window " + win + " at "
+                        + i + " of " + N);
                 localmWindows.add(i, win);
             }
             if (addToToken) {
@@ -955,7 +959,7 @@
         if (w != null) {
             if (willMove) {
                 RuntimeException e = new RuntimeException();
-                e.fillInStackTrace();
+                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
                         + mInputMethodTarget + " to " + w, e);
                 mInputMethodTarget = w;
@@ -969,7 +973,7 @@
         }
         if (willMove) {
             RuntimeException e = new RuntimeException();
-            e.fillInStackTrace();
+            if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
             if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
                     + mInputMethodTarget + " to null", e);
             mInputMethodTarget = null;
@@ -982,6 +986,8 @@
         int pos = findDesiredInputMethodWindowIndexLocked(true);
         if (pos >= 0) {
             win.mTargetAppToken = mInputMethodTarget.mAppToken;
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(
+                    TAG, "Adding input method window " + win + " at " + pos);
             mWindows.add(pos, win);
             moveInputMethodDialogsLocked(pos+1);
             return;
@@ -1022,6 +1028,7 @@
         int wpos = mWindows.indexOf(win);
         if (wpos >= 0) {
             if (wpos < interestingPos) interestingPos--;
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Temp removing at " + wpos + ": " + win);
             mWindows.remove(wpos);
             int NC = win.mChildWindows.size();
             while (NC > 0) {
@@ -1030,6 +1037,8 @@
                 int cpos = mWindows.indexOf(cw);
                 if (cpos >= 0) {
                     if (cpos < interestingPos) interestingPos--;
+                    if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Temp removing child at "
+                            + cpos + ": " + cw);
                     mWindows.remove(cpos);
                 }
             }
@@ -1044,6 +1053,8 @@
         // this case should be rare, so it shouldn't be that big a deal.
         int wpos = mWindows.indexOf(win);
         if (wpos >= 0) {
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "ReAdd removing from " + wpos
+                    + ": " + win);
             mWindows.remove(wpos);
             reAddWindowLocked(wpos, win);
         }
@@ -1472,6 +1483,8 @@
                 // not in the list.
                 int oldIndex = localmWindows.indexOf(wallpaper);
                 if (oldIndex >= 0) {
+                    if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Wallpaper removing at "
+                            + oldIndex + ": " + wallpaper);
                     localmWindows.remove(oldIndex);
                     if (oldIndex < foundI) {
                         foundI--;
@@ -1479,7 +1492,8 @@
                 }
                 
                 // Now stick it in.
-                if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
+                if (DEBUG_WALLPAPER || DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+                        "Moving wallpaper " + wallpaper
                         + " from " + oldIndex + " to " + foundI);
                 
                 localmWindows.add(foundI, wallpaper);
@@ -2003,6 +2017,7 @@
 
         mWindowMap.remove(win.mClient.asBinder());
         mWindows.remove(win);
+        if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Final remove of window: " + win);
 
         if (mInputMethodWindow == win) {
             mInputMethodWindow = null;
@@ -2447,7 +2462,7 @@
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = new RuntimeException();
-                    e.fillInStackTrace();
+                    if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                     Log.v(TAG, "Loaded animation " + a + " for " + win, e);
                 }
                 win.setAnimation(a);
@@ -2551,7 +2566,7 @@
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = new RuntimeException();
-                    e.fillInStackTrace();
+                    if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                     Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
                 }
                 wtoken.setAnimation(a);
@@ -3093,6 +3108,8 @@
                         startingWindow.mToken = wtoken;
                         startingWindow.mRootToken = wtoken;
                         startingWindow.mAppToken = wtoken;
+                        if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+                                "Removing starting window: " + startingWindow);
                         mWindows.remove(startingWindow);
                         ttoken.windows.remove(startingWindow);
                         ttoken.allAppWindows.remove(startingWindow);
@@ -3320,7 +3337,7 @@
 
             if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
                 RuntimeException e = new RuntimeException();
-                e.fillInStackTrace();
+                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
                         + "): mNextAppTransition=" + mNextAppTransition
                         + " hidden=" + wtoken.hidden
@@ -3412,7 +3429,7 @@
             int configChanges) {
         if (DEBUG_ORIENTATION) {
             RuntimeException e = new RuntimeException();
-            e.fillInStackTrace();
+            if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
             Log.i(TAG, "Set freezing of " + wtoken.appToken
                     + ": hidden=" + wtoken.hidden + " freezing="
                     + wtoken.freezingScreen, e);
@@ -3512,6 +3529,12 @@
                 if (delayed) {
                     // set the token aside because it has an active animation to be finished
                     mExitingAppTokens.add(wtoken);
+                } else {
+                    // Make sure there is no animation running on this token,
+                    // so any windows associated with it will be removed as
+                    // soon as their animations are complete
+                    wtoken.animation = null;
+                    wtoken.animating = false;
                 }
                 mAppTokens.remove(wtoken);
                 wtoken.removed = true;
@@ -3547,7 +3570,7 @@
         final int NW = token.windows.size();
         for (int i=0; i<NW; i++) {
             WindowState win = token.windows.get(i);
-            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Tmp removing window " + win);
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Tmp removing app window " + win);
             mWindows.remove(win);
             int j = win.mChildWindows.size();
             while (j > 0) {
@@ -6999,13 +7022,13 @@
                 try {
                     if (DEBUG_VISIBILITY) {
                         RuntimeException e = new RuntimeException();
-                        e.fillInStackTrace();
+                        if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                         Log.w(TAG, "Window " + this + " destroying surface "
                                 + mSurface + ", session " + mSession, e);
                     }
                     if (SHOW_TRANSACTIONS) {
                         RuntimeException ex = new RuntimeException();
-                        ex.fillInStackTrace();
+                        if (!HIDE_STACK_CRAWLS) ex.fillInStackTrace();
                         Log.i(TAG, "  SURFACE " + mSurface + ": DESTROY ("
                                 + mAttrs.getTitle() + ")", ex);
                     }
@@ -7060,7 +7083,7 @@
         boolean performShowLocked() {
             if (DEBUG_VISIBILITY) {
                 RuntimeException e = new RuntimeException();
-                e.fillInStackTrace();
+                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                 Log.v(TAG, "performShow on " + this
                         + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
                         + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
@@ -8662,6 +8685,7 @@
     final void rebuildAppWindowListLocked() {
         int NW = mWindows.size();
         int i;
+        int numRemoved = 0;
         
         // First remove all existing app windows.
         i=0;
@@ -8671,6 +8695,7 @@
                 if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
                         "Rebuild removing window: " + win);
                 NW--;
+                numRemoved++;
                 continue;
             }
             i++;
@@ -8691,6 +8716,11 @@
         for (int j=0; j<NT; j++) {
             i = reAddAppWindowsLocked(i, mAppTokens.get(j));
         }
+        
+        if (i != numRemoved) {
+            Log.w(TAG, "Rebuild removed " + numRemoved
+                    + " windows but added " + i);
+        }
     }
     
     private final void assignLayersLocked() {
@@ -8853,13 +8883,34 @@
                 }
             }
 
-            if (!mPolicy.finishLayoutLw()) {
+            int changes = mPolicy.finishLayoutLw();
+            if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                    assignLayersLocked();
+                }
+            }
+            if (changes == 0) {
                 mLayoutNeeded = false;
             } else if (repeats > 2) {
                 Log.w(TAG, "Layout repeat aborted after too many iterations");
                 mLayoutNeeded = false;
+                if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                    Configuration newConfig = updateOrientationFromAppTokensLocked(
+                            null, null);
+                    if (newConfig != null) {
+                        mLayoutNeeded = true;
+                        mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+                    }
+                }
             } else {
                 repeats++;
+                if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                    Configuration newConfig = updateOrientationFromAppTokensLocked(
+                            null, null);
+                    if (newConfig != null) {
+                        mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+                    }
+                }
             }
         }
     }
@@ -9784,6 +9835,11 @@
         for (i=mExitingAppTokens.size()-1; i>=0; i--) {
             AppWindowToken token = mExitingAppTokens.get(i);
             if (!token.hasVisible && !mClosingApps.contains(token)) {
+                // Make sure there is no animation running on this token,
+                // so any windows associated with it will be removed as
+                // soon as their animations are complete
+                token.animation = null;
+                token.animating = false;
                 mAppTokens.remove(token);
                 mExitingAppTokens.remove(i);
             }