Properly remove activity from task on start failure.

When we fail to start an activity, it is removed from its parent task
by the starter. We currently directly ask the task to remove the
child activity. This is incorrect as the stack is unaware of the
movement and cannot cleanup the task if necessary.

This changelist addresses the problem by asking the stack instead to
finish the activity.

Change-Id: I41faa2f4e81873601d45a8ccd1bf22fef9e57033
Fixes: 76679042
Test: atest FrameworksServicesTests:ActivityStarterTests#testTaskModeViolation
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 741901d..f5e61a1 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.spy;
 
+import android.app.ActivityOptions;
 import com.android.server.wm.DisplayWindowController;
 
 import org.junit.Rule;
@@ -51,6 +52,9 @@
 import android.support.test.InstrumentationRegistry;
 import android.testing.DexmakerShareClassLoaderRule;
 
+
+import com.android.internal.app.IVoiceInteractor;
+
 import com.android.server.AttributeCache;
 import com.android.server.wm.AppWindowContainerController;
 import com.android.server.wm.PinnedStackWindowController;
@@ -62,6 +66,7 @@
 import org.junit.Before;
 import org.mockito.MockitoAnnotations;
 
+
 /**
  * A base class to handle common operations in activity related unit tests.
  */
@@ -215,6 +220,7 @@
         private int mTaskId = 0;
         private int mUserId = 0;
         private IVoiceInteractionSession mVoiceSession;
+        private boolean mCreateStack = true;
 
         private ActivityStack mStack;
 
@@ -232,6 +238,15 @@
             return this;
         }
 
+        /**
+         * Set to {@code true} by default, set to {@code false} to prevent the task from
+         * automatically creating a parent stack.
+         */
+        TaskBuilder setCreateStack(boolean createStack) {
+            mCreateStack = createStack;
+            return this;
+        }
+
         TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
             mVoiceSession = session;
             return this;
@@ -258,7 +273,7 @@
         }
 
         TaskRecord build() {
-            if (mStack == null) {
+            if (mStack == null && mCreateStack) {
                 mStack = mSupervisor.getDefaultDisplay().createStack(
                         WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
             }
@@ -276,17 +291,38 @@
             intent.setComponent(mComponent);
             intent.setFlags(mFlags);
 
-            final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
+            final TestTaskRecord task = new TestTaskRecord(mSupervisor.mService, mTaskId, aInfo,
                     intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/);
             task.userId = mUserId;
-            mSupervisor.setFocusStackUnchecked("test", mStack);
-            mStack.addTask(task, true, "creating test task");
-            task.setStack(mStack);
-            task.setWindowContainerController(mock(TaskWindowContainerController.class));
+
+            if (mStack != null) {
+                mSupervisor.setFocusStackUnchecked("test", mStack);
+                mStack.addTask(task, true, "creating test task");
+                task.setStack(mStack);
+                task.setWindowContainerController();
+            }
+
             task.touchActiveTime();
 
             return task;
         }
+
+        private static class TestTaskRecord extends TaskRecord {
+            TestTaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info,
+                       Intent _intent, IVoiceInteractionSession _voiceSession,
+                       IVoiceInteractor _voiceInteractor) {
+                super(service, _taskId, info, _intent, _voiceSession, _voiceInteractor);
+            }
+
+            @Override
+            void createWindowContainer(boolean onTop, boolean showForAllUsers) {
+                setWindowContainerController();
+            }
+
+            private void setWindowContainerController() {
+                setWindowContainerController(mock(TaskWindowContainerController.class));
+            }
+        }
     }
 
     /**
@@ -295,6 +331,7 @@
      */
     protected static class TestActivityManagerService extends ActivityManagerService {
         private ClientLifecycleManager mLifecycleManager;
+        private LockTaskController mLockTaskController;
 
         TestActivityManagerService(Context context) {
             super(context);
@@ -314,6 +351,14 @@
             return mLifecycleManager;
         }
 
+        public LockTaskController getLockTaskController() {
+            if (mLockTaskController == null) {
+                mLockTaskController = spy(super.getLockTaskController());
+            }
+
+            return mLockTaskController;
+        }
+
         void setLifecycleManager(ClientLifecycleManager manager) {
             mLifecycleManager = manager;
         }
@@ -444,7 +489,7 @@
     }
 
     /**
-     * Overrided of {@link ActivityStack} that tracks test metrics, such as the number of times a
+     * Overridden {@link ActivityStack} that tracks test metrics, such as the number of times a
      * method is called. Note that its functionality depends on the implementations of the
      * construction arguments.
      */
@@ -530,5 +575,11 @@
                     return super.supportsSplitScreenWindowingMode();
             }
         }
+
+        @Override
+        void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
+                                 boolean newTask, boolean keepCurTransition,
+                                 ActivityOptions options) {
+        }
     }
 }