Loading core/java/android/app/Activity.java +0 −12 Original line number Diff line number Diff line Loading @@ -140,7 +140,6 @@ import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; import android.window.SplashScreen; import android.window.SplashScreenView; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -969,7 +968,6 @@ public class Activity extends ContextThemeWrapper private UiTranslationController mUiTranslationController; private SplashScreen mSplashScreen; private SplashScreenView mSplashScreenView; private final WindowControllerCallback mWindowControllerCallback = new WindowControllerCallback() { Loading Loading @@ -1640,16 +1638,6 @@ public class Activity extends ContextThemeWrapper } } /** @hide */ public void setSplashScreenView(SplashScreenView v) { mSplashScreenView = v; } /** @hide */ SplashScreenView getSplashScreenView() { return mSplashScreenView; } /** * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with * the attribute {@link android.R.attr#persistableMode} set to Loading core/java/android/app/ActivityThread.java +37 −47 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ import android.view.Choreographer; import android.view.Display; import android.view.DisplayAdjustments; import android.view.DisplayAdjustments.FixedRotationAdjustments; import android.view.SurfaceControl; import android.view.ThreadedRenderer; import android.view.View; import android.view.ViewDebug; Loading Loading @@ -235,7 +236,6 @@ import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** Loading Loading @@ -4074,10 +4074,11 @@ public final class ActivityThread extends ClientTransactionHandler @Override public void handleAttachSplashScreenView(@NonNull ActivityClientRecord r, @Nullable SplashScreenView.SplashScreenViewParcelable parcelable) { @Nullable SplashScreenView.SplashScreenViewParcelable parcelable, @NonNull SurfaceControl startingWindowLeash) { final DecorView decorView = (DecorView) r.window.peekDecorView(); if (parcelable != null && decorView != null) { createSplashScreen(r, decorView, parcelable); createSplashScreen(r, decorView, parcelable, startingWindowLeash); } else { // shouldn't happen! Slog.e(TAG, "handleAttachSplashScreenView failed, unable to attach"); Loading @@ -4085,61 +4086,50 @@ public final class ActivityThread extends ClientTransactionHandler } private void createSplashScreen(ActivityClientRecord r, DecorView decorView, SplashScreenView.SplashScreenViewParcelable parcelable) { SplashScreenView.SplashScreenViewParcelable parcelable, @NonNull SurfaceControl startingWindowLeash) { final SplashScreenView.Builder builder = new SplashScreenView.Builder(r.activity); final SplashScreenView view = builder.createFromParcel(parcelable).build(); decorView.addView(view); view.attachHostActivityAndSetSystemUIColors(r.activity, r.window); view.requestLayout(); // Ensure splash screen view is shown before remove the splash screen window. final ViewRootImpl impl = decorView.getViewRootImpl(); final boolean hardwareEnabled = impl != null && impl.isHardwareEnabled(); final AtomicBoolean notified = new AtomicBoolean(); if (hardwareEnabled) { final Runnable frameCommit = new Runnable() { @Override public void run() { view.post(() -> { if (!notified.get()) { view.getViewTreeObserver().unregisterFrameCommitCallback(this); ActivityClient.getInstance().reportSplashScreenAttached( r.token); notified.set(true); } }); } }; view.getViewTreeObserver().registerFrameCommitCallback(frameCommit); } else { final ViewTreeObserver.OnDrawListener onDrawListener = new ViewTreeObserver.OnDrawListener() { view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() { @Override public void onDraw() { view.post(() -> { if (!notified.get()) { view.getViewTreeObserver().removeOnDrawListener(this); ActivityClient.getInstance().reportSplashScreenAttached( r.token); notified.set(true); // Transfer the splash screen view from shell to client. // Call syncTransferSplashscreenViewTransaction at the first onDraw so we can ensure // the client view is ready to show and we can use applyTransactionOnDraw to make // all transitions happen at the same frame. syncTransferSplashscreenViewTransaction( view, r.token, decorView, startingWindowLeash); view.postOnAnimation(() -> view.getViewTreeObserver().removeOnDrawListener(this)); } }); } }; view.getViewTreeObserver().addOnDrawListener(onDrawListener); } } @Override public void handOverSplashScreenView(@NonNull ActivityClientRecord r) { final SplashScreenView v = r.activity.getSplashScreenView(); if (v == null) { return; } private void reportSplashscreenViewShown(IBinder token, SplashScreenView view) { ActivityClient.getInstance().reportSplashScreenAttached(token); synchronized (this) { if (mSplashScreenGlobal != null) { mSplashScreenGlobal.handOverSplashScreenView(r.token, v); mSplashScreenGlobal.handOverSplashScreenView(token, view); } } } private void syncTransferSplashscreenViewTransaction(SplashScreenView view, IBinder token, View decorView, @NonNull SurfaceControl startingWindowLeash) { // Ensure splash screen view is shown before remove the splash screen window. // Once the copied splash screen view is onDrawn on decor view, use applyTransactionOnDraw // to ensure the transfer of surface view and hide starting window are happen at the same // frame. final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); transaction.hide(startingWindowLeash); decorView.getViewRootImpl().applyTransactionOnDraw(transaction); view.syncTransferSurfaceOnDraw(); // Tell server we can remove the starting window decorView.postOnAnimation(() -> reportSplashscreenViewShown(token, view)); } /** Loading core/java/android/app/ClientTransactionHandler.java +3 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import android.view.DisplayAdjustments.FixedRotationAdjustments; import android.view.SurfaceControl; import android.window.SplashScreenView.SplashScreenViewParcelable; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -165,10 +166,8 @@ public abstract class ClientTransactionHandler { /** Attach a splash screen window view to the top of the activity */ public abstract void handleAttachSplashScreenView(@NonNull ActivityClientRecord r, @NonNull SplashScreenViewParcelable parcelable); /** Hand over the splash screen window view to the activity */ public abstract void handOverSplashScreenView(@NonNull ActivityClientRecord r); @NonNull SplashScreenViewParcelable parcelable, @NonNull SurfaceControl startingWindowLeash); /** Perform activity launch. */ public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r, Loading core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java +9 −29 Original line number Diff line number Diff line Loading @@ -16,17 +16,14 @@ package android.app.servertransaction; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.app.ClientTransactionHandler; import android.os.Parcel; import android.view.SurfaceControl; import android.window.SplashScreenView.SplashScreenViewParcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Transfer a splash screen view to an Activity. * @hide Loading @@ -34,31 +31,13 @@ import java.lang.annotation.RetentionPolicy; public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { private SplashScreenViewParcelable mSplashScreenViewParcelable; private @TransferRequest int mRequest; @IntDef(value = { ATTACH_TO, HANDOVER_TO }) @Retention(RetentionPolicy.SOURCE) public @interface TransferRequest {} // request client to attach the view on it. public static final int ATTACH_TO = 0; // tell client that you can handle the splash screen view. public static final int HANDOVER_TO = 1; private SurfaceControl mStartingWindowLeash; @Override public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityThread.ActivityClientRecord r, PendingTransactionActions pendingActions) { switch (mRequest) { case ATTACH_TO: client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable); break; case HANDOVER_TO: client.handOverSplashScreenView(r); break; } client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable, mStartingWindowLeash); } @Override Loading @@ -68,26 +47,27 @@ public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mRequest); dest.writeTypedObject(mSplashScreenViewParcelable, flags); dest.writeTypedObject(mStartingWindowLeash, flags); } private TransferSplashScreenViewStateItem() {} private TransferSplashScreenViewStateItem(Parcel in) { mRequest = in.readInt(); mSplashScreenViewParcelable = in.readTypedObject(SplashScreenViewParcelable.CREATOR); mStartingWindowLeash = in.readTypedObject(SurfaceControl.CREATOR); } /** Obtain an instance initialized with provided params. */ public static TransferSplashScreenViewStateItem obtain(@TransferRequest int state, @Nullable SplashScreenViewParcelable parcelable) { public static TransferSplashScreenViewStateItem obtain( @Nullable SplashScreenViewParcelable parcelable, @Nullable SurfaceControl startingWindowLeash) { TransferSplashScreenViewStateItem instance = ObjectPool.obtain(TransferSplashScreenViewStateItem.class); if (instance == null) { instance = new TransferSplashScreenViewStateItem(); } instance.mRequest = state; instance.mSplashScreenViewParcelable = parcelable; instance.mStartingWindowLeash = startingWindowLeash; return instance; } Loading core/java/android/view/SurfaceView.java +29 −2 Original line number Diff line number Diff line Loading @@ -1889,18 +1889,45 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * @param p The SurfacePackage to embed. */ public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) { setChildSurfacePackage(p, false /* applyTransactionOnDraw */); } /** * Similar to setChildSurfacePackage, but using the BLAST queue so the transaction can be * synchronized with the ViewRootImpl frame. * @hide */ public void setChildSurfacePackageOnDraw( @NonNull SurfaceControlViewHost.SurfacePackage p) { setChildSurfacePackage(p, true /* applyTransactionOnDraw */); } /** * @param applyTransactionOnDraw Whether to apply transaction at onDraw or immediately. */ private void setChildSurfacePackage( @NonNull SurfaceControlViewHost.SurfacePackage p, boolean applyTransactionOnDraw) { final SurfaceControl lastSc = mSurfacePackage != null ? mSurfacePackage.getSurfaceControl() : null; if (mSurfaceControl != null && lastSc != null) { mTmpTransaction.reparent(lastSc, null).apply(); mTmpTransaction.reparent(lastSc, null); mSurfacePackage.release(); applyTransaction(applyTransactionOnDraw); } else if (mSurfaceControl != null) { reparentSurfacePackage(mTmpTransaction, p); mTmpTransaction.apply(); applyTransaction(applyTransactionOnDraw); } mSurfacePackage = p; } private void applyTransaction(boolean applyTransactionOnDraw) { if (applyTransactionOnDraw) { getViewRootImpl().applyTransactionOnDraw(mTmpTransaction); } else { mTmpTransaction.apply(); } } private void reparentSurfacePackage(SurfaceControl.Transaction t, SurfaceControlViewHost.SurfacePackage p) { final SurfaceControl sc = p.getSurfaceControl(); Loading Loading
core/java/android/app/Activity.java +0 −12 Original line number Diff line number Diff line Loading @@ -140,7 +140,6 @@ import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; import android.window.SplashScreen; import android.window.SplashScreenView; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -969,7 +968,6 @@ public class Activity extends ContextThemeWrapper private UiTranslationController mUiTranslationController; private SplashScreen mSplashScreen; private SplashScreenView mSplashScreenView; private final WindowControllerCallback mWindowControllerCallback = new WindowControllerCallback() { Loading Loading @@ -1640,16 +1638,6 @@ public class Activity extends ContextThemeWrapper } } /** @hide */ public void setSplashScreenView(SplashScreenView v) { mSplashScreenView = v; } /** @hide */ SplashScreenView getSplashScreenView() { return mSplashScreenView; } /** * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with * the attribute {@link android.R.attr#persistableMode} set to Loading
core/java/android/app/ActivityThread.java +37 −47 Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ import android.view.Choreographer; import android.view.Display; import android.view.DisplayAdjustments; import android.view.DisplayAdjustments.FixedRotationAdjustments; import android.view.SurfaceControl; import android.view.ThreadedRenderer; import android.view.View; import android.view.ViewDebug; Loading Loading @@ -235,7 +236,6 @@ import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** Loading Loading @@ -4074,10 +4074,11 @@ public final class ActivityThread extends ClientTransactionHandler @Override public void handleAttachSplashScreenView(@NonNull ActivityClientRecord r, @Nullable SplashScreenView.SplashScreenViewParcelable parcelable) { @Nullable SplashScreenView.SplashScreenViewParcelable parcelable, @NonNull SurfaceControl startingWindowLeash) { final DecorView decorView = (DecorView) r.window.peekDecorView(); if (parcelable != null && decorView != null) { createSplashScreen(r, decorView, parcelable); createSplashScreen(r, decorView, parcelable, startingWindowLeash); } else { // shouldn't happen! Slog.e(TAG, "handleAttachSplashScreenView failed, unable to attach"); Loading @@ -4085,61 +4086,50 @@ public final class ActivityThread extends ClientTransactionHandler } private void createSplashScreen(ActivityClientRecord r, DecorView decorView, SplashScreenView.SplashScreenViewParcelable parcelable) { SplashScreenView.SplashScreenViewParcelable parcelable, @NonNull SurfaceControl startingWindowLeash) { final SplashScreenView.Builder builder = new SplashScreenView.Builder(r.activity); final SplashScreenView view = builder.createFromParcel(parcelable).build(); decorView.addView(view); view.attachHostActivityAndSetSystemUIColors(r.activity, r.window); view.requestLayout(); // Ensure splash screen view is shown before remove the splash screen window. final ViewRootImpl impl = decorView.getViewRootImpl(); final boolean hardwareEnabled = impl != null && impl.isHardwareEnabled(); final AtomicBoolean notified = new AtomicBoolean(); if (hardwareEnabled) { final Runnable frameCommit = new Runnable() { @Override public void run() { view.post(() -> { if (!notified.get()) { view.getViewTreeObserver().unregisterFrameCommitCallback(this); ActivityClient.getInstance().reportSplashScreenAttached( r.token); notified.set(true); } }); } }; view.getViewTreeObserver().registerFrameCommitCallback(frameCommit); } else { final ViewTreeObserver.OnDrawListener onDrawListener = new ViewTreeObserver.OnDrawListener() { view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() { @Override public void onDraw() { view.post(() -> { if (!notified.get()) { view.getViewTreeObserver().removeOnDrawListener(this); ActivityClient.getInstance().reportSplashScreenAttached( r.token); notified.set(true); // Transfer the splash screen view from shell to client. // Call syncTransferSplashscreenViewTransaction at the first onDraw so we can ensure // the client view is ready to show and we can use applyTransactionOnDraw to make // all transitions happen at the same frame. syncTransferSplashscreenViewTransaction( view, r.token, decorView, startingWindowLeash); view.postOnAnimation(() -> view.getViewTreeObserver().removeOnDrawListener(this)); } }); } }; view.getViewTreeObserver().addOnDrawListener(onDrawListener); } } @Override public void handOverSplashScreenView(@NonNull ActivityClientRecord r) { final SplashScreenView v = r.activity.getSplashScreenView(); if (v == null) { return; } private void reportSplashscreenViewShown(IBinder token, SplashScreenView view) { ActivityClient.getInstance().reportSplashScreenAttached(token); synchronized (this) { if (mSplashScreenGlobal != null) { mSplashScreenGlobal.handOverSplashScreenView(r.token, v); mSplashScreenGlobal.handOverSplashScreenView(token, view); } } } private void syncTransferSplashscreenViewTransaction(SplashScreenView view, IBinder token, View decorView, @NonNull SurfaceControl startingWindowLeash) { // Ensure splash screen view is shown before remove the splash screen window. // Once the copied splash screen view is onDrawn on decor view, use applyTransactionOnDraw // to ensure the transfer of surface view and hide starting window are happen at the same // frame. final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); transaction.hide(startingWindowLeash); decorView.getViewRootImpl().applyTransactionOnDraw(transaction); view.syncTransferSurfaceOnDraw(); // Tell server we can remove the starting window decorView.postOnAnimation(() -> reportSplashscreenViewShown(token, view)); } /** Loading
core/java/android/app/ClientTransactionHandler.java +3 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import android.view.DisplayAdjustments.FixedRotationAdjustments; import android.view.SurfaceControl; import android.window.SplashScreenView.SplashScreenViewParcelable; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -165,10 +166,8 @@ public abstract class ClientTransactionHandler { /** Attach a splash screen window view to the top of the activity */ public abstract void handleAttachSplashScreenView(@NonNull ActivityClientRecord r, @NonNull SplashScreenViewParcelable parcelable); /** Hand over the splash screen window view to the activity */ public abstract void handOverSplashScreenView(@NonNull ActivityClientRecord r); @NonNull SplashScreenViewParcelable parcelable, @NonNull SurfaceControl startingWindowLeash); /** Perform activity launch. */ public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r, Loading
core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java +9 −29 Original line number Diff line number Diff line Loading @@ -16,17 +16,14 @@ package android.app.servertransaction; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.app.ClientTransactionHandler; import android.os.Parcel; import android.view.SurfaceControl; import android.window.SplashScreenView.SplashScreenViewParcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Transfer a splash screen view to an Activity. * @hide Loading @@ -34,31 +31,13 @@ import java.lang.annotation.RetentionPolicy; public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { private SplashScreenViewParcelable mSplashScreenViewParcelable; private @TransferRequest int mRequest; @IntDef(value = { ATTACH_TO, HANDOVER_TO }) @Retention(RetentionPolicy.SOURCE) public @interface TransferRequest {} // request client to attach the view on it. public static final int ATTACH_TO = 0; // tell client that you can handle the splash screen view. public static final int HANDOVER_TO = 1; private SurfaceControl mStartingWindowLeash; @Override public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityThread.ActivityClientRecord r, PendingTransactionActions pendingActions) { switch (mRequest) { case ATTACH_TO: client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable); break; case HANDOVER_TO: client.handOverSplashScreenView(r); break; } client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable, mStartingWindowLeash); } @Override Loading @@ -68,26 +47,27 @@ public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mRequest); dest.writeTypedObject(mSplashScreenViewParcelable, flags); dest.writeTypedObject(mStartingWindowLeash, flags); } private TransferSplashScreenViewStateItem() {} private TransferSplashScreenViewStateItem(Parcel in) { mRequest = in.readInt(); mSplashScreenViewParcelable = in.readTypedObject(SplashScreenViewParcelable.CREATOR); mStartingWindowLeash = in.readTypedObject(SurfaceControl.CREATOR); } /** Obtain an instance initialized with provided params. */ public static TransferSplashScreenViewStateItem obtain(@TransferRequest int state, @Nullable SplashScreenViewParcelable parcelable) { public static TransferSplashScreenViewStateItem obtain( @Nullable SplashScreenViewParcelable parcelable, @Nullable SurfaceControl startingWindowLeash) { TransferSplashScreenViewStateItem instance = ObjectPool.obtain(TransferSplashScreenViewStateItem.class); if (instance == null) { instance = new TransferSplashScreenViewStateItem(); } instance.mRequest = state; instance.mSplashScreenViewParcelable = parcelable; instance.mStartingWindowLeash = startingWindowLeash; return instance; } Loading
core/java/android/view/SurfaceView.java +29 −2 Original line number Diff line number Diff line Loading @@ -1889,18 +1889,45 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * @param p The SurfacePackage to embed. */ public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) { setChildSurfacePackage(p, false /* applyTransactionOnDraw */); } /** * Similar to setChildSurfacePackage, but using the BLAST queue so the transaction can be * synchronized with the ViewRootImpl frame. * @hide */ public void setChildSurfacePackageOnDraw( @NonNull SurfaceControlViewHost.SurfacePackage p) { setChildSurfacePackage(p, true /* applyTransactionOnDraw */); } /** * @param applyTransactionOnDraw Whether to apply transaction at onDraw or immediately. */ private void setChildSurfacePackage( @NonNull SurfaceControlViewHost.SurfacePackage p, boolean applyTransactionOnDraw) { final SurfaceControl lastSc = mSurfacePackage != null ? mSurfacePackage.getSurfaceControl() : null; if (mSurfaceControl != null && lastSc != null) { mTmpTransaction.reparent(lastSc, null).apply(); mTmpTransaction.reparent(lastSc, null); mSurfacePackage.release(); applyTransaction(applyTransactionOnDraw); } else if (mSurfaceControl != null) { reparentSurfacePackage(mTmpTransaction, p); mTmpTransaction.apply(); applyTransaction(applyTransactionOnDraw); } mSurfacePackage = p; } private void applyTransaction(boolean applyTransactionOnDraw) { if (applyTransactionOnDraw) { getViewRootImpl().applyTransactionOnDraw(mTmpTransaction); } else { mTmpTransaction.apply(); } } private void reparentSurfacePackage(SurfaceControl.Transaction t, SurfaceControlViewHost.SurfacePackage p) { final SurfaceControl sc = p.getSurfaceControl(); Loading