From 08531a81cb34dc45f0da4ca88e8530169831c7d2 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Thu, 7 May 2015 17:45:43 -0400 Subject: [PATCH] Settings: New DND access settings page. - New advanced notification settings subpage for managing apps that have requested the ability to manage notification policy. - Create new "Advanced" section at the bottom of notification settings for this and the existing Notification access settings page. Bug: 18298798 Change-Id: Ib415e634980d37d6492799f67a6619700ee2a01c --- AndroidManifest.xml | 19 +- res/values/strings.xml | 11 +- res/xml/notification_settings.xml | 13 ++ src/com/android/settings/Settings.java | 1 + .../android/settings/SettingsActivity.java | 2 + .../notification/NotificationSettings.java | 30 ++-- .../notification/ZenAccessSettings.java | 169 ++++++++++++++++++ 7 files changed, 231 insertions(+), 14 deletions(-) create mode 100644 src/com/android/settings/notification/ZenAccessSettings.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 12551d0cfa1..500c0aa12cd 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2251,7 +2251,24 @@ + android:resource="@id/notification_settings" /> + + + + + + + + + + + + + Notification + + Advanced + Pulse notification light @@ -5999,7 +6002,7 @@ Vibrate - + Notification access @@ -6028,6 +6031,12 @@ to dismiss these notifications or touch action buttons within them. + + Do Not Disturb access + + + No installed apps have requested Do Not Disturb access + Loading apps... diff --git a/res/xml/notification_settings.xml b/res/xml/notification_settings.xml index 7956a6d4280..72a189d1bb4 100644 --- a/res/xml/notification_settings.xml +++ b/res/xml/notification_settings.xml @@ -120,6 +120,12 @@ android:value="com.android.settings.Settings$NotificationAppListActivity" /> + + + + + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index b91275a542d..5a6a2f0f5c4 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -91,6 +91,7 @@ public class Settings extends SettingsActivity { public static class NotificationStationActivity extends SettingsActivity { /* empty */ } public static class UserSettingsActivity extends SettingsActivity { /* empty */ } public static class NotificationAccessSettingsActivity extends SettingsActivity { /* empty */ } + public static class ZenAccessSettingsActivity extends SettingsActivity { /* empty */ } public static class ConditionProviderSettingsActivity extends SettingsActivity { /* empty */ } public static class UsbSettingsActivity extends SettingsActivity { /* empty */ } public static class TrustedCredentialsSettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 89dbc99d1ae..aa492f319a3 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -103,6 +103,7 @@ import com.android.settings.notification.NotificationAccessSettings; import com.android.settings.notification.NotificationSettings; import com.android.settings.notification.NotificationStation; import com.android.settings.notification.OtherSoundSettings; +import com.android.settings.notification.ZenAccessSettings; import com.android.settings.notification.ZenModeEventRuleSettings; import com.android.settings.notification.ZenModeExternalRuleSettings; import com.android.settings.notification.ZenModePrioritySettings; @@ -328,6 +329,7 @@ public class SettingsActivity extends Activity DreamSettings.class.getName(), UserSettings.class.getName(), NotificationAccessSettings.class.getName(), + ZenAccessSettings.class.getName(), PrintSettingsFragment.class.getName(), PrintJobSettingsFragment.class.getName(), TrustedCredentialsSettings.class.getName(), diff --git a/src/com/android/settings/notification/NotificationSettings.java b/src/com/android/settings/notification/NotificationSettings.java index cdff32f26b4..00f54978db1 100644 --- a/src/com/android/settings/notification/NotificationSettings.java +++ b/src/com/android/settings/notification/NotificationSettings.java @@ -79,6 +79,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements private static final String KEY_NOTIFICATION_PULSE = "notification_pulse"; private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "lock_screen_notifications"; private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access"; + private static final String KEY_ZEN_ACCESS = "manage_zen_access"; private static final int SAMPLE_CUTOFF = 2000; // manually cap sample playback at 2 seconds @@ -101,6 +102,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements private TwoStatePreference mNotificationPulse; private DropDownPreference mLockscreen; private Preference mNotificationAccess; + private Preference mZenAccess; private boolean mSecure; private int mLockscreenSelectedValue; private ComponentName mSuppressor; @@ -153,6 +155,8 @@ public class NotificationSettings extends SettingsPreferenceFragment implements mNotificationAccess = findPreference(KEY_NOTIFICATION_ACCESS); refreshNotificationListeners(); + mZenAccess = findPreference(KEY_ZEN_ACCESS); + refreshZenAccess(); updateRingerMode(); updateEffectsSuppressor(); } @@ -161,6 +165,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements public void onResume() { super.onResume(); refreshNotificationListeners(); + refreshZenAccess(); lookupRingtoneNames(); mSettingsObserver.register(true); mReceiver.register(true); @@ -471,23 +476,24 @@ public class NotificationSettings extends SettingsPreferenceFragment implements private void refreshNotificationListeners() { if (mNotificationAccess != null) { - final int total = NotificationAccessSettings.getListenersCount(mPM); - if (total == 0) { - getPreferenceScreen().removePreference(mNotificationAccess); + final int n = NotificationAccessSettings.getEnabledListenersCount(mContext); + if (n == 0) { + mNotificationAccess.setSummary(getResources().getString( + R.string.manage_notification_access_summary_zero)); } else { - final int n = NotificationAccessSettings.getEnabledListenersCount(mContext); - if (n == 0) { - mNotificationAccess.setSummary(getResources().getString( - R.string.manage_notification_access_summary_zero)); - } else { - mNotificationAccess.setSummary(String.format(getResources().getQuantityString( - R.plurals.manage_notification_access_summary_nonzero, - n, n))); - } + mNotificationAccess.setSummary(String.format(getResources().getQuantityString( + R.plurals.manage_notification_access_summary_nonzero, + n, n))); } } } + // === Zen access === + + private void refreshZenAccess() { + // noop for now + } + // === Callbacks === private final class SettingsObserver extends ContentObserver { diff --git a/src/com/android/settings/notification/ZenAccessSettings.java b/src/com/android/settings/notification/ZenAccessSettings.java new file mode 100644 index 00000000000..a9f02a9d7c9 --- /dev/null +++ b/src/com/android/settings/notification/ZenAccessSettings.java @@ -0,0 +1,169 @@ +/* + * 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 android.app.ListFragment; +import android.app.NotificationManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.util.ArraySet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.android.settings.R; + +import java.util.List; + +public class ZenAccessSettings extends ListFragment { + private static final boolean SHOW_PACKAGE_NAME = false; + + private Context mContext; + private PackageManager mPkgMan; + private NotificationManager mNoMan; + private Adapter mAdapter; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mContext = getActivity(); + mPkgMan = mContext.getPackageManager(); + mNoMan = mContext.getSystemService(NotificationManager.class); + mAdapter = new Adapter(mContext); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + final View v = inflater.inflate(R.layout.managed_service_settings, container, false); + final TextView empty = (TextView) v.findViewById(android.R.id.empty); + empty.setText(R.string.zen_access_empty_text); + return v; + } + + @Override + public void onResume() { + super.onResume(); + reloadList(); + } + + private void reloadList() { + mAdapter.clear(); + final ArraySet requesting = mNoMan.getPackagesRequestingNotificationPolicyAccess(); + if (requesting != null && !requesting.isEmpty()) { + final List apps = mPkgMan.getInstalledApplications(0); + if (apps != null) { + for (ApplicationInfo app : apps) { + if (requesting.contains(app.packageName)) { + mAdapter.add(app); + } + } + } + } + mAdapter.sort(new PackageItemInfo.DisplayNameComparator(mPkgMan)); + getListView().setAdapter(mAdapter); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + final ApplicationInfo info = mAdapter.getItem(position); + final boolean hasAccess = hasAccess(info.packageName); + setAccess(info.packageName, !hasAccess); + mAdapter.notifyDataSetChanged(); + } + + private boolean hasAccess(String pkg) { + return mNoMan.isNotificationPolicyAccessGrantedForPackage(pkg); + } + + private void setAccess(String pkg, boolean access) { + mNoMan.setNotificationPolicyAccessGranted(pkg, access); + } + + private static class ViewHolder { + ImageView icon; + TextView name; + CheckBox checkbox; + TextView description; + } + + private final class Adapter extends ArrayAdapter { + final LayoutInflater mInflater; + + Adapter(Context context) { + super(context, 0, 0); + mInflater = (LayoutInflater) + getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + public boolean hasStableIds() { + return true; + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + View v; + if (convertView == null) { + v = newView(parent); + } else { + v = convertView; + } + bindView(v, position); + return v; + } + + public View newView(ViewGroup parent) { + View v = mInflater.inflate(R.layout.managed_service_item, parent, false); + ViewHolder h = new ViewHolder(); + h.icon = (ImageView) v.findViewById(R.id.icon); + h.name = (TextView) v.findViewById(R.id.name); + h.checkbox = (CheckBox) v.findViewById(R.id.checkbox); + h.description = (TextView) v.findViewById(R.id.description); + v.setTag(h); + return v; + } + + public void bindView(View view, int position) { + ViewHolder vh = (ViewHolder) view.getTag(); + ApplicationInfo info = getItem(position); + + vh.icon.setImageDrawable(info.loadIcon(mPkgMan)); + vh.name.setText(info.loadLabel(mPkgMan)); + if (SHOW_PACKAGE_NAME) { + vh.description.setText(info.packageName); + vh.description.setVisibility(View.VISIBLE); + } else { + vh.description.setVisibility(View.GONE); + } + vh.checkbox.setChecked(hasAccess(info.packageName)); + } + + } + +}