diff --git a/res/values/strings.xml b/res/values/strings.xml index db986f1659ec0d08d6d0fe879cb5bbd6f6e65a64..8614d7a11be6c7170051c53458c59ec4927eb16d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6011,6 +6011,9 @@ App notifications + + Topic notifications + Other sounds @@ -6093,17 +6096,17 @@ Never show notifications from this app - - Treat as priority + + Override Do Not Disturb - - Let this app\u2019s notifications be heard when Do not disturb is set to Priority only + + Let these notifications continue to interrupt when Do Not Disturb is set to Priority Only Hide sensitive content - When the device is locked, hide content in this app\u2019s notifications that might reveal private information + When the device is locked, hide content in these notifications that might reveal private information Blocked @@ -6484,10 +6487,6 @@ Normal Block - - Sensitive content hidden - - Priority %1$s / %2$s @@ -6528,10 +6527,6 @@ Work Blocked - - Priority - - Sensitive content hidden With domain URLs diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml index 149b9fc3933b546f0ee238bcfeda8bdf353106c4..6e27a075b383f96c0e0895175edbfe0a4db24183 100644 --- a/res/xml/app_notification_settings.xml +++ b/res/xml/app_notification_settings.xml @@ -26,22 +26,6 @@ android:order="1" android:persistent="false" /> - - - - - - + + + + + + + + + + + diff --git a/src/com/android/settings/applications/AppStateNotificationBridge.java b/src/com/android/settings/applications/AppStateNotificationBridge.java index 44a37a5624ad18148a762ebdfeb047610bb9e036..6d057b35b65fa1b9f979ae4081a9cf39ffab779e 100644 --- a/src/com/android/settings/applications/AppStateNotificationBridge.java +++ b/src/com/android/settings/applications/AppStateNotificationBridge.java @@ -66,26 +66,4 @@ public class AppStateNotificationBridge extends AppStateBaseBridge { return info.extraInfo != null && ((AppRow) info.extraInfo).banned; } }; - - public static final AppFilter FILTER_APP_NOTIFICATION_PRIORITY = new AppFilter() { - @Override - public void init() { - } - - @Override - public boolean filterApp(AppEntry info) { - return info.extraInfo != null && ((AppRow) info.extraInfo).priority; - } - }; - - public static final AppFilter FILTER_APP_NOTIFICATION_SENSITIVE = new AppFilter() { - @Override - public void init() { - } - - @Override - public boolean filterApp(AppEntry info) { - return info.extraInfo != null && ((AppRow) info.extraInfo).sensitive; - } - }; } diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java index 4e8a168ad2c3a10c8f1afa2d1384fb2fb99a9d46..32d3d2ffb73a11971b0acbd5eb67219fe5181c38 100755 --- a/src/com/android/settings/applications/InstalledAppDetails.java +++ b/src/com/android/settings/applications/InstalledAppDetails.java @@ -814,25 +814,7 @@ public class InstalledAppDetails extends AppInfoBase if (appRow.banned) { return context.getString(R.string.notifications_disabled); } - ArrayList notifSummary = new ArrayList<>(); - if (appRow.priority) { - notifSummary.add(context.getString(R.string.notifications_priority)); - } - if (appRow.sensitive) { - notifSummary.add(context.getString(R.string.notifications_sensitive)); - } - switch (notifSummary.size()) { - case 3: - return context.getString(R.string.notifications_three_items, - notifSummary.get(0), notifSummary.get(1), notifSummary.get(2)); - case 2: - return context.getString(R.string.notifications_two_items, - notifSummary.get(0), notifSummary.get(1)); - case 1: - return notifSummary.get(0); - default: - return context.getString(R.string.notifications_enabled); - } + return context.getString(R.string.notifications_enabled); } private class MemoryUpdater extends AsyncTask { diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java index 384fbf80d5dc5d08dda01046001b92fd62b1a22c..bd1f28c4774ecac1eb6cc3b7598f92cb45beece1 100644 --- a/src/com/android/settings/applications/ManageApplications.java +++ b/src/com/android/settings/applications/ManageApplications.java @@ -138,8 +138,6 @@ public class ManageApplications extends InstrumentedFragment R.string.filter_enabled_apps, // Enabled R.string.filter_apps_disabled, // Disabled R.string.filter_notif_blocked_apps, // Blocked Notifications - R.string.filter_notif_priority_apps, // Priority Notifications - R.string.filter_notif_sensitive_apps, // Sensitive Notifications R.string.filter_personal_apps, // Personal R.string.filter_work_apps, // Work R.string.filter_with_domain_urls_apps, // Domain URLs @@ -158,8 +156,6 @@ public class ManageApplications extends InstrumentedFragment ApplicationsState.FILTER_ALL_ENABLED, // Enabled ApplicationsState.FILTER_DISABLED, // Disabled AppStateNotificationBridge.FILTER_APP_NOTIFICATION_BLOCKED, // Blocked Notifications - AppStateNotificationBridge.FILTER_APP_NOTIFICATION_PRIORITY, // Priority Notifications - AppStateNotificationBridge.FILTER_APP_NOTIFICATION_SENSITIVE, // Sensitive Notifications ApplicationsState.FILTER_PERSONAL, // Personal ApplicationsState.FILTER_WORK, // Work ApplicationsState.FILTER_WITH_DOMAIN_URLS, // Apps with Domain URLs diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java index 2669f2fcec07bc5fa9b6d68a573de6213757d696..deba7d41b243c7c28b95cccf2ad0f868c5d0835a 100644 --- a/src/com/android/settings/notification/AppNotificationSettings.java +++ b/src/com/android/settings/notification/AppNotificationSettings.java @@ -54,8 +54,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String KEY_BLOCK = "block"; - private static final String KEY_PRIORITY = "priority"; - private static final String KEY_SENSITIVE = "sensitive"; private static final String KEY_APP_SETTINGS = "app_settings"; private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT @@ -66,8 +64,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment { private Context mContext; private SwitchPreference mBlock; - private SwitchPreference mPriority; - private SwitchPreference mSensitive; private AppRow mAppRow; private boolean mCreated; private boolean mIsSystemPackage; @@ -130,8 +126,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment { addPreferencesFromResource(R.xml.app_notification_settings); mBlock = (SwitchPreference) findPreference(KEY_BLOCK); - mPriority = (SwitchPreference) findPreference(KEY_PRIORITY); - mSensitive = (SwitchPreference) findPreference(KEY_SENSITIVE); mAppRow = mBackend.loadAppRow(pm, info.applicationInfo); @@ -140,10 +134,29 @@ public class AppNotificationSettings extends SettingsPreferenceFragment { rows.put(mAppRow.pkg, mAppRow); collectConfigActivities(getPackageManager(), rows); + // Add topics + List topics = mBackend.getTopics(pkg, mUid); + for (Notification.Topic topic : topics) { + Preference topicPreference = new Preference(mContext); + topicPreference.setKey(topic.getId()); + topicPreference.setTitle(topic.getLabel()); + // Create intent for this preference. + Bundle topicArgs = new Bundle(); + topicArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid); + topicArgs.putParcelable(TopicNotificationSettings.ARG_TOPIC, topic); + topicArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true); + topicArgs.putParcelable(TopicNotificationSettings.ARG_PACKAGE_INFO, info); + + Intent topicIntent = Utils.onBuildStartFragmentIntent(getActivity(), + TopicNotificationSettings.class.getName(), + topicArgs, null, R.string.topic_notifications_title, null, false); + topicPreference.setIntent(topicIntent); + // Add preference to the settings menu. + getPreferenceScreen().addPreference(topicPreference); + } + mBlock.setChecked(mAppRow.banned); updateDependents(mAppRow.banned); - mPriority.setChecked(mAppRow.priority); - mSensitive.setChecked(mAppRow.sensitive); mBlock.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override @@ -160,22 +173,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment { } }); - mPriority.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final boolean priority = (Boolean) newValue; - return mBackend.setHighPriority(pkg, mUid, priority); - } - }); - - mSensitive.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - final boolean sensitive = (Boolean) newValue; - return mBackend.setSensitive(pkg, mUid, sensitive); - } - }); - if (mAppRow.settingsIntent != null) { findPreference(KEY_APP_SETTINGS).setOnPreferenceClickListener( new OnPreferenceClickListener() { @@ -200,15 +197,7 @@ public class AppNotificationSettings extends SettingsPreferenceFragment { } private void updateDependents(boolean banned) { - final boolean lockscreenSecure = new LockPatternUtils(getActivity()).isSecure( - UserHandle.myUserId()); - final boolean lockscreenNotificationsEnabled = getLockscreenNotificationsEnabled(); - final boolean allowPrivate = getLockscreenAllowPrivateNotifications(); - setVisible(mBlock, !mIsSystemPackage); - setVisible(mPriority, mIsSystemPackage || !banned); - setVisible(mSensitive, mIsSystemPackage || !banned && lockscreenSecure - && lockscreenNotificationsEnabled && allowPrivate); } private void setVisible(Preference p, boolean visible) { @@ -221,16 +210,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment { } } - private boolean getLockscreenNotificationsEnabled() { - return Settings.Secure.getInt(getContentResolver(), - Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0; - } - - private boolean getLockscreenAllowPrivateNotifications() { - return Settings.Secure.getInt(getContentResolver(), - Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0; - } - private void toastAndFinish() { Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show(); getActivity().finish(); diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java index e86fee012a0885a640e6911d3329648d9a9894fa..dcebf8b29cfd65be64b9658170316c42197fc17e 100644 --- a/src/com/android/settings/notification/NotificationBackend.java +++ b/src/com/android/settings/notification/NotificationBackend.java @@ -15,17 +15,22 @@ */ package com.android.settings.notification; +import com.google.android.collect.Lists; + import android.app.INotificationManager; import android.app.Notification; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.graphics.drawable.Drawable; import android.os.ServiceManager; import android.service.notification.NotificationListenerService; import android.util.Log; +import java.util.List; + public class NotificationBackend { private static final String TAG = "NotificationBackend"; @@ -44,8 +49,19 @@ public class NotificationBackend { } row.icon = app.loadIcon(pm); row.banned = getNotificationsBanned(row.pkg, row.uid); - row.priority = getHighPriority(row.pkg, row.uid); - row.sensitive = getSensitive(row.pkg, row.uid); + return row; + } + + public TopicRow loadTopicRow(PackageManager pm, ApplicationInfo app, Notification.Topic topic) { + final TopicRow row = new TopicRow(); + row.pkg = app.packageName; + row.uid = app.uid; + row.label = topic.getLabel(); + row.icon = app.loadIcon(pm); + row.topic = topic; + row.priority = getBypassZenMode(row.pkg, row.uid, row.topic); + row.sensitive = getSensitive(row.pkg, row.uid, row.topic); + row.banned = getNotificationsBanned(row.pkg, row.uid); return row; } @@ -69,19 +85,20 @@ public class NotificationBackend { } } - public boolean getHighPriority(String pkg, int uid) { + public boolean getBypassZenMode(String pkg, int uid, Notification.Topic topic) { try { - return sINM.getPackagePriority(pkg, uid) == Notification.PRIORITY_MAX; + return sINM.getTopicPriority(pkg, uid, topic) == Notification.PRIORITY_MAX; } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); return false; } } - public boolean setHighPriority(String pkg, int uid, boolean highPriority) { + public boolean setBypassZenMode(String pkg, int uid, Notification.Topic topic, + boolean bypassZen) { try { - sINM.setPackagePriority(pkg, uid, - highPriority ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT); + sINM.setTopicPriority(pkg, uid, topic, + bypassZen ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT); return true; } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); @@ -89,18 +106,19 @@ public class NotificationBackend { } } - public boolean getSensitive(String pkg, int uid) { + public boolean getSensitive(String pkg, int uid, Notification.Topic topic) { try { - return sINM.getPackageVisibilityOverride(pkg, uid) == Notification.VISIBILITY_PRIVATE; + return sINM.getTopicVisibilityOverride(pkg, uid, topic) + == Notification.VISIBILITY_PRIVATE; } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); return false; } } - public boolean setSensitive(String pkg, int uid, boolean sensitive) { + public boolean setSensitive(String pkg, int uid, Notification.Topic topic, boolean sensitive) { try { - sINM.setPackageVisibilityOverride(pkg, uid, + sINM.setTopicVisibilityOverride(pkg, uid, topic, sensitive ? Notification.VISIBILITY_PRIVATE : NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE); return true; @@ -110,6 +128,16 @@ public class NotificationBackend { } } + public List getTopics(String pkg, int uid) { + try { + final ParceledListSlice parceledList = sINM.getTopics(pkg, uid); + return parceledList.getList(); + } catch (Exception e) { + Log.w(TAG, "Error calling NoMan", e); + return Lists.newArrayList(); + } + } + static class Row { public String section; } @@ -121,9 +149,13 @@ public class NotificationBackend { public CharSequence label; public Intent settingsIntent; public boolean banned; + public boolean first; // first app in section + } + + public static class TopicRow extends AppRow { + public Notification.Topic topic; public boolean priority; public boolean sensitive; - public boolean first; // first app in section } } diff --git a/src/com/android/settings/notification/TopicNotificationSettings.java b/src/com/android/settings/notification/TopicNotificationSettings.java new file mode 100644 index 0000000000000000000000000000000000000000..48c611e84c06b235634bf8e1dad5d68f204abf37 --- /dev/null +++ b/src/com/android/settings/notification/TopicNotificationSettings.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015 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.settings.notification; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.AppHeader; +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.Utils; +import com.android.settings.applications.AppInfoBase; +import com.android.settings.notification.NotificationBackend.TopicRow; + +import android.app.Notification; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.os.UserHandle; +import android.provider.Settings; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.preference.Preference; +import android.support.v7.preference.Preference.OnPreferenceChangeListener; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +/** These settings are per topic, so should not be returned in global search results. */ +public class TopicNotificationSettings extends SettingsPreferenceFragment { + private static final String TAG = "TopicNotiSettings"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + protected static final String ARG_TOPIC = "arg_topic"; + protected static final String ARG_PACKAGE_INFO = "arg_info"; + private static final String KEY_BYPASS_DND = "bypass_dnd"; + private static final String KEY_SENSITIVE = "sensitive"; + + private final NotificationBackend mBackend = new NotificationBackend(); + + private Context mContext; + private SwitchPreference mPriority; + private SwitchPreference mSensitive; + private TopicRow mTopicRow; + private boolean mCreated; + private boolean mIsSystemPackage; + private int mUid; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (DEBUG) Log.d(TAG, "onActivityCreated mCreated=" + mCreated); + if (mCreated) { + Log.w(TAG, "onActivityCreated: ignoring duplicate call"); + return; + } + mCreated = true; + if (mTopicRow == null) return; + AppHeader.createAppHeader( + this, mTopicRow.icon, mTopicRow.label, mTopicRow.pkg, mTopicRow.uid); + } + + @Override + protected int getMetricsCategory() { + return MetricsLogger.NOTIFICATION_TOPIC_NOTIFICATION; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = getActivity(); + Intent intent = getActivity().getIntent(); + Bundle args = getArguments(); + if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent); + if (intent == null && args == null) { + Log.w(TAG, "No intent"); + toastAndFinish(); + return; + } + + final Notification.Topic topic = args != null && args.containsKey(ARG_TOPIC) + ? (Notification.Topic) args.getParcelable(ARG_TOPIC) : null; + + if (topic == null) { + toastAndFinish(); + return; + } + + final PackageInfo info = args != null && args.containsKey(ARG_PACKAGE_INFO) + ? (PackageInfo) args.getParcelable(ARG_PACKAGE_INFO) : null; + if (info == null) { + Log.w(TAG, "Failed to find package info"); + toastAndFinish(); + return; + } + + mUid = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_UID) + ? args.getInt(AppInfoBase.ARG_PACKAGE_UID) + : intent.getIntExtra(Settings.EXTRA_APP_UID, -1); + if (mUid == -1) { + Log.w(TAG, "Missing extras: " + Settings.EXTRA_APP_UID + " was " + mUid); + toastAndFinish(); + return; + } + + final PackageManager pm = getPackageManager(); + mIsSystemPackage = Utils.isSystemPackage(pm, info); + + addPreferencesFromResource(R.xml.topic_notification_settings); + mPriority = (SwitchPreference) findPreference(KEY_BYPASS_DND); + mSensitive = (SwitchPreference) findPreference(KEY_SENSITIVE); + + mTopicRow = mBackend.loadTopicRow(pm, info.applicationInfo, topic); + + mPriority.setChecked(mTopicRow.priority); + mSensitive.setChecked(mTopicRow.sensitive); + + mPriority.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final boolean bypassZenMode = (Boolean) newValue; + return mBackend.setBypassZenMode(info.packageName, mUid, topic, bypassZenMode); + } + }); + + mSensitive.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final boolean sensitive = (Boolean) newValue; + return mBackend.setSensitive(info.packageName, mUid, topic, sensitive); + } + }); + updateDependents(mTopicRow.banned); + + } + + @Override + public void onResume() { + super.onResume(); + if (mUid != -1 && getPackageManager().getPackagesForUid(mUid) == null) { + // App isn't around anymore, must have been removed. + finish(); + } + } + + private void updateDependents(boolean banned) { + final boolean lockscreenSecure = new LockPatternUtils(getActivity()).isSecure( + UserHandle.myUserId()); + final boolean lockscreenNotificationsEnabled = getLockscreenNotificationsEnabled(); + final boolean allowPrivate = getLockscreenAllowPrivateNotifications(); + + setVisible(mPriority, mIsSystemPackage || !banned); + setVisible(mSensitive, mIsSystemPackage || !banned && lockscreenSecure + && lockscreenNotificationsEnabled && allowPrivate); + } + + private void setVisible(Preference p, boolean visible) { + final boolean isVisible = getPreferenceScreen().findPreference(p.getKey()) != null; + if (isVisible == visible) return; + if (visible) { + getPreferenceScreen().addPreference(p); + } else { + getPreferenceScreen().removePreference(p); + } + } + + private boolean getLockscreenNotificationsEnabled() { + return Settings.Secure.getInt(getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0; + } + + private boolean getLockscreenAllowPrivateNotifications() { + return Settings.Secure.getInt(getContentResolver(), + Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0; + } + + private void toastAndFinish() { + Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show(); + getActivity().finish(); + } +}