Unbind notification listener when badging is disabled
- Added SettingsObserver as wrapper around ContentObserver to observe Secure or System setting changes. - NotificationListener and LauncherAppState observe changes to the notification dots setting and unbind and rebind the NotificationListener service, respectively. Bug: 36815147 Change-Id: I2cc04ac816a8974969ad0ec759c5402e181fde24
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -28,13 +29,17 @@ import com.android.launcher3.compat.PackageInstallerCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dynamicui.ExtractionUtils;
|
||||
import com.android.launcher3.notification.NotificationListener;
|
||||
import com.android.launcher3.util.ConfigMonitor;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.SettingsObserver;
|
||||
import com.android.launcher3.util.TestingUtils;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
|
||||
|
||||
public class LauncherAppState {
|
||||
|
||||
public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD;
|
||||
@@ -47,7 +52,7 @@ public class LauncherAppState {
|
||||
private final IconCache mIconCache;
|
||||
private final WidgetPreviewLoader mWidgetCache;
|
||||
private final InvariantDeviceProfile mInvariantDeviceProfile;
|
||||
|
||||
private final SettingsObserver mNotificationBadgingObserver;
|
||||
|
||||
public static LauncherAppState getInstance(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
@@ -117,6 +122,23 @@ public class LauncherAppState {
|
||||
new ConfigMonitor(mContext).register();
|
||||
|
||||
ExtractionUtils.startColorExtractionServiceIfNecessary(mContext);
|
||||
|
||||
if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
|
||||
mNotificationBadgingObserver = null;
|
||||
} else {
|
||||
// Register an observer to rebind the notification listener when badging is re-enabled.
|
||||
mNotificationBadgingObserver = new SettingsObserver.Secure(
|
||||
mContext.getContentResolver()) {
|
||||
@Override
|
||||
public void onSettingChanged(boolean isNotificationBadgingEnabled) {
|
||||
if (isNotificationBadgingEnabled) {
|
||||
NotificationListener.requestRebind(new ComponentName(
|
||||
mContext, NotificationListener.class));
|
||||
}
|
||||
}
|
||||
};
|
||||
mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,6 +149,9 @@ public class LauncherAppState {
|
||||
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
|
||||
launcherApps.removeOnAppsChangedCallback(mModel);
|
||||
PackageInstallerCompat.getInstance(mContext).onStop();
|
||||
if (mNotificationBadgingObserver != null) {
|
||||
mNotificationBadgingObserver.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
LauncherModel setLauncher(Launcher launcher) {
|
||||
|
||||
@@ -26,17 +26,15 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.System;
|
||||
|
||||
import com.android.launcher3.graphics.IconShapeOverride;
|
||||
import com.android.launcher3.notification.NotificationListener;
|
||||
import com.android.launcher3.util.SettingsObserver;
|
||||
import com.android.launcher3.views.ButtonPreference;
|
||||
|
||||
/**
|
||||
@@ -45,8 +43,8 @@ import com.android.launcher3.views.ButtonPreference;
|
||||
public class SettingsActivity extends Activity {
|
||||
|
||||
private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
|
||||
// TODO: use Settings.Secure.NOTIFICATION_BADGING
|
||||
private static final String NOTIFICATION_BADGING = "notification_badging";
|
||||
/** Hidden field Settings.Secure.NOTIFICATION_BADGING */
|
||||
public static final String NOTIFICATION_BADGING = "notification_badging";
|
||||
/** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
|
||||
private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
|
||||
|
||||
@@ -88,12 +86,9 @@ public class SettingsActivity extends Activity {
|
||||
|
||||
// Register a content observer to listen for system setting changes while
|
||||
// this UI is active.
|
||||
resolver.registerContentObserver(
|
||||
Settings.System.getUriFor(System.ACCELEROMETER_ROTATION),
|
||||
false, mRotationLockObserver);
|
||||
mRotationLockObserver.register(Settings.System.ACCELEROMETER_ROTATION);
|
||||
|
||||
// Initialize the UI once
|
||||
mRotationLockObserver.onChange(true);
|
||||
rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
|
||||
}
|
||||
|
||||
@@ -107,13 +102,7 @@ public class SettingsActivity extends Activity {
|
||||
// Listen to system notification badge settings while this UI is active.
|
||||
mIconBadgingObserver = new IconBadgingObserver(
|
||||
iconBadgingPref, resolver, getFragmentManager());
|
||||
resolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(NOTIFICATION_BADGING),
|
||||
false, mIconBadgingObserver);
|
||||
resolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS),
|
||||
false, mIconBadgingObserver);
|
||||
mIconBadgingObserver.onChange(true);
|
||||
mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS);
|
||||
}
|
||||
|
||||
Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE);
|
||||
@@ -129,11 +118,11 @@ public class SettingsActivity extends Activity {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mRotationLockObserver != null) {
|
||||
getActivity().getContentResolver().unregisterContentObserver(mRotationLockObserver);
|
||||
mRotationLockObserver.unregister();
|
||||
mRotationLockObserver = null;
|
||||
}
|
||||
if (mIconBadgingObserver != null) {
|
||||
getActivity().getContentResolver().unregisterContentObserver(mIconBadgingObserver);
|
||||
mIconBadgingObserver.unregister();
|
||||
mIconBadgingObserver = null;
|
||||
}
|
||||
super.onDestroy();
|
||||
@@ -144,22 +133,18 @@ public class SettingsActivity extends Activity {
|
||||
* Content observer which listens for system auto-rotate setting changes, and enables/disables
|
||||
* the launcher rotation setting accordingly.
|
||||
*/
|
||||
private static class SystemDisplayRotationLockObserver extends ContentObserver {
|
||||
private static class SystemDisplayRotationLockObserver extends SettingsObserver.System {
|
||||
|
||||
private final Preference mRotationPref;
|
||||
private final ContentResolver mResolver;
|
||||
|
||||
public SystemDisplayRotationLockObserver(
|
||||
Preference rotationPref, ContentResolver resolver) {
|
||||
super(new Handler());
|
||||
super(resolver);
|
||||
mRotationPref = rotationPref;
|
||||
mResolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
boolean enabled = Settings.System.getInt(mResolver,
|
||||
Settings.System.ACCELEROMETER_ROTATION, 1) == 1;
|
||||
public void onSettingChanged(boolean enabled) {
|
||||
mRotationPref.setEnabled(enabled);
|
||||
mRotationPref.setSummary(enabled
|
||||
? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc);
|
||||
@@ -170,7 +155,7 @@ public class SettingsActivity extends Activity {
|
||||
* Content observer which listens for system badging setting changes,
|
||||
* and updates the launcher badging setting subtext accordingly.
|
||||
*/
|
||||
private static class IconBadgingObserver extends ContentObserver
|
||||
private static class IconBadgingObserver extends SettingsObserver.Secure
|
||||
implements Preference.OnPreferenceClickListener {
|
||||
|
||||
private final ButtonPreference mBadgingPref;
|
||||
@@ -179,15 +164,14 @@ public class SettingsActivity extends Activity {
|
||||
|
||||
public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver,
|
||||
FragmentManager fragmentManager) {
|
||||
super(new Handler());
|
||||
super(resolver);
|
||||
mBadgingPref = badgingPref;
|
||||
mResolver = resolver;
|
||||
mFragmentManager = fragmentManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
boolean enabled = Settings.Secure.getInt(mResolver, NOTIFICATION_BADGING, 1) == 1;
|
||||
public void onSettingChanged(boolean enabled) {
|
||||
int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off;
|
||||
|
||||
boolean serviceEnabled = true;
|
||||
|
||||
@@ -30,15 +30,20 @@ import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.SettingsObserver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
|
||||
|
||||
/**
|
||||
* A {@link NotificationListenerService} that sends updates to its
|
||||
* {@link NotificationsChangedListener} when notifications are posted or canceled,
|
||||
@@ -57,12 +62,14 @@ public class NotificationListener extends NotificationListenerService {
|
||||
private static NotificationListener sNotificationListenerInstance = null;
|
||||
private static NotificationsChangedListener sNotificationsChangedListener;
|
||||
private static boolean sIsConnected;
|
||||
private static boolean sIsCreated;
|
||||
|
||||
private final Handler mWorkerHandler;
|
||||
private final Handler mUiHandler;
|
||||
|
||||
private final Ranking mTempRanking = new Ranking();
|
||||
|
||||
private SettingsObserver mNotificationBadgingObserver;
|
||||
|
||||
private final Handler.Callback mWorkerCallback = new Handler.Callback() {
|
||||
@Override
|
||||
public boolean handleMessage(Message message) {
|
||||
@@ -77,7 +84,7 @@ public class NotificationListener extends NotificationListenerService {
|
||||
List<StatusBarNotification> activeNotifications;
|
||||
if (sIsConnected) {
|
||||
try {
|
||||
activeNotifications = filterNotifications(getActiveNotifications());
|
||||
activeNotifications = filterNotifications(getActiveNotifications());
|
||||
} catch (SecurityException ex) {
|
||||
Log.e(TAG, "SecurityException: failed to fetch notifications");
|
||||
activeNotifications = new ArrayList<StatusBarNotification>();
|
||||
@@ -130,6 +137,28 @@ public class NotificationListener extends NotificationListenerService {
|
||||
sNotificationListenerInstance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
sIsCreated = true;
|
||||
mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) {
|
||||
@Override
|
||||
public void onSettingChanged(boolean isNotificationBadgingEnabled) {
|
||||
if (!isNotificationBadgingEnabled) {
|
||||
requestUnbind();
|
||||
}
|
||||
}
|
||||
};
|
||||
mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
sIsCreated = false;
|
||||
mNotificationBadgingObserver.unregister();
|
||||
}
|
||||
|
||||
public static @Nullable NotificationListener getInstanceIfConnected() {
|
||||
return sIsConnected ? sNotificationListenerInstance : null;
|
||||
}
|
||||
@@ -143,6 +172,11 @@ public class NotificationListener extends NotificationListenerService {
|
||||
NotificationListener notificationListener = getInstanceIfConnected();
|
||||
if (notificationListener != null) {
|
||||
notificationListener.onNotificationFullRefresh();
|
||||
} else if (!sIsCreated && sNotificationsChangedListener != null) {
|
||||
// User turned off badging globally, so we unbound this service;
|
||||
// tell the listener that there are no notifications to remove dots.
|
||||
sNotificationsChangedListener.onNotificationFullRefresh(
|
||||
Collections.<StatusBarNotification>emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +239,7 @@ public class NotificationListener extends NotificationListenerService {
|
||||
.getActiveNotifications(NotificationKeyData.extractKeysOnly(keys)
|
||||
.toArray(new String[keys.size()]));
|
||||
return notifications == null
|
||||
? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications);
|
||||
? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
|
||||
public interface SettingsObserver {
|
||||
|
||||
/**
|
||||
* Registers the content observer to call {@link #onSettingChanged(boolean)} when any of the
|
||||
* passed settings change. The value passed to onSettingChanged() is based on the key setting.
|
||||
*/
|
||||
void register(String keySetting, String ... dependentSettings);
|
||||
void unregister();
|
||||
void onSettingChanged(boolean keySettingEnabled);
|
||||
|
||||
|
||||
abstract class Secure extends ContentObserver implements SettingsObserver {
|
||||
private ContentResolver mResolver;
|
||||
private String mKeySetting;
|
||||
|
||||
public Secure(ContentResolver resolver) {
|
||||
super(new Handler());
|
||||
mResolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String keySetting, String ... dependentSettings) {
|
||||
mKeySetting = keySetting;
|
||||
mResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(mKeySetting), false, this);
|
||||
for (String setting : dependentSettings) {
|
||||
mResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(setting), false, this);
|
||||
}
|
||||
onChange(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister() {
|
||||
mResolver.unregisterContentObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
super.onChange(selfChange);
|
||||
onSettingChanged(Settings.Secure.getInt(mResolver, mKeySetting, 1) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class System extends ContentObserver implements SettingsObserver {
|
||||
private ContentResolver mResolver;
|
||||
private String mKeySetting;
|
||||
|
||||
public System(ContentResolver resolver) {
|
||||
super(new Handler());
|
||||
mResolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String keySetting, String ... dependentSettings) {
|
||||
mKeySetting = keySetting;
|
||||
mResolver.registerContentObserver(
|
||||
Settings.System.getUriFor(mKeySetting), false, this);
|
||||
for (String setting : dependentSettings) {
|
||||
mResolver.registerContentObserver(
|
||||
Settings.System.getUriFor(setting), false, this);
|
||||
}
|
||||
onChange(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister() {
|
||||
mResolver.unregisterContentObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
super.onChange(selfChange);
|
||||
onSettingChanged(Settings.System.getInt(mResolver, mKeySetting, 1) == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user