Making AsyncClockEventDelegate a singleton

RemoteViews can get inflated after the activity is destroyed during
async inflation. This can cause the delegate to loose the destroy event.

Bug: 303686041
Test: Presubmit
Flag: N/A
Change-Id: Iecb9d69d95b2c924e1189ac15515fac327d8f44d
This commit is contained in:
Sunny Goyal
2023-10-05 13:22:17 -07:00
parent cfaba6e814
commit df178f5320
2 changed files with 15 additions and 20 deletions
@@ -218,8 +218,6 @@ public class QuickstepLauncher extends Launcher {
private SplitWithKeyboardShortcutController mSplitWithKeyboardShortcutController;
private SplitToWorkspaceController mSplitToWorkspaceController;
private AsyncClockEventDelegate mAsyncClockEventDelegate;
/**
* If Launcher restarted while in the middle of an Overview split select, it needs this data to
* recover. In all other cases this will remain null.
@@ -497,10 +495,6 @@ public class QuickstepLauncher extends Launcher {
mSplitSelectStateController.onDestroy();
}
if (mAsyncClockEventDelegate != null) {
mAsyncClockEventDelegate.onDestroy();
}
super.onDestroy();
mHotseatPredictionController.destroy();
mSplitWithKeyboardShortcutController.onDestroy();
@@ -1346,18 +1340,12 @@ public class QuickstepLauncher extends Launcher {
switch (name) {
case "TextClock", "android.widget.TextClock" -> {
TextClock tc = new TextClock(context, attrs);
if (mAsyncClockEventDelegate == null) {
mAsyncClockEventDelegate = new AsyncClockEventDelegate(this);
}
tc.setClockEventDelegate(mAsyncClockEventDelegate);
tc.setClockEventDelegate(AsyncClockEventDelegate.INSTANCE.get(this));
return tc;
}
case "AnalogClock", "android.widget.AnalogClock" -> {
AnalogClock ac = new AnalogClock(context, attrs);
if (mAsyncClockEventDelegate == null) {
mAsyncClockEventDelegate = new AsyncClockEventDelegate(this);
}
ac.setClockEventDelegate(mAsyncClockEventDelegate);
ac.setClockEventDelegate(AsyncClockEventDelegate.INSTANCE.get(this));
return ac;
}
}
@@ -32,6 +32,8 @@ import android.widget.TextClock.ClockEventDelegate;
import androidx.annotation.WorkerThread;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SettingsCache.OnChangeListener;
import com.android.launcher3.util.SimpleBroadcastReceiver;
@@ -42,7 +44,11 @@ import java.util.List;
/**
* Extension of {@link ClockEventDelegate} to support async event registration
*/
public class AsyncClockEventDelegate extends ClockEventDelegate implements OnChangeListener {
public class AsyncClockEventDelegate extends ClockEventDelegate
implements OnChangeListener, SafeCloseable {
public static final MainThreadInitializedObject<AsyncClockEventDelegate> INSTANCE =
new MainThreadInitializedObject<>(AsyncClockEventDelegate::new);
private final Context mContext;
private final SimpleBroadcastReceiver mReceiver =
@@ -55,7 +61,7 @@ public class AsyncClockEventDelegate extends ClockEventDelegate implements OnCha
private boolean mFormatRegistered = false;
private boolean mDestroyed = false;
public AsyncClockEventDelegate(Context context) {
private AsyncClockEventDelegate(Context context) {
super(context);
mContext = context;
@@ -79,6 +85,9 @@ public class AsyncClockEventDelegate extends ClockEventDelegate implements OnCha
@Override
public void registerFormatChangeObserver(ContentObserver observer, int userHandle) {
if (mDestroyed) {
return;
}
synchronized (mFormatObservers) {
if (!mFormatRegistered && !mDestroyed) {
SettingsCache.INSTANCE.get(mContext).register(mFormatUri, this);
@@ -114,10 +123,8 @@ public class AsyncClockEventDelegate extends ClockEventDelegate implements OnCha
}
}
/**
* Unregisters all system callbacks and destroys this delegate
*/
public void onDestroy() {
@Override
public void close() {
mDestroyed = true;
SettingsCache.INSTANCE.get(mContext).unregister(mFormatUri, this);
UI_HELPER_EXECUTOR.execute(() -> mReceiver.unregisterReceiverSafely(mContext));