Merge "Change ActivityView startActivity state sequence" into lmp-mr1-modular-dev
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 94ea2c5..fecaf6f 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.app.ActivityManager.START_CANCELED;
+
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.IIntentSender;
@@ -23,6 +25,7 @@
 import android.content.IntentSender;
 import android.graphics.SurfaceTexture;
 import android.os.IBinder;
+import android.os.OperationCanceledException;
 import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -55,10 +58,6 @@
     private int mLastVisibility;
     private ActivityViewCallback mActivityViewCallback;
 
-    // Only one IIntentSender or Intent may be queued at a time. Most recent one wins.
-    IIntentSender mQueuedPendingIntent;
-    Intent mQueuedIntent;
-
     public ActivityView(Context context) {
         this(context, null);
     }
@@ -167,14 +166,13 @@
         if (mActivityContainer == null) {
             throw new IllegalStateException("Attempt to call startActivity after release");
         }
+        if (mSurface == null) {
+            throw new IllegalStateException("Surface not yet created.");
+        }
         if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " +
                 (isAttachedToDisplay() ? "" : "not") + " attached");
-        if (mSurface != null) {
-            mActivityContainer.startActivity(intent);
-        } else {
-            mActivityContainer.checkEmbeddedAllowed(intent);
-            mQueuedIntent = intent;
-            mQueuedPendingIntent = null;
+        if (mActivityContainer.startActivity(intent) == START_CANCELED) {
+            throw new OperationCanceledException();
         }
     }
 
@@ -182,15 +180,14 @@
         if (mActivityContainer == null) {
             throw new IllegalStateException("Attempt to call startActivity after release");
         }
+        if (mSurface == null) {
+            throw new IllegalStateException("Surface not yet created.");
+        }
         if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " +
                 (isAttachedToDisplay() ? "" : "not") + " attached");
         final IIntentSender iIntentSender = intentSender.getTarget();
-        if (mSurface != null) {
-            mActivityContainer.startActivityIntentSender(iIntentSender);
-        } else {
-            mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
-            mQueuedPendingIntent = iIntentSender;
-            mQueuedIntent = null;
+        if (mActivityContainer.startActivityIntentSender(iIntentSender) == START_CANCELED) {
+            throw new OperationCanceledException();
         }
     }
 
@@ -198,15 +195,14 @@
         if (mActivityContainer == null) {
             throw new IllegalStateException("Attempt to call startActivity after release");
         }
+        if (mSurface == null) {
+            throw new IllegalStateException("Surface not yet created.");
+        }
         if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " "
                 + (isAttachedToDisplay() ? "" : "not") + " attached");
         final IIntentSender iIntentSender = pendingIntent.getTarget();
-        if (mSurface != null) {
-            mActivityContainer.startActivityIntentSender(iIntentSender);
-        } else {
-            mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
-            mQueuedPendingIntent = iIntentSender;
-            mQueuedIntent = null;
+        if (mActivityContainer.startActivityIntentSender(iIntentSender) == START_CANCELED) {
+            throw new OperationCanceledException();
         }
     }
 
@@ -243,26 +239,24 @@
             mSurface = null;
             throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e);
         }
-
-        if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null ||
-                mQueuedPendingIntent != null ? "" : "no") + " queued intent");
-        if (mQueuedIntent != null) {
-            mActivityContainer.startActivity(mQueuedIntent);
-            mQueuedIntent = null;
-        } else if (mQueuedPendingIntent != null) {
-            mActivityContainer.startActivityIntentSender(mQueuedPendingIntent);
-            mQueuedPendingIntent = null;
-        }
     }
 
     /**
      * Set the callback to use to report certain state changes.
-     * @param callback The callback to report events to.
+     *
+     * Note: If the surface has been created prior to this call being made, then
+     * ActivityViewCallback.onSurfaceAvailable will be called from within setCallback.
+     *
+     *  @param callback The callback to report events to.
      *
      * @see ActivityViewCallback
      */
     public void setCallback(ActivityViewCallback callback) {
         mActivityViewCallback = callback;
+
+        if (mSurface != null) {
+            mActivityViewCallback.onSurfaceAvailable(this);
+        }
     }
 
     public static abstract class ActivityViewCallback {
@@ -272,6 +266,16 @@
          * have at most one callback registered.
          */
         public abstract void onAllActivitiesComplete(ActivityView view);
+        /**
+         * Called when the surface is ready to be drawn to. Calling startActivity prior to this
+         * callback will result in an IllegalStateException.
+         */
+        public abstract void onSurfaceAvailable(ActivityView view);
+        /**
+         * Called when the surface has been removed. Calling startActivity after this callback
+         * will result in an IllegalStateException.
+         */
+        public abstract void onSurfaceDestroyed(ActivityView view);
     }
 
     private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
@@ -286,6 +290,9 @@
             mWidth = width;
             mHeight = height;
             attachToSurfaceWhenReady();
+            if (mActivityViewCallback != null) {
+                mActivityViewCallback.onSurfaceAvailable(ActivityView.this);
+            }
         }
 
         @Override
@@ -311,6 +318,9 @@
                 throw new RuntimeException(
                         "ActivityView: Unable to set surface of ActivityContainer. " + e);
             }
+            if (mActivityViewCallback != null) {
+                mActivityViewCallback.onSurfaceDestroyed(ActivityView.this);
+            }
             return true;
         }
 
@@ -325,7 +335,7 @@
         private final WeakReference<ActivityView> mActivityViewWeakReference;
 
         ActivityContainerCallback(ActivityView activityView) {
-            mActivityViewWeakReference = new WeakReference<ActivityView>(activityView);
+            mActivityViewWeakReference = new WeakReference<>(activityView);
         }
 
         @Override
@@ -391,24 +401,6 @@
             }
         }
 
-        void checkEmbeddedAllowed(Intent intent) {
-            try {
-                mIActivityContainer.checkEmbeddedAllowed(intent);
-            } catch (RemoteException e) {
-                throw new RuntimeException(
-                        "ActivityView: Unable to startActivity from Intent. " + e);
-            }
-        }
-
-        void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
-            try {
-                mIActivityContainer.checkEmbeddedAllowedIntentSender(intentSender);
-            } catch (RemoteException e) {
-                throw new RuntimeException(
-                        "ActivityView: Unable to startActivity from IntentSender. " + e);
-            }
-        }
-
         int getDisplayId() {
             try {
                 return mIActivityContainer.getDisplayId();
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index 52884f7..cc3b10c 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -29,8 +29,6 @@
     void setSurface(in Surface surface, int width, int height, int density);
     int startActivity(in Intent intent);
     int startActivityIntentSender(in IIntentSender intentSender);
-    void checkEmbeddedAllowed(in Intent intent);
-    void checkEmbeddedAllowedIntentSender(in IIntentSender intentSender);
     int getDisplayId();
     boolean injectEvent(in InputEvent event);
     void release();
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 32787d8..0630cad 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -69,6 +69,7 @@
 import android.hardware.display.VirtualDisplay;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -855,6 +856,11 @@
 
         ActivityContainer container = (ActivityContainer)iContainer;
         synchronized (mService) {
+            if (container != null && container.mParentActivity != null &&
+                    container.mParentActivity.state != ActivityState.RESUMED) {
+                // Cannot start a child activity if the parent is not resumed.
+                return ActivityManager.START_CANCELED;
+            }
             final int realCallingPid = Binder.getCallingPid();
             final int realCallingUid = Binder.getCallingUid();
             int callingPid;
@@ -3788,18 +3794,21 @@
         @Override
         public final int startActivity(Intent intent) {
             mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
-            int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+            final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false,
                     ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
+
             // TODO: Switch to user app stacks here.
-            intent.addFlags(FORCE_NEW_TASK_FLAGS);
             String mimeType = intent.getType();
-            if (mimeType == null && intent.getData() != null
-                    && "content".equals(intent.getData().getScheme())) {
-                mimeType = mService.getProviderMimeType(intent.getData(), userId);
+            final Uri data = intent.getData();
+            if (mimeType == null && data != null && "content".equals(data.getScheme())) {
+                mimeType = mService.getProviderMimeType(data, userId);
             }
-            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, 0,
-                    0, null, null, null, null, userId, this, null);
+            checkEmbeddedAllowedInner(userId, intent, mimeType);
+
+            intent.addFlags(FORCE_NEW_TASK_FLAGS);
+            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null,
+                    0, 0, null, null, null, null, userId, this, null);
         }
 
         @Override
@@ -3810,21 +3819,19 @@
                 throw new IllegalArgumentException("Bad PendingIntent object");
             }
 
-            return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null,
-                    null, 0, FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
-        }
-
-        private void checkEmbeddedAllowedInner(Intent intent, String resolvedType) {
-            int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+            final int userId = mService.handleIncomingUser(Binder.getCallingPid(),
                     Binder.getCallingUid(), mCurrentUser, false,
                     ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
-            if (resolvedType == null) {
-                resolvedType = intent.getType();
-                if (resolvedType == null && intent.getData() != null
-                        && "content".equals(intent.getData().getScheme())) {
-                    resolvedType = mService.getProviderMimeType(intent.getData(), userId);
-                }
-            }
+
+            final PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
+            checkEmbeddedAllowedInner(userId, pendingIntent.key.requestIntent,
+                    pendingIntent.key.requestResolvedType);
+
+            return pendingIntent.sendInner(0, null, null, null, null, null, null, 0,
+                    FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
+        }
+
+        private void checkEmbeddedAllowedInner(int userId, Intent intent, String resolvedType) {
             ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, userId);
             if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
                 throw new SecurityException(
@@ -3832,23 +3839,6 @@
             }
         }
 
-        /** Throw a SecurityException if allowEmbedded is not true */
-        @Override
-        public final void checkEmbeddedAllowed(Intent intent) {
-            checkEmbeddedAllowedInner(intent, null);
-        }
-
-        /** Throw a SecurityException if allowEmbedded is not true */
-        @Override
-        public final void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
-            if (!(intentSender instanceof PendingIntentRecord)) {
-                throw new IllegalArgumentException("Bad PendingIntent object");
-            }
-            PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
-            checkEmbeddedAllowedInner(pendingIntent.key.requestIntent,
-                    pendingIntent.key.requestResolvedType);
-        }
-
         @Override
         public IBinder asBinder() {
             return this;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index ffaa03d..7bdfced 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -29,6 +29,8 @@
 import android.os.UserHandle;
 import android.util.Slog;
 
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 
@@ -201,6 +203,13 @@
             IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
         synchronized(owner) {
+            final ActivityContainer activityContainer = (ActivityContainer)container;
+            if (activityContainer != null && activityContainer.mParentActivity != null &&
+                    activityContainer.mParentActivity.state
+                            != ActivityStack.ActivityState.RESUMED) {
+                // Cannot start a child activity if the parent is not resumed.
+                return ActivityManager.START_CANCELED;
+            }
             if (!canceled) {
                 sent = true;
                 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {