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
This commit is contained in:
Adnan Begovic
2025-02-12 13:43:34 -08:00
parent 4425ab3062
commit 1b26bb4a74
16 changed files with 118 additions and 113 deletions
@@ -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);
});
}
@@ -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();
}
@@ -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;
}
}
@@ -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<BroadcastReceiver, Handler> mTimeEventReceivers = new ArrayMap<>();
private final List<ContentObserver> 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();
}
}
@@ -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);
@@ -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) {
@@ -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);
@@ -62,8 +62,8 @@ constructor(
private val listeners = CopyOnWriteArrayList<ThemeChangeListener>()
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)
}
}
+5 -7
View File
@@ -81,10 +81,7 @@ public class UserCache {
}
private final List<BiConsumer<UserHandle, String>> 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,
@@ -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);
});
}
@@ -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()
}
/**
@@ -46,34 +46,31 @@ public class ScreenOnTracker implements SafeCloseable {
private final SimpleBroadcastReceiver mReceiver;
private final CopyOnWriteArrayList<ScreenOnListener> 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
@@ -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<Intent> mIntentConsumer;
// Handler to register/unregister broadcast receiver
private final Handler mHandler;
public SimpleBroadcastReceiver(LooperExecutor looperExecutor, Consumer<Intent> intentConsumer) {
this(looperExecutor.getHandler(), intentConsumer);
public SimpleBroadcastReceiver(@NonNull Context context, LooperExecutor looperExecutor,
Consumer<Intent> intentConsumer) {
this(context, looperExecutor.getHandler(), intentConsumer);
}
public SimpleBroadcastReceiver(Handler handler, Consumer<Intent> intentConsumer) {
public SimpleBroadcastReceiver(@NonNull Context context, Handler handler,
Consumer<Intent> 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) {
@@ -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;
}
@@ -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
@@ -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))