Cleanup after ActivityView

- Release Surface and VirtualDisplay when shutting down ActivityView.
- Shut down child stacks when relaunching parent activity.

Change-Id: I60314b2b43bd2da5406cf6ec871293b5baca157c
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index fef4597..25cde8c 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -24,6 +24,7 @@
 import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.Surface;
 import android.view.TextureView;
 import android.view.TextureView.SurfaceTextureListener;
@@ -31,12 +32,15 @@
 import android.view.WindowManager;
 
 public class ActivityView extends ViewGroup {
+    private final String TAG = "ActivityView";
+
     private final TextureView mTextureView;
     private IActivityContainer mActivityContainer;
     private Activity mActivity;
     private boolean mAttached;
     private int mWidth;
     private int mHeight;
+    private Surface mSurface;
 
     public ActivityView(Context context) {
         this(context, null);
@@ -83,20 +87,18 @@
 
         final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
         if (surfaceTexture != null) {
-            createActivityView(surfaceTexture);
+            attachToSurface(surfaceTexture);
         }
     }
 
     @Override
     protected void onDetachedFromWindow() {
-        if (mActivityContainer != null) {
-            try {
-                mActivityContainer.deleteActivityView();
-            } catch (RemoteException e) {
-            }
-            mActivityContainer = null;
-        }
-        mAttached = false;
+        detachFromSurface();
+    }
+
+    @Override
+    public boolean isAttachedToWindow() {
+        return mAttached;
     }
 
     public void startActivity(Intent intent) {
@@ -110,22 +112,41 @@
     }
 
     /** Call when both mActivityContainer and mTextureView's SurfaceTexture are not null */
-    private void createActivityView(SurfaceTexture surfaceTexture) {
+    private void attachToSurface(SurfaceTexture surfaceTexture) {
         WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
         DisplayMetrics metrics = new DisplayMetrics();
         wm.getDefaultDisplay().getMetrics(metrics);
 
+        mSurface = new Surface(surfaceTexture);
         try {
-            mActivityContainer.createActivityView(new Surface(surfaceTexture), mWidth, mHeight,
+            mActivityContainer.attachToSurface(mSurface, mWidth, mHeight,
                     metrics.densityDpi);
         } catch (RemoteException e) {
             mActivityContainer = null;
+            mSurface.release();
+            mSurface = null;
+            mAttached = false;
             throw new IllegalStateException(
                     "ActivityView: Unable to create ActivityContainer. " + e);
         }
         mAttached = true;
     }
 
+    private void detachFromSurface() {
+        if (mActivityContainer != null) {
+            try {
+                mActivityContainer.detachFromDisplay();
+            } catch (RemoteException e) {
+            }
+            mActivityContainer = null;
+        }
+        if (mSurface != null) {
+            mSurface.release();
+            mSurface = null;
+        }
+        mAttached = false;
+    }
+
     private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
         @Override
         public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
@@ -133,30 +154,26 @@
             mWidth = width;
             mHeight = height;
             if (mActivityContainer != null) {
-                createActivityView(surfaceTexture);
+                attachToSurface(surfaceTexture);
             }
         }
 
         @Override
         public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
                 int height) {
+            Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height);
         }
 
         @Override
         public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
-            try {
-                mActivityContainer.deleteActivityView();
-                // TODO: Add binderDied to handle this nullification.
-                mActivityContainer = null;
-            } catch (RemoteException r) {
-            }
-            mAttached = false;
-            return false;
+            Log.d(TAG, "onSurfaceTextureDestroyed");
+            detachFromSurface();
+            return true;
         }
 
         @Override
         public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
-
+//            Log.d(TAG, "onSurfaceTextureUpdated");
         }
 
     }
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index b03a459..df1cf91 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -24,9 +24,8 @@
 /** @hide */
 interface IActivityContainer {
     void attachToDisplay(int displayId);
-    int getDisplayId();
+    void attachToSurface(in Surface surface, int width, int height, int density);
     void detachFromDisplay();
     int startActivity(in Intent intent);
-    void createActivityView(in Surface surface, int width, int height, int density);
-    void deleteActivityView();
+    int getDisplayId();
 }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 600cc58..c9d6222 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -322,7 +322,7 @@
         }
     }
 
-    private int numActivities() {
+    int numActivities() {
         int count = 0;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             count += mTaskHistory.get(taskNdx).mActivities.size();
@@ -2675,6 +2675,7 @@
     }
 
     private void removeActivityFromHistoryLocked(ActivityRecord r) {
+        mStackSupervisor.removeChildActivityContainers(r);
         finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
         r.makeFinishing();
         if (DEBUG_ADD_REMOVE) {
@@ -3318,6 +3319,8 @@
 
         r.startFreezingScreenLocked(r.app, 0);
 
+        mStackSupervisor.removeChildActivityContainers(r);
+
         try {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
                     (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ")
@@ -3350,14 +3353,20 @@
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.appToken == token) {
-                        return true;
+                    return true;
                 }
                 if (r.fullscreen && !r.finishing) {
                     return false;
                 }
             }
         }
-        return true;
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r == null) {
+            return false;
+        }
+        if (r.finishing) Slog.e(TAG, "willActivityBeVisibleLocked: Returning false,"
+                + " would have returned true for r=" + r);
+        return !r.finishing;
     }
 
     void closeSystemDialogsLocked() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7acca84..c31669d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -417,11 +417,13 @@
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (!isFrontStack(stack)) {
+                if (!isFrontStack(stack) || stack.numActivities() == 0) {
                     continue;
                 }
                 final ActivityRecord resumedActivity = stack.mResumedActivity;
                 if (resumedActivity == null || !resumedActivity.idle) {
+                    if (DEBUG_STATES) Slog.d(TAG, "allResumedActivitiesIdle: stack="
+                             + stack.mStackId + " " + resumedActivity + " not idle");
                     return false;
                 }
             }
@@ -2130,6 +2132,28 @@
         return createActivityContainer(parentActivity, getNextStackId(), callback);
     }
 
+    void removeChildActivityContainers(ActivityRecord parentActivity) {
+        for (int ndx = mActivityContainers.size() - 1; ndx >= 0; --ndx) {
+            final ActivityContainer container = mActivityContainers.valueAt(ndx).get();
+            if (container == null) {
+                mActivityContainers.removeAt(ndx);
+                continue;
+            }
+            if (container.mParentActivity != parentActivity) {
+                continue;
+            }
+
+            ActivityStack stack = container.mStack;
+            ActivityRecord top = stack.topRunningNonDelayedActivityLocked(null);
+            if (top != null) {
+                // TODO: Make sure the next activity doesn't start up when top is destroyed.
+                stack.destroyActivityLocked(top, true, true, "stack removal");
+            }
+            mActivityContainers.removeAt(ndx);
+            container.detachLocked();
+        }
+    }
+
     private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
@@ -2683,7 +2707,9 @@
     }
 
     final void scheduleResumeTopActivities() {
-        mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+        if (!mHandler.hasMessages(RESUME_TOP_ACTIVITY_MSG)) {
+            mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+        }
     }
 
     void removeSleepTimeouts() {
@@ -2731,7 +2757,7 @@
             if (activityDisplay != null) {
                 ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
                 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                    activityDisplay.detachActivitiesLocked(stacks.get(stackNdx));
+                    stacks.get(stackNdx).mActivityContainer.detachLocked();
                 }
                 mActivityDisplays.remove(displayId);
             }
@@ -2872,6 +2898,7 @@
         final IActivityContainerCallback mCallback;
         final ActivityStack mStack;
         final ActivityRecord mParentActivity;
+        final String mIdString;
 
         /** Display this ActivityStack is currently on. Null if not attached to a Display. */
         ActivityDisplay mActivityDisplay;
@@ -2883,10 +2910,14 @@
                 mStack = new ActivityStack(this);
                 mParentActivity = parentActivity;
                 mCallback = callback;
+                mIdString = "ActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+                if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
             }
         }
 
         void attachToDisplayLocked(ActivityDisplay activityDisplay) {
+            if (DEBUG_STACK) Slog.d(TAG, "attachToDisplayLocked: " + this
+                    + " to display=" + activityDisplay);
             mActivityDisplay = activityDisplay;
             mStack.mDisplayId = activityDisplay.mDisplayId;
             mStack.mStacks = activityDisplay.mStacks;
@@ -2914,7 +2945,9 @@
             return -1;
         }
 
-        void detachLocked() {
+        private void detachLocked() {
+            if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display="
+                    + mActivityDisplay + " Callers=" + Debug.getCallers(2));
             if (mActivityDisplay != null) {
                 mActivityDisplay.detachActivitiesLocked(mStack);
                 mActivityDisplay = null;
@@ -2951,45 +2984,15 @@
         }
 
         @Override
-        public void createActivityView(Surface surface, int width, int height, int density) {
-            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
-            VirtualDisplay virtualDisplay;
-            long ident = Binder.clearCallingIdentity();
-            try {
-                virtualDisplay = dm.createVirtualDisplay(mService.mContext,
-                        VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface,
-                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
-                        DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-
-            final Display display = virtualDisplay.getDisplay();
-            final int displayId = display.getDisplayId();
-
-            mWindowManager.handleDisplayAdded(displayId);
-
+        public void attachToSurface(Surface surface, int width, int height, int density) {
             synchronized (mService) {
-                ActivityDisplay activityDisplay = new ActivityDisplay(display);
-                mActivityDisplays.put(displayId, activityDisplay);
+                ActivityDisplay activityDisplay =
+                        new ActivityDisplay(surface, width, height, density);
+                mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
                 attachToDisplayLocked(activityDisplay);
-                activityDisplay.mVirtualDisplay = virtualDisplay;
             }
-        }
-
-        @Override
-        public void deleteActivityView() {
-            synchronized (mService) {
-                if (!isAttached()) {
-                    return;
-                }
-                VirtualDisplay virtualDisplay = mActivityDisplay.mVirtualDisplay;
-                if (virtualDisplay != null) {
-                    virtualDisplay.release();
-                    mActivityDisplay.mVirtualDisplay = null;
-                }
-                detachLocked();
-            }
+            if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
+                    + mActivityDisplay);
         }
 
         ActivityStackSupervisor getOuter() {
@@ -3007,15 +3010,21 @@
                 outBounds.set(0, 0);
             }
         }
+
+        @Override
+        public String toString() {
+            return mIdString + (mActivityDisplay == null ? "N" : "A");
+        }
     }
 
     /** Exactly one of these classes per Display in the system. Capable of holding zero or more
      * attached {@link ActivityStack}s */
     final class ActivityDisplay {
         /** Actual Display this object tracks. */
-        final int mDisplayId;
-        final Display mDisplay;
-        final DisplayInfo mDisplayInfo = new DisplayInfo();
+        int mDisplayId;
+        Display mDisplay;
+        DisplayInfo mDisplayInfo = new DisplayInfo();
+        Surface mSurface;
 
         /** All of the stacks on this display. Order matters, topmost stack is in front of all other
          * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
@@ -3026,10 +3035,32 @@
         VirtualDisplay mVirtualDisplay;
 
         ActivityDisplay(int displayId) {
-            this(mDisplayManager.getDisplay(displayId));
+            init(mDisplayManager.getDisplay(displayId));
         }
 
         ActivityDisplay(Display display) {
+            init(display);
+        }
+
+        ActivityDisplay(Surface surface, int width, int height, int density) {
+            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+            long ident = Binder.clearCallingIdentity();
+            try {
+                mVirtualDisplay = dm.createVirtualDisplay(mService.mContext,
+                        VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface,
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+
+            init(mVirtualDisplay.getDisplay());
+            mSurface = surface;
+
+            mWindowManager.handleDisplayAdded(mDisplayId);
+        }
+
+        private void init(Display display) {
             mDisplay = display;
             mDisplayId = display.getDisplayId();
             mDisplay.getDisplayInfo(mDisplayInfo);
@@ -3042,9 +3073,14 @@
         }
 
         void detachActivitiesLocked(ActivityStack stack) {
-            if (DEBUG_STACK) Slog.v(TAG, "attachActivities: detaching " + stack
+            if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack
                     + " from displayId=" + mDisplayId);
             mStacks.remove(stack);
+            if (mStacks.isEmpty() && mVirtualDisplay != null) {
+                mVirtualDisplay.release();
+                mVirtualDisplay = null;
+            }
+            mSurface.release();
         }
 
         void getBounds(Point bounds) {
@@ -3052,5 +3088,11 @@
             bounds.x = mDisplayInfo.appWidth;
             bounds.y = mDisplayInfo.appHeight;
         }
+
+        @Override
+        public String toString() {
+            return "ActivityDisplay={" + mDisplayId + (mVirtualDisplay == null ? "" : "V")
+                    + " numStacks=" + mStacks.size() + "}";
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6e66d83..9be5347 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -18,8 +18,6 @@
 
 import static android.view.WindowManager.LayoutParams.*;
 
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
 import android.app.AppOpsManager;
@@ -3622,7 +3620,7 @@
             if (freezeThisOneIfNeeded != null) {
                 AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
                 if (atoken != null) {
-                    startAppFreezingScreenLocked(atoken, ActivityInfo.CONFIG_ORIENTATION);
+                    startAppFreezingScreenLocked(atoken);
                 }
             }
             config = computeNewConfigurationLocked();
@@ -4395,8 +4393,7 @@
         }
     }
 
-    public void startAppFreezingScreenLocked(AppWindowToken wtoken,
-            int configChanges) {
+    private void startAppFreezingScreenLocked(AppWindowToken wtoken) {
         if (DEBUG_ORIENTATION) {
             RuntimeException e = null;
             if (!HIDE_STACK_CRAWLS) {
@@ -4445,7 +4442,7 @@
                 return;
             }
             final long origId = Binder.clearCallingIdentity();
-            startAppFreezingScreenLocked(wtoken, configChanges);
+            startAppFreezingScreenLocked(wtoken);
             Binder.restoreCallingIdentity(origId);
         }
     }
@@ -8313,8 +8310,7 @@
         // it frozen/off until this window draws at its new
         // orientation.
         if (!okToDisplay()) {
-            if (DEBUG_ORIENTATION) Slog.v(TAG,
-                    "Changing surface while display frozen: " + w);
+            if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
             mInnerFields.mOrientationChangeComplete = false;