From 1b26bb4a74f95888fef45caadfa9fa99f5873ff9 Mon Sep 17 00:00:00 2001 From: Adnan Begovic Date: Tue, 11 Feb 2025 16:03:45 -0800 Subject: [PATCH] launcher3: Improve SimpleBroadcastReceiver. Unless explicitly annotated, parameters in java are by default nullable. There are a few cases where a null context may be passed to the unregisterReceiverSafely function of SimpleBroadcastReceiver. To mitigate misuses or incorrect contexts being passed for register vs unregister, keep the context as a strong reference in the constructor. Also added NonNull annotations for any public callsites to enforce behavior. Bug: 395019017, 395966395 Flag: NONE - bug fixed Test: manual - presubmit Change-Id: Ie371fa45cadceaf51cf184b446df9123ef27c337 --- .../launcher3/model/WellbeingModel.java | 8 +-- .../launcher3/taskbar/TaskbarManager.java | 21 +++--- .../quickstep/OverviewComponentObserver.java | 24 +++---- .../util/AsyncClockEventDelegate.java | 9 +-- .../util/ContextualSearchStateManager.java | 10 +-- .../launcher3/InvariantDeviceProfile.java | 6 +- .../android/launcher3/LauncherAppState.java | 7 +- .../launcher3/graphics/ThemeManager.kt | 6 +- src/com/android/launcher3/pm/UserCache.java | 12 ++-- .../launcher3/util/DisplayController.java | 12 ++-- .../android/launcher3/util/LockedUserState.kt | 7 +- .../launcher3/util/ScreenOnTracker.java | 9 +-- .../util/SimpleBroadcastReceiver.java | 64 ++++++++++--------- .../util/WallpaperOffsetInterpolator.java | 10 +-- .../launcher3/util/ScreenOnTrackerTest.kt | 4 +- .../util/SimpleBroadcastReceiverTest.kt | 22 ++++--- 16 files changed, 118 insertions(+), 113 deletions(-) diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java index 0f3aaa6fa7..09433c51a3 100644 --- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java +++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java @@ -109,9 +109,9 @@ public final class WellbeingModel implements SafeCloseable { ? Executors.UI_HELPER_EXECUTOR.getLooper() : Executors.getPackageExecutor(mWellbeingProviderPkg).getLooper()); mWellbeingAppChangeReceiver = - new SimpleBroadcastReceiver(mWorkerHandler, t -> restartObserver()); + new SimpleBroadcastReceiver(context, mWorkerHandler, t -> restartObserver()); mAppAddRemoveReceiver = - new SimpleBroadcastReceiver(mWorkerHandler, this::onAppPackageChanged); + new SimpleBroadcastReceiver(context, mWorkerHandler, this::onAppPackageChanged); mContentObserver = new ContentObserver(mWorkerHandler) { @@ -148,8 +148,8 @@ public final class WellbeingModel implements SafeCloseable { public void close() { if (!TextUtils.isEmpty(mWellbeingProviderPkg)) { mWorkerHandler.post(() -> { - mWellbeingAppChangeReceiver.unregisterReceiverSafely(mContext); - mAppAddRemoveReceiver.unregisterReceiverSafely(mContext); + mWellbeingAppChangeReceiver.unregisterReceiverSafely(); + mAppAddRemoveReceiver.unregisterReceiverSafely(); mContext.getContentResolver().unregisterContentObserver(mContentObserver); }); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index df3869ee5c..96bcffd487 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -124,8 +124,7 @@ public class TaskbarManager { private final TaskbarNavButtonController mDefaultNavButtonController; private final ComponentCallbacks mDefaultComponentCallbacks; - private final SimpleBroadcastReceiver mShutdownReceiver = - new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> destroyAllTaskbars()); + private final SimpleBroadcastReceiver mShutdownReceiver; // The source for this provider is set when Launcher is available // We use 'non-destroyable' version here so the original provider won't be destroyed @@ -183,8 +182,7 @@ public class TaskbarManager { private boolean mUserUnlocked = false; - private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver = - new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, this::showTaskbarFromBroadcast); + private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver; private final AllAppsActionManager mAllAppsActionManager; private final RecentsDisplayModel mRecentsDisplayModel; @@ -266,7 +264,13 @@ public class TaskbarManager { .register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener); Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor."); mPrimaryWindowContext.registerComponentCallbacks(mDefaultComponentCallbacks); - mShutdownReceiver.register(mPrimaryWindowContext, Intent.ACTION_SHUTDOWN); + mShutdownReceiver = + new SimpleBroadcastReceiver( + mPrimaryWindowContext, UI_HELPER_EXECUTOR, i -> destroyAllTaskbars()); + mTaskbarBroadcastReceiver = + new SimpleBroadcastReceiver(mPrimaryWindowContext, + UI_HELPER_EXECUTOR, this::showTaskbarFromBroadcast); + mShutdownReceiver.register(Intent.ACTION_SHUTDOWN); UI_HELPER_EXECUTOR.execute(() -> { mSharedState.taskbarSystemActionPendingIntent = PendingIntent.getBroadcast( mPrimaryWindowContext, @@ -274,8 +278,7 @@ public class TaskbarManager { new Intent(ACTION_SHOW_TASKBAR).setPackage( mPrimaryWindowContext.getPackageName()), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - mTaskbarBroadcastReceiver.register( - mPrimaryWindowContext, RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR); + mTaskbarBroadcastReceiver.register(RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR); }); debugWhyTaskbarNotDestroyed("TaskbarManager created"); @@ -795,7 +798,7 @@ public class TaskbarManager { mRecentsViewContainer = null; debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()"); removeActivityCallbacksAndListeners(); - mTaskbarBroadcastReceiver.unregisterReceiverSafely(mPrimaryWindowContext); + mTaskbarBroadcastReceiver.unregisterReceiverSafely(); if (mUserUnlocked) { DisplayController.INSTANCE.get(mPrimaryWindowContext).removeChangeListener( @@ -807,7 +810,7 @@ public class TaskbarManager { .unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener); Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy()."); mPrimaryWindowContext.unregisterComponentCallbacks(mDefaultComponentCallbacks); - mShutdownReceiver.unregisterReceiverSafely(mPrimaryWindowContext); + mShutdownReceiver.unregisterReceiverSafely(); destroyAllTaskbars(); } diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java index 1f95c41809..bc3de41aae 100644 --- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java +++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java @@ -72,12 +72,9 @@ public final class OverviewComponentObserver { new DaggerSingletonObject<>(LauncherAppComponent::getOverviewComponentObserver); // We register broadcast receivers on main thread to avoid missing updates. - private final SimpleBroadcastReceiver mUserPreferenceChangeReceiver = - new SimpleBroadcastReceiver(MAIN_EXECUTOR, this::updateOverviewTargets); - private final SimpleBroadcastReceiver mOtherHomeAppUpdateReceiver = - new SimpleBroadcastReceiver(MAIN_EXECUTOR, this::updateOverviewTargets); + private final SimpleBroadcastReceiver mUserPreferenceChangeReceiver; + private final SimpleBroadcastReceiver mOtherHomeAppUpdateReceiver; - private final Context mContext; private final RecentsDisplayModel mRecentsDisplayModel; private final Intent mCurrentHomeIntent; @@ -101,10 +98,13 @@ public final class OverviewComponentObserver { @ApplicationContext Context context, RecentsDisplayModel recentsDisplayModel, DaggerSingletonTracker lifecycleTracker) { - mContext = context; + mUserPreferenceChangeReceiver = + new SimpleBroadcastReceiver(context, MAIN_EXECUTOR, this::updateOverviewTargets); + mOtherHomeAppUpdateReceiver = + new SimpleBroadcastReceiver(context, MAIN_EXECUTOR, this::updateOverviewTargets); mRecentsDisplayModel = recentsDisplayModel; mCurrentHomeIntent = createHomeIntent(); - mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(mContext.getPackageName()); + mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(context.getPackageName()); ResolveInfo info = context.getPackageManager().resolveActivity(mMyHomeIntent, 0); ComponentName myHomeComponent = new ComponentName(context.getPackageName(), info.activityInfo.name); @@ -112,7 +112,7 @@ public final class OverviewComponentObserver { mConfigChangesMap.append(myHomeComponent.hashCode(), info.activityInfo.configChanges); mSetupWizardPkg = context.getString(R.string.setup_wizard_pkg); - ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class); + ComponentName fallbackComponent = new ComponentName(context, RecentsActivity.class); mFallbackIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(fallbackComponent) @@ -124,7 +124,7 @@ public final class OverviewComponentObserver { mConfigChangesMap.append(fallbackComponent.hashCode(), fallbackInfo.configChanges); } catch (PackageManager.NameNotFoundException ignored) { /* Impossible */ } - mUserPreferenceChangeReceiver.register(mContext, ACTION_PREFERRED_ACTIVITY_CHANGED); + mUserPreferenceChangeReceiver.register(ACTION_PREFERRED_ACTIVITY_CHANGED); updateOverviewTargets(); lifecycleTracker.addCloseable(this::onDestroy); @@ -224,7 +224,7 @@ public final class OverviewComponentObserver { mUpdateRegisteredPackage = defaultHome.getPackageName(); mOtherHomeAppUpdateReceiver.registerPkgActions( - mContext, mUpdateRegisteredPackage, ACTION_PACKAGE_ADDED, + mUpdateRegisteredPackage, ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REMOVED); } } @@ -235,13 +235,13 @@ public final class OverviewComponentObserver { * Clean up any registered receivers. */ private void onDestroy() { - mUserPreferenceChangeReceiver.unregisterReceiverSafely(mContext); + mUserPreferenceChangeReceiver.unregisterReceiverSafely(); unregisterOtherHomeAppUpdateReceiver(); } private void unregisterOtherHomeAppUpdateReceiver() { if (mUpdateRegisteredPackage != null) { - mOtherHomeAppUpdateReceiver.unregisterReceiverSafely(mContext); + mOtherHomeAppUpdateReceiver.unregisterReceiverSafely(); mUpdateRegisteredPackage = null; } } diff --git a/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java b/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java index 54f6443fa6..207e4825b3 100644 --- a/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java +++ b/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java @@ -59,8 +59,7 @@ public class AsyncClockEventDelegate extends ClockEventDelegate private final Context mContext; private final SettingsCache mSettingsCache; - private final SimpleBroadcastReceiver mReceiver = - new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, this::onClockEventReceived); + private final SimpleBroadcastReceiver mReceiver; private final ArrayMap mTimeEventReceivers = new ArrayMap<>(); private final List mFormatObservers = new ArrayList<>(); @@ -76,7 +75,9 @@ public class AsyncClockEventDelegate extends ClockEventDelegate super(context); mContext = context; mSettingsCache = settingsCache; - mReceiver.register(mContext, ACTION_TIME_CHANGED, ACTION_TIMEZONE_CHANGED); + mReceiver = new SimpleBroadcastReceiver( + context, UI_HELPER_EXECUTOR, this::onClockEventReceived); + mReceiver.register(ACTION_TIME_CHANGED, ACTION_TIMEZONE_CHANGED); tracker.addCloseable(this); } @@ -138,6 +139,6 @@ public class AsyncClockEventDelegate extends ClockEventDelegate public void close() { mDestroyed = true; mSettingsCache.unregister(mFormatUri, this); - mReceiver.unregisterReceiverSafely(mContext); + mReceiver.unregisterReceiverSafely(); } } diff --git a/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java b/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java index ed963999fa..a8d3c6d5a3 100644 --- a/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java +++ b/quickstep/src/com/android/quickstep/util/ContextualSearchStateManager.java @@ -74,8 +74,7 @@ public class ContextualSearchStateManager { Settings.Secure.getUriFor(Settings.Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED); private final Runnable mSysUiStateChangeListener = this::updateOverridesToSysUi; - private final SimpleBroadcastReceiver mContextualSearchPackageReceiver = - new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, (unused) -> requestUpdateProperties()); + private final SimpleBroadcastReceiver mContextualSearchPackageReceiver; protected final EventLogArray mEventLogArray = new EventLogArray(TAG, MAX_DEBUG_EVENT_SIZE); // Cached value whether the ContextualSearch intent filter matched any enabled components. @@ -95,6 +94,9 @@ public class ContextualSearchStateManager { TopTaskTracker topTaskTracker, DaggerSingletonTracker lifeCycle) { mContext = context; + mContextualSearchPackageReceiver = + new SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR, + (unused) -> requestUpdateProperties()); mContextualSearchPackage = mContext.getResources().getString( com.android.internal.R.string.config_defaultContextualSearchPackageName); mSystemUiProxy = systemUiProxy; @@ -112,7 +114,7 @@ public class ContextualSearchStateManager { requestUpdateProperties(); registerSearchScreenSystemAction(); mContextualSearchPackageReceiver.registerPkgActions( - context, mContextualSearchPackage, Intent.ACTION_PACKAGE_ADDED, + mContextualSearchPackage, Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED, Intent.ACTION_PACKAGE_REMOVED); SettingsCache.OnChangeListener settingChangedListener = @@ -124,7 +126,7 @@ public class ContextualSearchStateManager { systemUiProxy.addOnStateChangeListener(mSysUiStateChangeListener); lifeCycle.addCloseable(() -> { - mContextualSearchPackageReceiver.unregisterReceiverSafely(mContext); + mContextualSearchPackageReceiver.unregisterReceiverSafely(); unregisterSearchScreenSystemAction(); settingsCache.unregister(SEARCH_ALL_ENTRYPOINTS_ENABLED_URI, settingChangedListener); systemUiProxy.removeOnStateChangeListener(mSysUiStateChangeListener); diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 43876a6eda..4107c8fdea 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -300,10 +300,10 @@ public class InvariantDeviceProfile { lifeCycle.addCloseable(() -> prefs.removeListener(prefListener, FIXED_LANDSCAPE_MODE, ENABLE_TWOLINE_ALLAPPS_TOGGLE)); - SimpleBroadcastReceiver localeReceiver = new SimpleBroadcastReceiver( + SimpleBroadcastReceiver localeReceiver = new SimpleBroadcastReceiver(context, MAIN_EXECUTOR, i -> onConfigChanged(context)); - localeReceiver.register(context, Intent.ACTION_LOCALE_CHANGED); - lifeCycle.addCloseable(() -> localeReceiver.unregisterReceiverSafely(context)); + localeReceiver.register(Intent.ACTION_LOCALE_CHANGED); + lifeCycle.addCloseable(() -> localeReceiver.unregisterReceiverSafely()); } private String initGrid(Context context, String gridName) { diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index e560a14ab5..71013c3fa6 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -119,14 +119,13 @@ public class LauncherAppState implements SafeCloseable { } SimpleBroadcastReceiver modelChangeReceiver = - new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, mModel::onBroadcastIntent); + new SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR, mModel::onBroadcastIntent); modelChangeReceiver.register( - mContext, ACTION_DEVICE_POLICY_RESOURCE_UPDATED); if (BuildConfig.IS_STUDIO_BUILD) { - modelChangeReceiver.register(mContext, RECEIVER_EXPORTED, ACTION_FORCE_ROLOAD); + modelChangeReceiver.register(RECEIVER_EXPORTED, ACTION_FORCE_ROLOAD); } - mOnTerminateCallback.add(() -> modelChangeReceiver.unregisterReceiverSafely(mContext)); + mOnTerminateCallback.add(() -> modelChangeReceiver.unregisterReceiverSafely()); SafeCloseable userChangeListener = UserCache.INSTANCE.get(mContext) .addUserEventListener(mModel::onUserEvent); diff --git a/src/com/android/launcher3/graphics/ThemeManager.kt b/src/com/android/launcher3/graphics/ThemeManager.kt index 242220ad60..1636da8aa9 100644 --- a/src/com/android/launcher3/graphics/ThemeManager.kt +++ b/src/com/android/launcher3/graphics/ThemeManager.kt @@ -62,8 +62,8 @@ constructor( private val listeners = CopyOnWriteArrayList() init { - val receiver = SimpleBroadcastReceiver(MAIN_EXECUTOR) { verifyIconState() } - receiver.registerPkgActions(context, "android", ACTION_OVERLAY_CHANGED) + val receiver = SimpleBroadcastReceiver(context, MAIN_EXECUTOR) { verifyIconState() } + receiver.registerPkgActions("android", ACTION_OVERLAY_CHANGED) val prefListener = LauncherPrefChangeListener { key -> when (key) { @@ -74,7 +74,7 @@ constructor( prefs.addListener(prefListener, THEMED_ICONS, PREF_ICON_SHAPE) lifecycle.addCloseable { - receiver.unregisterReceiverSafely(context) + receiver.unregisterReceiverSafely() prefs.removeListener(prefListener) } } diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java index 0b18a8733e..20c0ecc4b1 100644 --- a/src/com/android/launcher3/pm/UserCache.java +++ b/src/com/android/launcher3/pm/UserCache.java @@ -81,10 +81,7 @@ public class UserCache { } private final List> mUserEventListeners = new ArrayList<>(); - private final SimpleBroadcastReceiver mUserChangeReceiver = - new SimpleBroadcastReceiver(MODEL_EXECUTOR, this::onUsersChanged); - - private final Context mContext; + private final SimpleBroadcastReceiver mUserChangeReceiver; private final ApiWrapper mApiWrapper; @NonNull @@ -99,16 +96,17 @@ public class UserCache { DaggerSingletonTracker tracker, ApiWrapper apiWrapper ) { - mContext = context; mApiWrapper = apiWrapper; + mUserChangeReceiver = new SimpleBroadcastReceiver(context, + MODEL_EXECUTOR, this::onUsersChanged); mUserToSerialMap = Collections.emptyMap(); MODEL_EXECUTOR.execute(this::initAsync); - tracker.addCloseable(() -> mUserChangeReceiver.unregisterReceiverSafely(mContext)); + tracker.addCloseable(() -> mUserChangeReceiver.unregisterReceiverSafely()); } @WorkerThread private void initAsync() { - mUserChangeReceiver.register(mContext, + mUserChangeReceiver.register( Intent.ACTION_MANAGED_PROFILE_AVAILABLE, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, Intent.ACTION_MANAGED_PROFILE_REMOVED, diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index ee1af810f7..89f12d80ef 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -107,7 +107,6 @@ public class DisplayController implements ComponentCallbacks, private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; private static final String TARGET_OVERLAY_PACKAGE = "android"; - private final Context mContext; private final WindowManagerProxy mWMProxy; // Null for SDK < S @@ -120,8 +119,7 @@ public class DisplayController implements ComponentCallbacks, // We will register broadcast receiver on main thread to ensure not missing changes on // TARGET_OVERLAY_PACKAGE and ACTION_OVERLAY_CHANGED. - private final SimpleBroadcastReceiver mReceiver = - new SimpleBroadcastReceiver(MAIN_EXECUTOR, this::onIntent); + private final SimpleBroadcastReceiver mReceiver; private Info mInfo; private boolean mDestroyed = false; @@ -131,7 +129,6 @@ public class DisplayController implements ComponentCallbacks, WindowManagerProxy wmProxy, LauncherPrefs prefs, DaggerSingletonTracker lifecycle) { - mContext = context; mWMProxy = wmProxy; if (enableTaskbarPinning()) { @@ -155,11 +152,12 @@ public class DisplayController implements ComponentCallbacks, Display display = context.getSystemService(DisplayManager.class) .getDisplay(DEFAULT_DISPLAY); - mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null); + mWindowContext = context.createWindowContext(display, TYPE_APPLICATION, null); mWindowContext.registerComponentCallbacks(this); // Initialize navigation mode change listener - mReceiver.registerPkgActions(mContext, TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED); + mReceiver = new SimpleBroadcastReceiver(context, MAIN_EXECUTOR, this::onIntent); + mReceiver.registerPkgActions(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED); mInfo = new Info(mWindowContext, wmProxy, wmProxy.estimateInternalDisplayBounds(mWindowContext)); @@ -169,7 +167,7 @@ public class DisplayController implements ComponentCallbacks, lifecycle.addCloseable(() -> { mDestroyed = true; mWindowContext.unregisterComponentCallbacks(this); - mReceiver.unregisterReceiverSafely(mContext); + mReceiver.unregisterReceiverSafely(); wmProxy.unregisterDesktopVisibilityListener(this); }); } diff --git a/src/com/android/launcher3/util/LockedUserState.kt b/src/com/android/launcher3/util/LockedUserState.kt index a6a6cebb5d..742a32798f 100644 --- a/src/com/android/launcher3/util/LockedUserState.kt +++ b/src/com/android/launcher3/util/LockedUserState.kt @@ -44,7 +44,7 @@ constructor(@ApplicationContext private val context: Context, lifeCycle: DaggerS @VisibleForTesting val userUnlockedReceiver = - SimpleBroadcastReceiver(UI_HELPER_EXECUTOR) { + SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR) { if (Intent.ACTION_USER_UNLOCKED == it.action) { isUserUnlocked = true } @@ -61,7 +61,6 @@ constructor(@ApplicationContext private val context: Context, lifeCycle: DaggerS isUserUnlockedAtLauncherStartup = isUserUnlocked if (!isUserUnlocked) { userUnlockedReceiver.register( - context, { // If user is unlocked while registering broadcast receiver, we should update // [isUserUnlocked], which will call [notifyUserUnlocked] in setter @@ -72,7 +71,7 @@ constructor(@ApplicationContext private val context: Context, lifeCycle: DaggerS Intent.ACTION_USER_UNLOCKED, ) } - lifeCycle.addCloseable { userUnlockedReceiver.unregisterReceiverSafely(context) } + lifeCycle.addCloseable { userUnlockedReceiver.unregisterReceiverSafely() } } private fun checkIsUserUnlocked() = @@ -80,7 +79,7 @@ constructor(@ApplicationContext private val context: Context, lifeCycle: DaggerS private fun notifyUserUnlocked() { mUserUnlockedActions.executeAllAndDestroy() - userUnlockedReceiver.unregisterReceiverSafely(context) + userUnlockedReceiver.unregisterReceiverSafely() } /** diff --git a/src/com/android/launcher3/util/ScreenOnTracker.java b/src/com/android/launcher3/util/ScreenOnTracker.java index 50be98b45c..8ffe9eac51 100644 --- a/src/com/android/launcher3/util/ScreenOnTracker.java +++ b/src/com/android/launcher3/util/ScreenOnTracker.java @@ -46,34 +46,31 @@ public class ScreenOnTracker implements SafeCloseable { private final SimpleBroadcastReceiver mReceiver; private final CopyOnWriteArrayList mListeners = new CopyOnWriteArrayList<>(); - private final Context mContext; private boolean mIsScreenOn; @Inject ScreenOnTracker(@ApplicationContext Context context, DaggerSingletonTracker tracker) { // Assume that the screen is on to begin with - mContext = context; - mReceiver = new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, this::onReceive); + mReceiver = new SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR, this::onReceive); init(tracker); } @VisibleForTesting ScreenOnTracker(@ApplicationContext Context context, SimpleBroadcastReceiver receiver, DaggerSingletonTracker tracker) { - mContext = context; mReceiver = receiver; init(tracker); } private void init(DaggerSingletonTracker tracker) { mIsScreenOn = true; - mReceiver.register(mContext, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT); + mReceiver.register(ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT); tracker.addCloseable(this); } @Override public void close() { - mReceiver.unregisterReceiverSafely(mContext); + mReceiver.unregisterReceiverSafely(); } @VisibleForTesting diff --git a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java index 539a7cb8ec..7a40abe62b 100644 --- a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java +++ b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java @@ -25,22 +25,29 @@ import android.os.PatternMatcher; import android.text.TextUtils; import androidx.annotation.AnyThread; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.function.Consumer; public class SimpleBroadcastReceiver extends BroadcastReceiver { + public static final String TAG = "SimpleBroadcastReceiver"; + // Keeps a strong reference to the context. + private final Context mContext; private final Consumer mIntentConsumer; // Handler to register/unregister broadcast receiver private final Handler mHandler; - public SimpleBroadcastReceiver(LooperExecutor looperExecutor, Consumer intentConsumer) { - this(looperExecutor.getHandler(), intentConsumer); + public SimpleBroadcastReceiver(@NonNull Context context, LooperExecutor looperExecutor, + Consumer intentConsumer) { + this(context, looperExecutor.getHandler(), intentConsumer); } - public SimpleBroadcastReceiver(Handler handler, Consumer intentConsumer) { + public SimpleBroadcastReceiver(@NonNull Context context, Handler handler, + Consumer intentConsumer) { + mContext = context; mIntentConsumer = intentConsumer; mHandler = handler; } @@ -50,18 +57,18 @@ public class SimpleBroadcastReceiver extends BroadcastReceiver { mIntentConsumer.accept(intent); } - /** Calls {@link #register(Context, Runnable, String...)} with null completionCallback. */ + /** Calls {@link #register(Runnable, String...)} with null completionCallback. */ @AnyThread - public void register(Context context, String... actions) { - register(context, null, actions); + public void register(String... actions) { + register(null, actions); } /** - * Calls {@link #register(Context, Runnable, int, String...)} with null completionCallback. + * Calls {@link #register(Runnable, int, String...)} with null completionCallback. */ @AnyThread - public void register(Context context, int flags, String... actions) { - register(context, null, flags, actions); + public void register(int flags, String... actions) { + register(null, flags, actions); } /** @@ -74,19 +81,18 @@ public class SimpleBroadcastReceiver extends BroadcastReceiver { * while registerReceiver() is executed on a binder call. */ @AnyThread - public void register( - Context context, @Nullable Runnable completionCallback, String... actions) { + public void register(@Nullable Runnable completionCallback, String... actions) { if (Looper.myLooper() == mHandler.getLooper()) { - registerInternal(context, completionCallback, actions); + registerInternal(mContext, completionCallback, actions); } else { - mHandler.post(() -> registerInternal(context, completionCallback, actions)); + mHandler.post(() -> registerInternal(mContext, completionCallback, actions)); } } /** Register broadcast receiver and run completion callback if passed. */ @AnyThread private void registerInternal( - Context context, @Nullable Runnable completionCallback, String... actions) { + @NonNull Context context, @Nullable Runnable completionCallback, String... actions) { context.registerReceiver(this, getFilter(actions)); if (completionCallback != null) { completionCallback.run(); @@ -94,37 +100,37 @@ public class SimpleBroadcastReceiver extends BroadcastReceiver { } /** - * Same as {@link #register(Context, Runnable, String...)} above but with additional flags - * params. + * Same as {@link #register(Runnable, String...)} above but with additional flags + * params utilizine the original {@link Context}. */ @AnyThread - public void register( - Context context, @Nullable Runnable completionCallback, int flags, String... actions) { + public void register(@Nullable Runnable completionCallback, int flags, String... actions) { if (Looper.myLooper() == mHandler.getLooper()) { - registerInternal(context, completionCallback, flags, actions); + registerInternal(mContext, completionCallback, flags, actions); } else { - mHandler.post(() -> registerInternal(context, completionCallback, flags, actions)); + mHandler.post(() -> registerInternal(mContext, completionCallback, flags, actions)); } } /** Register broadcast receiver and run completion callback if passed. */ @AnyThread private void registerInternal( - Context context, @Nullable Runnable completionCallback, int flags, String... actions) { + @NonNull Context context, @Nullable Runnable completionCallback, int flags, + String... actions) { context.registerReceiver(this, getFilter(actions), flags); if (completionCallback != null) { completionCallback.run(); } } - /** Same as {@link #register(Context, Runnable, String...)} above but with pkg name. */ + /** Same as {@link #register(Runnable, String...)} above but with pkg name. */ @AnyThread - public void registerPkgActions(Context context, @Nullable String pkg, String... actions) { + public void registerPkgActions(@Nullable String pkg, String... actions) { if (Looper.myLooper() == mHandler.getLooper()) { - context.registerReceiver(this, getPackageFilter(pkg, actions)); + mContext.registerReceiver(this, getPackageFilter(pkg, actions)); } else { mHandler.post(() -> { - context.registerReceiver(this, getPackageFilter(pkg, actions)); + mContext.registerReceiver(this, getPackageFilter(pkg, actions)); }); } } @@ -135,19 +141,19 @@ public class SimpleBroadcastReceiver extends BroadcastReceiver { * unregister happens on {@link #mHandler}'s looper. */ @AnyThread - public void unregisterReceiverSafely(Context context) { + public void unregisterReceiverSafely() { if (Looper.myLooper() == mHandler.getLooper()) { - unregisterReceiverSafelyInternal(context); + unregisterReceiverSafelyInternal(mContext); } else { mHandler.post(() -> { - unregisterReceiverSafelyInternal(context); + unregisterReceiverSafelyInternal(mContext); }); } } /** Unregister broadcast receiver ignoring any errors. */ @AnyThread - private void unregisterReceiverSafelyInternal(Context context) { + private void unregisterReceiverSafelyInternal(@NonNull Context context) { try { context.unregisterReceiver(this); } catch (IllegalArgumentException e) { diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java index f8cbe0d833..26a04a5a8a 100644 --- a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java +++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java @@ -31,8 +31,7 @@ public class WallpaperOffsetInterpolator { // Don't use all the wallpaper for parallax until you have at least this many pages private static final int MIN_PARALLAX_PAGE_SPAN = 4; - private final SimpleBroadcastReceiver mWallpaperChangeReceiver = - new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> onWallpaperChanged()); + private final SimpleBroadcastReceiver mWallpaperChangeReceiver; private final Workspace mWorkspace; private final boolean mIsRtl; private final Handler mHandler; @@ -46,6 +45,8 @@ public class WallpaperOffsetInterpolator { public WallpaperOffsetInterpolator(Workspace workspace) { mWorkspace = workspace; + mWallpaperChangeReceiver = new SimpleBroadcastReceiver( + workspace.getContext(), UI_HELPER_EXECUTOR, i -> onWallpaperChanged()); mIsRtl = Utilities.isRtl(workspace.getResources()); mHandler = new OffsetHandler(workspace.getContext()); } @@ -198,11 +199,10 @@ public class WallpaperOffsetInterpolator { public void setWindowToken(IBinder token) { mWindowToken = token; if (mWindowToken == null && mRegistered) { - mWallpaperChangeReceiver.unregisterReceiverSafely(mWorkspace.getContext()); + mWallpaperChangeReceiver.unregisterReceiverSafely(); mRegistered = false; } else if (mWindowToken != null && !mRegistered) { - mWallpaperChangeReceiver.register( - mWorkspace.getContext(), ACTION_WALLPAPER_CHANGED); + mWallpaperChangeReceiver.register(ACTION_WALLPAPER_CHANGED); onWallpaperChanged(); mRegistered = true; } diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ScreenOnTrackerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/ScreenOnTrackerTest.kt index 45cc19c8b2..9c3f223b80 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/ScreenOnTrackerTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/ScreenOnTrackerTest.kt @@ -51,7 +51,7 @@ class ScreenOnTrackerTest { @Test fun test_default_state() { - verify(receiver).register(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT) + verify(receiver).register(ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT) assertThat(underTest.isScreenOn).isTrue() } @@ -59,7 +59,7 @@ class ScreenOnTrackerTest { fun close_unregister_receiver() { underTest.close() - verify(receiver).unregisterReceiverSafely(context) + verify(receiver).unregisterReceiverSafely() } @Test diff --git a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt index d3e27b69e9..17933f202b 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt @@ -52,7 +52,7 @@ class SimpleBroadcastReceiverTest { @Before fun setUp() { MockitoAnnotations.initMocks(this) - underTest = SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, intentConsumer) + underTest = SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR, intentConsumer) if (Looper.getMainLooper() == null) { Looper.prepareMainLooper() } @@ -60,7 +60,7 @@ class SimpleBroadcastReceiverTest { @Test fun async_register() { - underTest.register(context, "test_action_1", "test_action_2") + underTest.register("test_action_1", "test_action_2") awaitTasksCompleted() verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture()) @@ -72,7 +72,7 @@ class SimpleBroadcastReceiverTest { @Test fun async_register_withCompletionRunnable() { - underTest.register(context, completionRunnable, "test_action_1", "test_action_2") + underTest.register(completionRunnable, "test_action_1", "test_action_2") awaitTasksCompleted() verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture()) @@ -85,7 +85,7 @@ class SimpleBroadcastReceiverTest { @Test fun async_register_withCompletionRunnable_and_flag() { - underTest.register(context, completionRunnable, 1, "test_action_1", "test_action_2") + underTest.register(completionRunnable, 1, "test_action_1", "test_action_2") awaitTasksCompleted() verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture(), eq(1)) @@ -98,7 +98,7 @@ class SimpleBroadcastReceiverTest { @Test fun async_register_with_package() { - underTest.registerPkgActions(context, "pkg", "test_action_1", "test_action_2") + underTest.registerPkgActions("pkg", "test_action_1", "test_action_2") awaitTasksCompleted() verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture()) @@ -112,9 +112,10 @@ class SimpleBroadcastReceiverTest { @Test fun sync_register_withCompletionRunnable_and_flag() { - underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer) + underTest = + SimpleBroadcastReceiver(context, Handler(Looper.getMainLooper()), intentConsumer) - underTest.register(context, completionRunnable, 1, "test_action_1", "test_action_2") + underTest.register(completionRunnable, 1, "test_action_1", "test_action_2") getInstrumentation().waitForIdleSync() verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture(), eq(1)) @@ -127,7 +128,7 @@ class SimpleBroadcastReceiverTest { @Test fun async_unregister() { - underTest.unregisterReceiverSafely(context) + underTest.unregisterReceiverSafely() awaitTasksCompleted() verify(context).unregisterReceiver(same(underTest)) @@ -135,9 +136,10 @@ class SimpleBroadcastReceiverTest { @Test fun sync_unregister() { - underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer) + underTest = + SimpleBroadcastReceiver(context, Handler(Looper.getMainLooper()), intentConsumer) - underTest.unregisterReceiverSafely(context) + underTest.unregisterReceiverSafely() getInstrumentation().waitForIdleSync() verify(context).unregisterReceiver(same(underTest))