From 87c7caa4556d0b5c6342fed1c0913874a2449c49 Mon Sep 17 00:00:00 2001 From: Robert Horvath Date: Fri, 29 Apr 2022 17:09:17 +0200 Subject: [PATCH] Finish DreamActivity on creation if it is obsolete DreamService keeps a reference to its DreamActivity, and finishes it when the dream stops. This reference is set when the DreamActivity receives its onCreate lifecycle callback. If a dream is stopped shortly after it started, before its DreamActivity was created, the DreamActivity can be created after the dream is supposed to be finished, and finish isn't called on the activity. If another dream starts another DreamActivity, the reference to the old DreamActivity is overwritten and lost, so that DreamService can no longer finish the old DreamActivity. This change tracks the DreamToken, unique to each dream, that an activity was started for. If an activity is created for a dream that is already finished, the activity is finished immediately. Bug: 229561570 Test: manual, with adding delay before startDreamActivity to ease reproduction Change-Id: I0fca226855ee4e2317ac807a4c87c8656c72169b --- .../android/service/dreams/DreamActivity.java | 5 +-- .../android/service/dreams/DreamService.java | 36 ++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java index cf4e6a6da96e0..bf64d06d4ff04 100644 --- a/core/java/android/service/dreams/DreamActivity.java +++ b/core/java/android/service/dreams/DreamActivity.java @@ -58,8 +58,9 @@ public class DreamActivity extends Activity { setTitle(title); } - DreamService.DreamServiceWrapper callback = - (DreamService.DreamServiceWrapper) getIntent().getIBinderExtra(EXTRA_CALLBACK); + final Bundle extras = getIntent().getExtras(); + final DreamService.DreamActivityCallback callback = + (DreamService.DreamActivityCallback) extras.getBinder(EXTRA_CALLBACK); if (callback != null) { callback.onActivityCreated(this); diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 6a9afdb84e188..9d5253b1dbf78 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -36,6 +36,7 @@ import android.content.pm.ServiceInfo; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; +import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -1264,7 +1265,7 @@ public class DreamService extends Service implements Window.Callback { Intent i = new Intent(this, DreamActivity.class); i.setPackage(getApplicationContext().getPackageName()); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper); + i.putExtra(DreamActivity.EXTRA_CALLBACK, new DreamActivityCallback(mDreamToken)); final ServiceInfo serviceInfo = fetchServiceInfo(this, new ComponentName(this, getClass())); i.putExtra(DreamActivity.EXTRA_DREAM_TITLE, fetchDreamLabel(this, serviceInfo)); @@ -1444,11 +1445,36 @@ public class DreamService extends Service implements Window.Callback { public void wakeUp() { mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/)); } + } - /** @hide */ - void onActivityCreated(DreamActivity a) { - mActivity = a; - onWindowCreated(a.getWindow()); + /** @hide */ + final class DreamActivityCallback extends Binder { + private final IBinder mActivityDreamToken; + + DreamActivityCallback(IBinder token) { + mActivityDreamToken = token; + } + + void onActivityCreated(DreamActivity activity) { + if (mActivityDreamToken != mDreamToken || mFinished) { + Slog.d(TAG, "DreamActivity was created after the dream was finished or " + + "a new dream started, finishing DreamActivity"); + if (!activity.isFinishing()) { + activity.finishAndRemoveTask(); + } + return; + } + if (mActivity != null) { + Slog.w(TAG, "A DreamActivity has already been started, " + + "finishing latest DreamActivity"); + if (!activity.isFinishing()) { + activity.finishAndRemoveTask(); + } + return; + } + + mActivity = activity; + onWindowCreated(activity.getWindow()); } }