Merge "Convert some security setting logic to PreferenceController"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5cd42c3..a809c78 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6926,7 +6926,7 @@
     <string name="notification_group_title">Notification category group</string>
 
     <!-- [CHAR LIMIT=100] Notification importance screen title -->
-    <string name="notification_importance_title">Importance</string>
+    <string name="notification_importance_title">Behavior</string>
 
     <!-- [CHAR LIMIT=100 BACKUP_MESSAGE_ID=1820188704793497324] Notification Importance: unspecified importance level description -->
     <string name="notification_importance_unspecified">Allow sound</string>
@@ -6991,6 +6991,9 @@
     <!-- [CHAR LIMIT=100] Notification Importance title: high importance level title -->
     <string name="notification_channel_summary_high">Urgent importance</string>
 
+    <!-- [CHAR LIMIT=100] Label for on/off toggle -->
+    <string name="notification_switch_label">Show notifications</string>
+
     <!-- Default Apps > Default notification assistant -->
     <string name="default_notification_assistant">Notification assistant</string>
 
@@ -7087,13 +7090,13 @@
     <string name="loading_notification_apps">Loading apps...</string>
 
     <!-- [CHAR LIMIT=NONE] Text appearing when app notifications are off -->
-    <string name="app_notifications_off_desc">Android is blocking this app\'s notifications from appearing on this device</string>
+    <string name="app_notifications_off_desc">At your request, Android is blocking this app\'s notifications from appearing on this device</string>
 
     <!-- [CHAR LIMIT=NONE] Text appearing when channel notifications are off -->
-    <string name="channel_notifications_off_desc">Android is blocking this category of notifications from appearing on this device</string>
+    <string name="channel_notifications_off_desc">At your request, Android is blocking this category of notifications from appearing on this device</string>
 
     <!-- [CHAR LIMIT=NONE] Text appearing when channel group notifications are off -->
-    <string name="channel_group_notifications_off_desc">Android is blocking this group of notifications from appearing on this device</string>
+    <string name="channel_group_notifications_off_desc">At your request, Android is blocking this group of notifications from appearing on this device</string>
 
     <!-- [CHAR LIMIT=NONE] App notification settings: channels title -->
     <string name="notification_channels">Categories</string>
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index fb2705a..c799c8b 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -15,7 +15,8 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:settings="http://schemas.android.com/apk/res-auto" >
+        xmlns:settings="http://schemas.android.com/apk/res-auto"
+        settings:initialExpandedChildrenCount="3">
 
     <com.android.settings.applications.LayoutPreference
         android:key="pref_app_header"
diff --git a/res/xml/notification_importance.xml b/res/xml/notification_importance.xml
index f801f3c..6f9cc0e 100644
--- a/res/xml/notification_importance.xml
+++ b/res/xml/notification_importance.xml
@@ -19,20 +19,15 @@
 
         <com.android.settings.widget.RadioButtonPreference
             android:key="importance_high"
-            android:title="@string/notification_importance_high_title"
-            android:summary="@string/notification_importance_high"
-        />
+            android:title="@string/notification_importance_high" />
         <com.android.settings.widget.RadioButtonPreference
             android:key="importance_default"
-            android:title="@string/notification_importance_default_title"
-            android:summary="@string/notification_importance_default" />
+            android:title="@string/notification_importance_default" />
         <com.android.settings.widget.RadioButtonPreference
             android:key="importance_low"
-            android:title="@string/notification_importance_low_title"
-            android:summary="@string/notification_importance_low" />
+            android:title="@string/notification_importance_low" />
         <com.android.settings.widget.RadioButtonPreference
             android:key="importance_min"
-            android:title="@string/notification_importance_min_title"
-            android:summary="@string/notification_importance_min" />
+            android:title="@string/notification_importance_min" />
 
 </PreferenceScreen>
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index af168d6..ef0f40b 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -135,7 +135,6 @@
         return new ArrayList<>(mControllers);
     }
 
-
     private void populateList() {
         if (!mDynamicPreferences.isEmpty()) {
             // If there's anything in mChannelGroups, we've called populateChannelList twice.
@@ -164,61 +163,41 @@
     }
 
     private void populateGroupList() {
-        PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
-        groupCategory.setTitle(R.string.notification_channels);
-        groupCategory.setKey(KEY_GENERAL_CATEGORY);
-        groupCategory.setOrderingAsAdded(true);
-        getPreferenceScreen().addPreference(groupCategory);
-        mDynamicPreferences.add(groupCategory);
         for (NotificationChannelGroup group : mChannelGroupList) {
-            final List<NotificationChannel> channels = group.getChannels();
-            int N = channels.size();
-            // app defined groups with one channel and channels with no group display the channel
-            // name and no summary and link directly to the channel page unless the group is blocked
-            if ((group.getId() == null || N < 2) && !group.isBlocked()) {
-                Collections.sort(channels, mChannelComparator);
-                for (int i = 0; i < N; i++) {
-                    final NotificationChannel channel = channels.get(i);
-                    populateSingleChannelPrefs(groupCategory, channel, "");
-                }
+            PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
+            groupCategory.setOrderingAsAdded(true);
+            getPreferenceScreen().addPreference(groupCategory);
+            mDynamicPreferences.add(groupCategory);
+            if (group.getId() == null) {
+                groupCategory.setTitle(mChannelGroupList.size() > 1
+                        ? R.string.notification_channels_other
+                        : R.string.notification_channels);
+                groupCategory.setKey(KEY_GENERAL_CATEGORY);
             } else {
-                populateGroupPreference(groupCategory, group, N);
+                groupCategory.setTitle(group.getName());
+                groupCategory.setKey(group.getId());
+                Bundle groupArgs = new Bundle();
+                groupArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
+                groupArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
+                groupArgs.putString(Settings.EXTRA_CHANNEL_GROUP_ID, group.getId());
+                Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
+                        ChannelGroupNotificationSettings.class.getName(),
+                        groupArgs, null, R.string.notification_group_title,
+                        null, false, getMetricsCategory());
+                groupCategory.setIntent(channelIntent);
+                populateGroupToggle(groupCategory, group);
+            }
+
+            final List<NotificationChannel> channels = group.getChannels();
+            Collections.sort(channels, mChannelComparator);
+            int N = channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel channel = channels.get(i);
+                populateSingleChannelPrefs(groupCategory, channel, group.isBlocked());
             }
         }
     }
 
-    void populateGroupPreference(PreferenceGroup parent,
-            final NotificationChannelGroup group, int channelCount) {
-        MasterSwitchPreference groupPref = new MasterSwitchPreference(
-                getPrefContext());
-        groupPref.setSwitchEnabled(mSuspendedAppsAdmin == null
-                && isChannelGroupBlockable(group));
-        groupPref.setKey(group.getId());
-        groupPref.setTitle(group.getName());
-        groupPref.setChecked(!group.isBlocked());
-        groupPref.setSummary(getResources().getQuantityString(
-                R.plurals.notification_group_summary, channelCount, channelCount));
-        Bundle groupArgs = new Bundle();
-        groupArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
-        groupArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
-        groupArgs.putString(Settings.EXTRA_CHANNEL_GROUP_ID, group.getId());
-        Intent groupIntent = Utils.onBuildStartFragmentIntent(getActivity(),
-                ChannelGroupNotificationSettings.class.getName(),
-                groupArgs, null, R.string.notification_group_title, null, false,
-                getMetricsCategory());
-        groupPref.setIntent(groupIntent);
-
-        groupPref.setOnPreferenceChangeListener(
-                (preference, o) -> {
-                    boolean value = (Boolean) o;
-                    group.setBlocked(!value);
-                    mBackend.updateChannelGroup(mPkg, mUid, group);
-
-                    return true;
-                });
-        parent.addPreference(groupPref);
-    }
-
     private Comparator<NotificationChannelGroup> mChannelGroupComparator =
             new Comparator<NotificationChannelGroup>() {
 
diff --git a/src/com/android/settings/notification/BlockPreferenceController.java b/src/com/android/settings/notification/BlockPreferenceController.java
index 5c366ea..6b65b0f 100644
--- a/src/com/android/settings/notification/BlockPreferenceController.java
+++ b/src/com/android/settings/notification/BlockPreferenceController.java
@@ -67,6 +67,8 @@
         LayoutPreference pref = (LayoutPreference) preference;
         SwitchBar bar = pref.findViewById(R.id.switch_bar);
         if (bar != null) {
+            bar.setSwitchBarText(R.string.notification_switch_label,
+                    R.string.notification_switch_label);
             bar.show();
             try {
                 bar.addOnSwitchChangeListener(this);
diff --git a/src/com/android/settings/notification/ChannelGroupNotificationSettings.java b/src/com/android/settings/notification/ChannelGroupNotificationSettings.java
index 68dd91b..707a559 100644
--- a/src/com/android/settings/notification/ChannelGroupNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelGroupNotificationSettings.java
@@ -19,7 +19,6 @@
 import android.app.NotificationChannel;
 import android.content.Context;
 import android.support.v7.preference.Preference;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -98,9 +97,7 @@
             Collections.sort(channels, mChannelComparator);
             for (NotificationChannel channel : channels) {
                 mDynamicPreferences.add(populateSingleChannelPrefs(
-                        getPreferenceScreen(), channel,
-                        ImportancePreferenceController.getImportanceSummary(
-                                getPrefContext(), channel)));
+                        getPreferenceScreen(), channel, mChannelGroup.isBlocked()));
             }
 
         }
diff --git a/src/com/android/settings/notification/ImportancePreferenceController.java b/src/com/android/settings/notification/ImportancePreferenceController.java
index ba47c54..977cd9a 100644
--- a/src/com/android/settings/notification/ImportancePreferenceController.java
+++ b/src/com/android/settings/notification/ImportancePreferenceController.java
@@ -73,7 +73,8 @@
             if (preference.isEnabled()) {
                 Intent channelIntent = Utils.onBuildStartFragmentIntent(mContext,
                         ChannelImportanceSettings.class.getName(),
-                        channelArgs, null, R.string.notification_importance_title, null,
+                        channelArgs, null,
+                        R.string.notification_importance_title, null,
                         false, getMetricsCategory());
                 preference.setIntent(channelIntent);
                 preference.setSummary(getImportanceSummary(mContext, mChannel));
@@ -82,23 +83,19 @@
     }
 
     protected static String getImportanceSummary(Context context, NotificationChannel channel) {
-        String title;
-        String summary = null;
+        String summary = "";
         int importance = channel.getImportance();
         switch (importance) {
             case IMPORTANCE_UNSPECIFIED:
-                title = context.getString(R.string.notification_importance_unspecified);
+                summary = context.getString(R.string.notification_importance_unspecified);
                 break;
             case NotificationManager.IMPORTANCE_MIN:
-                title = context.getString(R.string.notification_importance_min_title);
                 summary = context.getString(R.string.notification_importance_min);
                 break;
             case NotificationManager.IMPORTANCE_LOW:
-                title = context.getString(R.string.notification_importance_low_title);
                 summary = context.getString(R.string.notification_importance_low);
                 break;
             case NotificationManager.IMPORTANCE_DEFAULT:
-                title = context.getString(R.string.notification_importance_default_title);
                 if (SoundPreferenceController.hasValidSound(channel)) {
                     summary = context.getString(R.string.notification_importance_default);
                 } else {
@@ -107,7 +104,6 @@
                 break;
             case NotificationManager.IMPORTANCE_HIGH:
             case NotificationManager.IMPORTANCE_MAX:
-                title = context.getString(R.string.notification_importance_high_title);
                 if (SoundPreferenceController.hasValidSound(channel)) {
                     summary = context.getString(R.string.notification_importance_high);
                 } else {
@@ -118,10 +114,6 @@
                 return "";
         }
 
-        if (summary != null) {
-            return context.getString(R.string.notification_importance_divider, title, summary);
-        } else {
-            return title;
-        }
+        return summary;
     }
 }
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 9afb618..2a7e7d5 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -61,6 +61,7 @@
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
+import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceScreen;
@@ -214,7 +215,6 @@
         }
         for (ResolveInfo ri : resolveInfos) {
             final ActivityInfo activityInfo = ri.activityInfo;
-            final ApplicationInfo appInfo = activityInfo.applicationInfo;
             if (mAppRow.settingsIntent != null) {
                 if (DEBUG) {
                     Log.d(TAG, "Ignoring duplicate notification preference activity ("
@@ -225,7 +225,8 @@
             }
             mAppRow.settingsIntent = intent
                     .setPackage(null)
-                    .setClassName(activityInfo.packageName, activityInfo.name);
+                    .setClassName(activityInfo.packageName, activityInfo.name)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             if (mChannel != null) {
                 mAppRow.settingsIntent.putExtra(Notification.EXTRA_CHANNEL_ID, mChannel.getId());
             }
@@ -257,17 +258,41 @@
         return null;
     }
 
+    protected void populateGroupToggle(final PreferenceGroup parent,
+            NotificationChannelGroup group) {
+        RestrictedSwitchPreference preference = new RestrictedSwitchPreference(getPrefContext());
+        preference.setTitle(R.string.notification_switch_label);
+        preference.setEnabled(mSuspendedAppsAdmin == null
+                && isChannelGroupBlockable(group));
+        preference.setChecked(!group.isBlocked());
+        preference.setOnPreferenceClickListener(preference1 -> {
+            final boolean allowGroup = ((SwitchPreference) preference1).isChecked();
+            group.setBlocked(!allowGroup);
+            mBackend.updateChannelGroup(mAppRow.pkg, mAppRow.uid, group);
+
+            for (int i = 0; i < parent.getPreferenceCount(); i++) {
+                Preference pref = parent.getPreference(i);
+                if (pref instanceof MasterSwitchPreference) {
+                    ((MasterSwitchPreference) pref).setSwitchEnabled(allowGroup);
+                }
+            }
+            return true;
+        });
+
+        parent.addPreference(preference);
+    }
+
     protected Preference populateSingleChannelPrefs(PreferenceGroup parent,
-            final NotificationChannel channel, String summary) {
+            final NotificationChannel channel, final boolean groupBlocked) {
         MasterSwitchPreference channelPref = new MasterSwitchPreference(
                 getPrefContext());
         channelPref.setSwitchEnabled(mSuspendedAppsAdmin == null
                 && isChannelBlockable(channel)
-                && isChannelConfigurable(channel));
+                && isChannelConfigurable(channel)
+                && !groupBlocked);
         channelPref.setKey(channel.getId());
         channelPref.setTitle(channel.getName());
         channelPref.setChecked(channel.getImportance() != IMPORTANCE_NONE);
-        channelPref.setSummary(summary);
         Bundle channelArgs = new Bundle();
         channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
         channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
@@ -288,7 +313,6 @@
                         channel.setImportance(importance);
                         channel.lockFields(
                                 NotificationChannel.USER_LOCKED_IMPORTANCE);
-                        channelPref.setSummary(summary);
                         mBackend.updateChannel(mPkg, mUid, channel);
 
                         return true;
diff --git a/src/com/android/settings/widget/SwitchBar.java b/src/com/android/settings/widget/SwitchBar.java
index 3d30638..3c1e7c1 100644
--- a/src/com/android/settings/widget/SwitchBar.java
+++ b/src/com/android/settings/widget/SwitchBar.java
@@ -64,6 +64,8 @@
     private TextView mTextView;
     private String mLabel;
     private String mSummary;
+    private int mOnTextId;
+    private int mOffTextId;
 
     private boolean mLoggingIntialized;
     private boolean mDisabledByAdmin;
@@ -102,9 +104,7 @@
 
         mTextView = (TextView) findViewById(R.id.switch_text);
         mTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
-        mLabel = getResources().getString(R.string.switch_off_text);
         mSummarySpan = new TextAppearanceSpan(mContext, R.style.TextAppearance_Small_SwitchBar);
-        updateText();
         ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) mTextView.getLayoutParams();
         lp.setMarginStart(switchBarMarginStart);
 
@@ -117,6 +117,8 @@
         lp.setMarginEnd(switchBarMarginEnd);
         setBackgroundColor(switchBarBackgroundColor);
 
+        setSwitchBarText(R.string.switch_on_text, R.string.switch_off_text);
+
         addOnSwitchChangeListener(new OnSwitchChangeListener() {
             @Override
             public void onSwitchChanged(Switch switchView, boolean isChecked) {
@@ -139,11 +141,16 @@
     }
 
     public void setTextViewLabel(boolean isChecked) {
-        mLabel = getResources()
-                .getString(isChecked ? R.string.switch_on_text : R.string.switch_off_text);
+        mLabel = getResources().getString(isChecked ? mOnTextId : mOffTextId);
         updateText();
     }
 
+    public void setSwitchBarText(int onText, int offText) {
+        mOnTextId = onText;
+        mOffTextId = offText;
+        setTextViewLabel(isChecked());
+    }
+
     public void setSummary(String summary) {
         mSummary = summary;
         updateText();
diff --git a/tests/robotests/src/com/android/settings/widget/SwitchBarTest.java b/tests/robotests/src/com/android/settings/widget/SwitchBarTest.java
new file mode 100644
index 0000000..c805761
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/SwitchBarTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.RuntimeEnvironment.application;
+
+import android.content.Context;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SwitchBarTest {
+
+    private Context mContext;
+    private SwitchBar mBar;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mBar = new SwitchBar(application, Robolectric.buildAttributeSet().build());
+    }
+
+    @Test
+    public void testDefaultLabels() {
+        int defaultOnText = R.string.switch_on_text;
+        int defaultOffText = R.string.switch_off_text;
+        assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
+                .isEqualTo(mContext.getString(defaultOffText));
+
+        mBar.setChecked(true);
+        assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
+                .isEqualTo(mContext.getString(defaultOnText));
+    }
+
+    @Test
+    public void testCustomLabels() {
+        int onText = R.string.master_clear_progress_text;
+        int offText = R.string.manage_space_text;
+        mBar.setSwitchBarText(onText, offText);
+        assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
+                .isEqualTo(mContext.getString(offText));
+
+        mBar.setChecked(true);
+        assertThat(((TextView) mBar.findViewById(R.id.switch_text)).getText())
+                .isEqualTo(mContext.getString(onText));
+    }
+}