am 534de491: Merge "Make immersive mode public & imply update locking" into jb-mr1-aah-dev

* commit '534de491e6522465a7ad12d7cba9b2f80deab364':
  Make immersive mode public & imply update locking
diff --git a/api/current.txt b/api/current.txt
index f409526..d281f13 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2683,6 +2683,7 @@
     method public final boolean isChild();
     method public boolean isDestroyed();
     method public boolean isFinishing();
+    method public boolean isImmersive();
     method public boolean isTaskRoot();
     method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public boolean moveTaskToBack(boolean);
@@ -2770,6 +2771,7 @@
     method public final void setFeatureDrawableResource(int, int);
     method public final void setFeatureDrawableUri(int, android.net.Uri);
     method public void setFinishOnTouchOutside(boolean);
+    method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setProgress(int);
     method public final void setProgressBarIndeterminate(boolean);
@@ -6330,6 +6332,7 @@
     field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
     field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
     field public static final int FLAG_HARDWARE_ACCELERATED = 512; // 0x200
+    field public static final int FLAG_IMMERSIVE = 2048; // 0x800
     field public static final int FLAG_MULTIPROCESS = 1; // 0x1
     field public static final int FLAG_NO_HISTORY = 128; // 0x80
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f6b9a8e..cbeffc1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4818,8 +4818,8 @@
      * <code>android:immersive</code> but may be changed at runtime by
      * {@link #setImmersive}.
      *
+     * @see #setImmersive(boolean)
      * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
-     * @hide
      */
     public boolean isImmersive() {
         try {
@@ -4831,7 +4831,7 @@
 
     /**
      * Adjust the current immersive mode setting.
-     * 
+     *
      * Note that changing this value will have no effect on the activity's
      * {@link android.content.pm.ActivityInfo} structure; that is, if
      * <code>android:immersive</code> is set to <code>true</code>
@@ -4840,9 +4840,8 @@
      * always have its {@link android.content.pm.ActivityInfo#FLAG_IMMERSIVE
      * FLAG_IMMERSIVE} bit set.
      *
-     * @see #isImmersive
+     * @see #isImmersive()
      * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
-     * @hide
      */
     public void setImmersive(boolean i) {
         try {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e2ca1dd..8f3b62d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -161,7 +161,6 @@
      */
     public static final int FLAG_SHOW_ON_LOCK_SCREEN = 0x0400;
     /**
-     * @hide
      * Bit in {@link #flags} corresponding to an immersive activity
      * that wishes not to be interrupted by notifications.
      * Applications that hide the system notification bar with
@@ -174,7 +173,14 @@
      * {@link #FLAG_IMMERSIVE} set, however, will not be interrupted; the
      * notification may be shown in some other way (such as a small floating
      * "toast" window).
-     * {@see android.app.Notification#FLAG_HIGH_PRIORITY}
+     *
+     * Note that this flag will always reflect the Activity's
+     * <code>android:immersive</code> manifest definition, even if the Activity's
+     * immersive state is changed at runtime via
+     * {@link android.app.Activity#setImmersive(boolean)}.
+     *
+     * @see android.app.Notification#FLAG_HIGH_PRIORITY
+     * @see android.app.Activity#setImmersive(boolean)
      */
     public static final int FLAG_IMMERSIVE = 0x0800;
     /**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 49dc220..2ba9a10 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -115,6 +115,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.format.Time;
@@ -191,6 +192,7 @@
     static final boolean DEBUG_POWER = localLOGV || false;
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
     static final boolean DEBUG_MU = localLOGV || false;
+    static final boolean DEBUG_IMMERSIVE = localLOGV || false;
     static final boolean VALIDATE_TOKENS = false;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
     
@@ -827,6 +829,12 @@
     long mLastWriteTime = 0;
 
     /**
+     * Used to retain an update lock when the foreground activity is in
+     * immersive mode.
+     */
+    final UpdateLock mUpdateLock = new UpdateLock("immersive");
+
+    /**
      * Set to true after the system has finished booting.
      */
     boolean mBooted = false;
@@ -895,6 +903,7 @@
     static final int REPORT_USER_SWITCH_MSG = 34;
     static final int CONTINUE_USER_SWITCH_MSG = 35;
     static final int USER_SWITCH_TIMEOUT_MSG = 36;
+    static final int IMMERSIVE_MODE_LOCK_MSG = 37;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1356,6 +1365,21 @@
                 timeoutUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
                 break;
             }
+            case IMMERSIVE_MODE_LOCK_MSG: {
+                final boolean nextState = (msg.arg1 != 0);
+                if (mUpdateLock.isHeld() != nextState) {
+                    if (DEBUG_IMMERSIVE) {
+                        final ActivityRecord r = (ActivityRecord) msg.obj;
+                        Slog.d(TAG, "Applying new update lock state '" + nextState + "' for " + r);
+                    }
+                    if (nextState) {
+                        mUpdateLock.acquire();
+                    } else {
+                        mUpdateLock.release();
+                    }
+                }
+                break;
+            }
             }
         }
     };
@@ -1822,9 +1846,20 @@
             if (r != null) {
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
+            applyUpdateLockStateLocked(r);
         }
     }
 
+    final void applyUpdateLockStateLocked(ActivityRecord r) {
+        // Modifications to the UpdateLock state are done on our handler, outside
+        // the activity manager's locks.  The new state is determined based on the
+        // state *now* of the relevant activity record.  The object is passed to
+        // the handler solely for logging detail, not to be consulted/modified.
+        final boolean nextState = r != null && r.immersive;
+        mHandler.sendMessage(
+                mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
+    }
+
     private final void updateLruProcessInternalLocked(ProcessRecord app, int bestPos) {
         // put it on the LRU to keep track of when it should be exited.
         int lrui = mLruProcesses.indexOf(app);
@@ -7421,11 +7456,19 @@
 
     public void setImmersive(IBinder token, boolean immersive) {
         synchronized(this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            final ActivityRecord r = mMainStack.isInStackLocked(token);
             if (r == null) {
                 throw new IllegalArgumentException();
             }
             r.immersive = immersive;
+
+            // update associated state if we're frontmost
+            if (r == mFocusedActivity) {
+                if (DEBUG_IMMERSIVE) {
+                    Slog.d(TAG, "Frontmost changed immersion: "+ r);
+                }
+                applyUpdateLockStateLocked(r);
+            }
         }
     }