Add toast when an app intercepts the launch of another app.

The activity manager looks for cases where one app launches immediately
after another.  If this happens, a brief toast is shown telling the user
when app is actually running and what was originally starting.

Change-Id: If94cf5bd393dd0bc0f09789dae044fde1386c481
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 5f79b85..a0c21dd 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -102,6 +102,10 @@
     // 30 minutes.
     static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
     
+    // How long between activity launches that we consider safe to not warn
+    // the user about an unexpected activity being launched on top.
+    static final long START_WARN_TIME = 5*1000;
+    
     // Set to false to disable the preview that is shown while a new activity
     // is being started.
     static final boolean SHOW_APP_STARTING_PREVIEW = true;
@@ -213,6 +217,13 @@
     ActivityRecord mResumedActivity = null;
     
     /**
+     * This is the last activity that has been started.  It is only used to
+     * identify when multiple activities are started at once so that the user
+     * can be warned they may not be in the activity they think they are.
+     */
+    ActivityRecord mLastStartedActivity = null;
+    
+    /**
      * Set when we know we are going to be calling updateConfiguration()
      * soon, so want to skip intermediate config checks.
      */
@@ -586,10 +597,10 @@
         ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                 r.info.applicationInfo.uid);
         
-        if (r.startTime == 0) {
-            r.startTime = SystemClock.uptimeMillis();
+        if (r.launchTime == 0) {
+            r.launchTime = SystemClock.uptimeMillis();
             if (mInitialStartTime == 0) {
-                mInitialStartTime = r.startTime;
+                mInitialStartTime = r.launchTime;
             }
         } else if (mInitialStartTime == 0) {
             mInitialStartTime = SystemClock.uptimeMillis();
@@ -1090,6 +1101,31 @@
             return false;
         }
 
+        // Okay we are now going to start a switch, to 'next'.  We may first
+        // have to pause the current activity, but this is an important point
+        // where we have decided to go to 'next' so keep track of that.
+        if (mLastStartedActivity != null) {
+            long now = SystemClock.uptimeMillis();
+            final boolean inTime = mLastStartedActivity.startTime != 0
+                    && (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
+            final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
+            final int nextUid = next.info.applicationInfo.uid;
+            if (inTime && lastUid != nextUid
+                    && lastUid != next.launchedFromUid
+                    && mService.checkPermission(
+                            android.Manifest.permission.STOP_APP_SWITCHES,
+                            -1, next.launchedFromUid)
+                    != PackageManager.PERMISSION_GRANTED) {
+                mService.showLaunchWarningLocked(mLastStartedActivity, next);
+            } else {
+                next.startTime = now;
+                mLastStartedActivity = next;
+            }
+        } else {
+            next.startTime = SystemClock.uptimeMillis();
+            mLastStartedActivity = next;
+        }
+        
         // We need to start pausing the current activity so the top one
         // can be resumed...
         if (mResumedActivity != null) {
@@ -1314,7 +1350,6 @@
         
         if (!newTask) {
             // If starting in an existing task, find where that is...
-            ActivityRecord next = null;
             boolean startIt = true;
             for (int i = NH-1; i >= 0; i--) {
                 ActivityRecord p = (ActivityRecord)mHistory.get(i);
@@ -1342,14 +1377,13 @@
                 if (p.fullscreen) {
                     startIt = false;
                 }
-                next = p;
             }
         }
 
         // Place a new activity at top of stack, so it is next to interact
         // with the user.
         if (addPos < 0) {
-            addPos = mHistory.size();
+            addPos = NH;
         }
         
         // If we are not placing the new activity frontmost, we do not want