Merge "Add lockTaskOnLaunch attribute."
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4723c0d..24c026d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -648,6 +648,12 @@
      */
     public boolean resizeable;
 
+    /**
+     * Value indicating if the activity is to be locked at startup.
+     * @hide
+     */
+    public boolean lockTaskOnLaunch;
+
     public ActivityInfo() {
     }
 
@@ -665,13 +671,15 @@
         uiOptions = orig.uiOptions;
         parentActivityName = orig.parentActivityName;
         maxRecents = orig.maxRecents;
+        resizeable = orig.resizeable;
+        lockTaskOnLaunch = orig.lockTaskOnLaunch;
     }
-    
+
     /**
      * Return the theme resource identifier to use for this activity.  If
      * the activity defines a theme, that is used; else, the application
      * theme is used.
-     * 
+     *
      * @return The theme associated with this activity.
      */
     public final int getThemeResource() {
@@ -709,7 +717,7 @@
         if (uiOptions != 0) {
             pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
         }
-        pw.println(prefix + "resizeable=" + resizeable);
+        pw.println(prefix + "resizeable=" + resizeable + " lockTaskOnLaunch=" + lockTaskOnLaunch);
         super.dumpBack(pw, prefix);
     }
     
@@ -739,6 +747,7 @@
         dest.writeInt(persistableMode);
         dest.writeInt(maxRecents);
         dest.writeInt(resizeable ? 1 : 0);
+        dest.writeInt(lockTaskOnLaunch ? 1 : 0);
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -767,5 +776,6 @@
         persistableMode = source.readInt();
         maxRecents = source.readInt();
         resizeable = (source.readInt() == 1);
+        lockTaskOnLaunch = (source.readInt() == 1);
     }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4b81fd4..3d5c2ed 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3113,6 +3113,9 @@
                         R.styleable.AndroidManifestActivity_screenOrientation,
                         ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
             }
+
+            a.info.lockTaskOnLaunch =
+                    sa.getBoolean(R.styleable.AndroidManifestActivity_lockTaskOnLaunch, false);
         } else {
             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             a.info.configChanges = 0;
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b0b4e3a..1b3a5e9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1038,6 +1038,13 @@
          activity. -->
     <attr name="resizeableActivity" format="boolean" />
 
+    <!-- Tasks rooted at this activity will start up in lock-task mode. That means that they
+         cannot be navigated away from until they finish or explicitly release lock-task mode.
+         This only works for system privileged activities. An exception will be thrown for
+         non-privileged activities that use this attribute.
+         @hide -->
+    <attr name="lockTaskOnLaunch" format="boolean" />
+
     <!-- When set installer will extract native libraries. If set to false
          libraries in the apk must be stored and page-aligned.  -->
     <attr name="extractNativeLibs" format="boolean"/>
@@ -1191,7 +1198,7 @@
          features in your package (or other packages).  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermission" parent="AndroidManifest">
@@ -1210,15 +1217,15 @@
         <attr name="protectionLevel" />
         <attr name="permissionFlags" />
     </declare-styleable>
-    
+
     <!-- The <code>permission-group</code> tag declares a logical grouping of
          related permissions.
-         
+
          <p>Note that this tag does not declare a permission itself, only
          a namespace in which further permissions can be placed.  See
          the {@link #AndroidManifestPermission &lt;permission&gt;} tag for
          more information.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermissionGroup" parent="AndroidManifest">
@@ -1236,7 +1243,7 @@
         <attr name="permissionGroupFlags" />
         <attr name="priority" />
     </declare-styleable>
-    
+
     <!-- The <code>permission-tree</code> tag declares the base of a tree of
          permission values: it declares that this package has ownership of
          the given permission name, as well as all names underneath it
@@ -1749,6 +1756,7 @@
         <attr name="relinquishTaskIdentity" />
         <attr name="resumeWhilePausing" />
         <attr name="resizeableActivity" />
+        <attr name="lockTaskOnLaunch" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5c7daf2..754d7ebd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2657,4 +2657,5 @@
   <!--IntentFilter auto verification -->
   <public type="attr" name="autoVerify" />
 
+  <public type="attr" name="lockTaskOnLaunch" />
 </resources>
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c318370..6543bc2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3911,9 +3911,9 @@
             }
             // Do not allow task to finish in Lock Task mode.
             if (tr == mStackSupervisor.mLockTaskModeTask) {
-                if (rootR == r) {
+                if (rootR == r && tr.getTopActivity() == r) {
                     Slog.i(TAG, "Not finishing task in lock task mode");
-                    mStackSupervisor.showLockTaskToast();
+                    mStackSupervisor.showLockTaskToastLocked();
                     return false;
                 }
             }
@@ -4074,7 +4074,7 @@
                 // Do not allow task to finish in Lock Task mode.
                 if (r.task == mStackSupervisor.mLockTaskModeTask) {
                     if (rootR == r) {
-                        mStackSupervisor.showLockTaskToast();
+                        mStackSupervisor.showLockTaskToastLocked();
                         return false;
                     }
                 }
@@ -8238,7 +8238,7 @@
                 return;
             }
             if (mStackSupervisor.isLockTaskModeViolation(task)) {
-                mStackSupervisor.showLockTaskToast();
+                mStackSupervisor.showLockTaskToastLocked();
                 Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode");
                 return;
             }
@@ -8272,7 +8272,7 @@
                 if (taskId >= 0) {
                     if ((mStackSupervisor.mLockTaskModeTask != null)
                             && (mStackSupervisor.mLockTaskModeTask.taskId == taskId)) {
-                        mStackSupervisor.showLockTaskToast();
+                        mStackSupervisor.showLockTaskToastLocked();
                         return false;
                     }
                     return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f874244..d574571 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -154,9 +154,10 @@
     static final int CONTAINER_CALLBACK_VISIBILITY = FIRST_SUPERVISOR_STACK_MSG + 8;
     static final int LOCK_TASK_START_MSG = FIRST_SUPERVISOR_STACK_MSG + 9;
     static final int LOCK_TASK_END_MSG = FIRST_SUPERVISOR_STACK_MSG + 10;
-    static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 11;
-    static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 12;
-    static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 13;
+    static final int LOCK_TASK_SHOW_TOAST_MSG = FIRST_SUPERVISOR_STACK_MSG + 11;
+    static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 12;
+    static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 13;
+    static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 14;
 
     private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
 
@@ -1884,7 +1885,7 @@
                         findTaskLocked(r) : findActivityLocked(intent, r.info);
                 if (intentActivity != null) {
                     if (isLockTaskModeViolation(intentActivity.task)) {
-                        showLockTaskToast();
+                        showLockTaskToastLocked();
                         Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                         return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
                     }
@@ -2144,6 +2145,20 @@
             } else {
                 r.setTask(reuseTask, taskToAffiliate);
             }
+            if (r.info.lockTaskOnLaunch) {
+                try {
+                    if (!AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
+                        Slog.e(TAG, "Non-privileged activity " + r +
+                                " using lockTaskOnLaunch attribute");
+                        throw new RuntimeException(
+                                "Non-privileged activity using lockTaskOnLaunch attribute.");
+                    }
+                } catch (RemoteException e) {
+                    // Unreachable. The package manager is in this process.
+                }
+                setLockTaskModeLocked(r.task, ActivityManager.LOCK_TASK_MODE_LOCKED,
+                        "lockTaskOnLaunch attribute");
+            }
             if (!movedHome) {
                 if ((launchFlags &
                         (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
@@ -3596,8 +3611,8 @@
         return list;
     }
 
-    void showLockTaskToast() {
-        mLockTaskNotify.showToast(mLockTaskModeState);
+    void showLockTaskToastLocked() {
+        mHandler.sendEmptyMessage(LOCK_TASK_SHOW_TOAST_MSG);
     }
 
     void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) {
@@ -3796,6 +3811,13 @@
                         mLockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE;
                     }
                 } break;
+                case LOCK_TASK_SHOW_TOAST_MSG: {
+                    if (mLockTaskNotify == null) {
+                        mLockTaskNotify = new LockTaskNotify(mService.mContext);
+                    }
+                    mLockTaskNotify.showToast(mLockTaskModeState);
+                    break;
+                }
                 case CONTAINER_CALLBACK_TASK_LIST_EMPTY: {
                     final ActivityContainer container = (ActivityContainer) msg.obj;
                     final IActivityContainerCallback callback = container.mCallback;