Merge changes from topic "splashscreen-surface" into sc-dev

* changes:
  Do not reparent the SC when package is already realeased
  Display Splashscreen AVD in a SurfaceView
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 92bdda3..eb0a7b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -73,8 +73,8 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
@@ -4108,7 +4108,7 @@
         }
         synchronized (this) {
             if (mSplashScreenGlobal != null) {
-                mSplashScreenGlobal.dispatchOnExitAnimation(r.token, v);
+                mSplashScreenGlobal.handOverSplashScreenView(r.token, v);
             }
         }
     }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2fce434..6b0bb9d 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -571,7 +571,10 @@
         // recreate this Surface, so only release it when we are fully
         // detached.
         if (mSurfacePackage != null) {
-            mTmpTransaction.reparent(mSurfacePackage.getSurfaceControl(), null).apply();
+            final SurfaceControl sc = mSurfacePackage.getSurfaceControl();
+            if (sc != null && sc.isValid()) {
+                mTmpTransaction.reparent(sc, null).apply();
+            }
             mSurfacePackage.release();
             mSurfacePackage = null;
         }
@@ -1826,7 +1829,7 @@
      */
     public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
         final SurfaceControl lastSc = mSurfacePackage != null ?
-            mSurfacePackage.getSurfaceControl() : null;
+                mSurfacePackage.getSurfaceControl() : null;
         if (mSurfaceControl != null && lastSc != null) {
             mTmpTransaction.reparent(lastSc, null).apply();
             mSurfacePackage.release();
@@ -1839,8 +1842,11 @@
 
     private void reparentSurfacePackage(SurfaceControl.Transaction t,
             SurfaceControlViewHost.SurfacePackage p) {
-        initEmbeddedHierarchyForAccessibility(p);
         final SurfaceControl sc = p.getSurfaceControl();
+        if (sc == null || !sc.isValid()) {
+            return;
+        }
+        initEmbeddedHierarchyForAccessibility(p);
         final SurfaceControl parent;
         if (mUseBlastAdapter) {
             parent = mBlastSurfaceControl;
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 7d222db..42a58fb 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -220,7 +220,13 @@
             }
         }
 
-        public void dispatchOnExitAnimation(IBinder token, SplashScreenView view) {
+        public void handOverSplashScreenView(@NonNull IBinder token,
+                @NonNull SplashScreenView splashScreenView) {
+            transferSurface(splashScreenView);
+            dispatchOnExitAnimation(token, splashScreenView);
+        }
+
+        private void dispatchOnExitAnimation(IBinder token, SplashScreenView view) {
             synchronized (mGlobalLock) {
                 final SplashScreenImpl impl = findImpl(token);
                 if (impl == null) {
@@ -240,5 +246,9 @@
                 return impl != null && impl.mExitAnimationListener != null;
             }
         }
+
+        private void transferSurface(@NonNull SplashScreenView splashScreenView) {
+            splashScreenView.transferSurface();
+        }
     }
 }
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 6d7163909..000dfb2 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -30,6 +30,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -38,13 +39,17 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowInsetsController;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
 
 import com.android.internal.R;
 import com.android.internal.policy.DecorView;
@@ -92,6 +97,14 @@
 
     // The host activity when transfer view to it.
     private Activity mHostActivity;
+
+    @Nullable
+    private SurfaceControlViewHost.SurfacePackage mSurfacePackageCopy;
+    @Nullable
+    private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+    @Nullable
+    private SurfaceView mSurfaceView;
+
     // cache original window and status
     private Window mWindow;
     private int mAppWindowFlags;
@@ -114,6 +127,7 @@
         private @ColorInt int mIconBackground;
         private Bitmap mParceledIconBitmap;
         private Drawable mIconDrawable;
+        private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
         private int mBrandingImageWidth;
         private int mBrandingImageHeight;
         private Drawable mBrandingDrawable;
@@ -133,7 +147,10 @@
             mIconSize = parcelable.getIconSize();
             mBackgroundColor = parcelable.getBackgroundColor();
             mIconBackground = parcelable.getIconBackground();
-            if (parcelable.mIconBitmap != null) {
+            mSurfacePackage = parcelable.mSurfacePackage;
+            if (mSurfacePackage == null && parcelable.mIconBitmap != null) {
+                // We only create a Bitmap copies of immobile icons since animated icon are using
+                // a surface view
                 mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap);
                 mParceledIconBitmap = parcelable.mIconBitmap;
             }
@@ -145,6 +162,9 @@
             }
             mIconAnimationStart = Instant.ofEpochMilli(parcelable.mIconAnimationStartMillis);
             mIconAnimationDuration = Duration.ofMillis(parcelable.mIconAnimationDurationMillis);
+            if (DEBUG) {
+                Log.d(TAG, String.format("Building from parcel drawable: %s", mIconDrawable));
+            }
             return this;
         }
 
@@ -167,7 +187,7 @@
         /**
          * Set the Drawable object to fill the center view.
          */
-        public Builder setCenterViewDrawable(Drawable drawable) {
+        public Builder setCenterViewDrawable(@Nullable Drawable drawable) {
             mIconDrawable = drawable;
             return this;
         }
@@ -191,7 +211,7 @@
         /**
          * Set the Drawable object and size for the branding view.
          */
-        public Builder setBrandingDrawable(Drawable branding, int width, int height) {
+        public Builder setBrandingDrawable(@Nullable Drawable branding, int width, int height) {
             mBrandingDrawable = branding;
             mBrandingImageWidth = width;
             mBrandingImageHeight = height;
@@ -209,22 +229,30 @@
             view.mInitBackgroundColor = mBackgroundColor;
             view.mInitIconBackgroundColor = mIconBackground;
             view.setBackgroundColor(mBackgroundColor);
-            view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
+
             view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view);
+
             // center icon
-            if (mIconSize != 0) {
-                final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
-                params.width = mIconSize;
-                params.height = mIconSize;
-                view.mIconView.setLayoutParams(params);
-            }
-            if (mIconDrawable != null) {
-                view.mIconView.setBackground(mIconDrawable);
+            if (mIconDrawable instanceof SplashScreenView.IconAnimateListener
+                    || mSurfacePackage != null) {
+                view.mIconView = createSurfaceView(view);
                 view.initIconAnimation(mIconDrawable,
                         mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
+                view.mIconAnimationStart = mIconAnimationStart;
+                view.mIconAnimationDuration = mIconAnimationDuration;
+            } else {
+                view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
+                if (mIconSize != 0) {
+                    final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
+                    params.width = mIconSize;
+                    params.height = mIconSize;
+                    view.mIconView.setLayoutParams(params);
+                    if (mIconDrawable != null) {
+                        view.mIconView.setBackground(mIconDrawable);
+                    }
+                }
             }
-            view.mIconAnimationStart = mIconAnimationStart;
-            view.mIconAnimationDuration = mIconAnimationDuration;
+
             if (mParceledIconBitmap != null) {
                 view.mParceledIconBitmap = mParceledIconBitmap;
             }
@@ -242,14 +270,60 @@
                 view.mParceledBrandingBitmap = mParceledBrandingBitmap;
             }
             if (DEBUG) {
-                Log.d(TAG, " build " + view + " Icon: view: " + view.mIconView + " drawable: "
-                        + mIconDrawable + " size: " + mIconSize + "\n Branding: view: "
-                        + view.mBrandingImageView + " drawable: " + mBrandingDrawable
-                        + " size w: " + mBrandingImageWidth + " h: " + mBrandingImageHeight);
+                Log.d(TAG, "Build " + view
+                        + "\nIcon: view: " + view.mIconView + " drawable: "
+                        + mIconDrawable + " size: " + mIconSize
+                        + "\nBranding: view: " + view.mBrandingImageView + " drawable: "
+                        + mBrandingDrawable + " size w: " + mBrandingImageWidth + " h: "
+                        + mBrandingImageHeight);
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return view;
         }
+
+        private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
+            final SurfaceView surfaceView = new SurfaceView(view.getContext());
+            if (mSurfacePackage == null) {
+                if (DEBUG) {
+                    Log.d(TAG,
+                            "Creating Original SurfacePackage. SurfaceView: " + surfaceView);
+                }
+
+                SurfaceControlViewHost viewHost = new SurfaceControlViewHost(mContext,
+                        mContext.getDisplay(),
+                        surfaceView.getHostToken());
+                ImageView imageView = new ImageView(mContext);
+                imageView.setBackground(mIconDrawable);
+                viewHost.setView(imageView, mIconSize, mIconSize);
+                SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage();
+                surfaceView.setChildSurfacePackage(surfacePackage);
+                view.mSurfacePackage = surfacePackage;
+                view.mSurfacePackageCopy = new SurfaceControlViewHost.SurfacePackage(
+                        surfacePackage);
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "Using copy of SurfacePackage in the client");
+                }
+                view.mSurfacePackage = mSurfacePackage;
+            }
+            if (mIconSize != 0) {
+                LayoutParams lp = new FrameLayout.LayoutParams(mIconSize, mIconSize);
+                lp.gravity = Gravity.CENTER;
+                surfaceView.setLayoutParams(lp);
+                if (DEBUG) {
+                    Log.d(TAG, "Icon size " + mIconSize);
+                }
+            }
+
+            // We ensure that we can blend the alpha of the surface view with the SplashScreenView
+            surfaceView.setUseAlpha();
+            surfaceView.setZOrderOnTop(true);
+            surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+
+            view.addView(surfaceView);
+            view.mSurfaceView = surfaceView;
+            return surfaceView;
+        }
     }
 
     /** @hide */
@@ -298,6 +372,35 @@
     }
 
     /**
+     * Called when this {@link SplashScreenView} has been copied to be transferred to the client.
+     *
+     * @hide
+     */
+    public void onCopied() {
+        if (mSurfaceView == null) {
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Setting SurfaceView's SurfacePackage to null.");
+        }
+        // If we don't release the surface package, the surface will be reparented to this
+        // surface view. So once it's copied into the client process, we release it.
+        mSurfacePackage.release();
+        mSurfacePackage = null;
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        super.setAlpha(alpha);
+
+        // The surface view's alpha is not multiplied with the containing view's alpha, so we
+        // manually do it here
+        if (mSurfaceView != null) {
+            mSurfaceView.setAlpha(mSurfaceView.getAlpha() * alpha);
+        }
+    }
+
+    /**
      * Returns the duration of the icon animation if icon is animatable.
      *
      * @see android.R.attr#windowSplashScreenAnimatedIcon
@@ -316,6 +419,22 @@
         return mIconAnimationStart;
     }
 
+
+    void transferSurface() {
+        if (mSurfacePackage == null) {
+            return;
+        }
+        if (DEBUG) {
+            mSurfacePackage.getSurfaceControl().addOnReparentListener(
+                    (transaction, parent) -> Log.e(TAG,
+                            String.format("SurfacePackage'surface reparented.\n Parent: %s",
+                                    parent), new Throwable()));
+            Log.d(TAG, "Transferring surface " + mSurfaceView.toString());
+        }
+        mSurfaceView.setChildSurfacePackage(mSurfacePackage);
+
+    }
+
     void initIconAnimation(Drawable iconDrawable, long duration) {
         if (!(iconDrawable instanceof IconAnimateListener)) {
             return;
@@ -477,7 +596,7 @@
         private int mBackgroundColor;
         private int mIconBackground;
 
-        private Bitmap mIconBitmap;
+        private Bitmap mIconBitmap = null;
         private int mBrandingWidth;
         private int mBrandingHeight;
         private Bitmap mBrandingBitmap;
@@ -485,14 +604,20 @@
         private long mIconAnimationStartMillis;
         private long mIconAnimationDurationMillis;
 
+        private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+
         public SplashScreenViewParcelable(SplashScreenView view) {
-            ViewGroup.LayoutParams params = view.getIconView().getLayoutParams();
-            mIconSize = params.height;
+            mIconSize = view.mIconView.getWidth();
             mBackgroundColor = view.getInitBackgroundColor();
             mIconBackground = view.getIconBackgroundColor();
-            mIconBitmap = copyDrawable(view.getIconView().getBackground());
+            mSurfacePackage = view.mSurfacePackageCopy;
+            if (mSurfacePackage == null) {
+                // We only need to copy the drawable if we are not using a SurfaceView
+                mIconBitmap = copyDrawable(view.getIconView().getBackground());
+            }
             mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
-            params = view.getBrandingView().getLayoutParams();
+
+            ViewGroup.LayoutParams params = view.getBrandingView().getLayoutParams();
             mBrandingWidth = params.width;
             mBrandingHeight = params.height;
 
@@ -535,6 +660,7 @@
             mIconAnimationStartMillis = source.readLong();
             mIconAnimationDurationMillis = source.readLong();
             mIconBackground = source.readInt();
+            mSurfacePackage = source.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR);
         }
 
         @Override
@@ -553,6 +679,7 @@
             dest.writeLong(mIconAnimationStartMillis);
             dest.writeLong(mIconAnimationDurationMillis);
             dest.writeInt(mIconBackground);
+            dest.writeTypedObject(mSurfacePackage, flags);
         }
 
         public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index c37e88a..1a03ebd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -375,6 +375,7 @@
         if (preView != null && preView.mContentView != null
                 && preView.mContentView.isCopyable()) {
             parcelable = new SplashScreenViewParcelable(preView.mContentView);
+            preView.mContentView.onCopied();
         } else {
             parcelable = null;
         }