Merge "Allow users to pick a notification assistant."
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 62e7452..fd64db0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6272,6 +6272,9 @@
     <!-- [CHAR LIMIT=180] Notification importance summary -->
     <string name="show_silently_summary">Don\'t make sound, vibrate, or peek these notifications into view on the current screen.</string>
 
+    <!-- Default Apps > Default notification assistant -->
+    <string name="default_notification_assistant">Notification assistant</string>
+
     <!-- Sound & notification > Advanced section: Title for managing notification listeners option. [CHAR LIMIT=30] -->
     <string name="manage_notification_access_title">Notification access</string>
 
diff --git a/res/xml/advanced_apps.xml b/res/xml/advanced_apps.xml
index 7b1af10..7e2e9cd 100644
--- a/res/xml/advanced_apps.xml
+++ b/res/xml/advanced_apps.xml
@@ -66,6 +66,10 @@
             android:title="@string/sms_application_title"
             settings:keywords="@string/keywords_more_default_sms_app" />
 
+        <com.android.settings.applications.DefaultNotificationAssistantPreference
+            android:key="default_notification_asst_app"
+            android:title="@string/default_notification_assistant" />
+
     </PreferenceCategory>
 
     <com.android.settings.WorkOnlyCategory
diff --git a/res/xml/app_default_settings.xml b/res/xml/app_default_settings.xml
index c6e56a1..932fa60 100644
--- a/res/xml/app_default_settings.xml
+++ b/res/xml/app_default_settings.xml
@@ -56,6 +56,11 @@
         settings:keywords="@string/keywords_emergency_app"
         android:order="-15"/>
 
+    <com.android.settings.applications.DefaultNotificationAssistantPreference
+        android:key="default_notification_asst_app"
+        android:title="@string/default_notification_assistant"
+        android:order="-14"/>
+
     <Preference
         android:key="domain_urls"
         android:title="@string/domain_urls_title"
diff --git a/src/com/android/settings/AppListPreference.java b/src/com/android/settings/AppListPreference.java
index 1ebeeaa..1fe0c13 100644
--- a/src/com/android/settings/AppListPreference.java
+++ b/src/com/android/settings/AppListPreference.java
@@ -201,14 +201,21 @@
             try {
                 ActivityInfo activityInfo = AppGlobals.getPackageManager().getActivityInfo(
                         componentNames[i], 0, mUserId);
-                if (activityInfo == null) continue;
-                applicationNames.add(activityInfo.loadLabel(pm));
-                validatedComponentNames.add(componentNames[i].flattenToString());
-                entryDrawables.add(activityInfo.loadIcon(pm));
+                if (activityInfo != null) {
+                    applicationNames.add(activityInfo.loadLabel(pm));
+                    validatedComponentNames.add(componentNames[i].flattenToString());
+                    entryDrawables.add(activityInfo.loadIcon(pm));
+                } else {
+                    ApplicationInfo appInfo = pm.getApplicationInfoAsUser(
+                            componentNames[i].getPackageName().toString(), 0, mUserId);
+                    applicationNames.add(appInfo.loadLabel(pm));
+                    validatedComponentNames.add(componentNames[i].flattenToString());
+                    entryDrawables.add(appInfo.loadIcon(pm));
+                }
                 if (defaultCN != null && componentNames[i].equals(defaultCN)) {
                     selectedIndex = i;
                 }
-            } catch (RemoteException e) {
+            } catch (RemoteException|NameNotFoundException e) {
                 // Skip unknown packages.
             }
         }
diff --git a/src/com/android/settings/applications/DefaultNotificationAssistantPreference.java b/src/com/android/settings/applications/DefaultNotificationAssistantPreference.java
new file mode 100644
index 0000000..91fc0c8
--- /dev/null
+++ b/src/com/android/settings/applications/DefaultNotificationAssistantPreference.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright (C) 2016 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.applications;
+
+import com.android.settings.AppListPreference;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.provider.Settings;
+import android.service.notification.NotificationAssistantService;
+import android.util.AttributeSet;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.settings.R;
+import com.android.settings.utils.ManagedServiceSettings;
+
+public class DefaultNotificationAssistantPreference extends AppListPreference {
+    private static final String TAG = "DefaultNotiAssist";
+
+    private PackageManager mPm;
+    private final ManagedServiceSettings.Config mConfig;
+    private final Context mContext;
+
+    public DefaultNotificationAssistantPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mContext = context;
+        mPm = context.getPackageManager();
+        mConfig = getConfig();
+        setShowItemNone(true);
+        updateList(getServices());
+    }
+
+    @Override
+    protected boolean persistString(String value) {
+        Settings.Secure.putString(mContext.getContentResolver(), mConfig.setting, value);
+        setSummary(getEntry());
+        return true;
+    }
+
+    private void updateList(List<ServiceInfo> services) {
+        final ComponentName[] assistants = new ComponentName[services.size()];
+        for (int i = 0; i < services.size(); i++) {
+            assistants[i] = new ComponentName(services.get(i).packageName, services.get(i).name);
+        }
+        final String assistant =
+                Settings.Secure.getString(mContext.getContentResolver(), mConfig.setting);
+        setComponentNames(assistants, assistant == null ? null
+                : ComponentName.unflattenFromString(assistant));
+    }
+
+    private List<ServiceInfo> getServices() {
+        List<ServiceInfo> services = new ArrayList<>();
+        final int user = ActivityManager.getCurrentUser();
+
+        List<ResolveInfo> installedServices = mPm.queryIntentServicesAsUser(
+                new Intent(mConfig.intentAction),
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+                user);
+
+        for (int i = 0, count = installedServices.size(); i < count; i++) {
+            ResolveInfo resolveInfo = installedServices.get(i);
+            ServiceInfo info = resolveInfo.serviceInfo;
+
+            if (!mConfig.permission.equals(info.permission)) {
+                Slog.w(mConfig.tag, "Skipping " + mConfig.noun + " service "
+                        + info.packageName + "/" + info.name
+                        + ": it does not require the permission "
+                        + mConfig.permission);
+                continue;
+            }
+            services.add(info);
+        }
+        return services;
+    }
+
+    private ManagedServiceSettings.Config getConfig() {
+        final ManagedServiceSettings.Config c = new ManagedServiceSettings.Config();
+        c.tag = TAG;
+        c.setting = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
+        c.intentAction = NotificationAssistantService.SERVICE_INTERFACE;
+        c.permission = android.Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
+        c.noun = "notification assistant";
+        c.warningDialogTitle = R.string.notification_listener_security_warning_title;
+        c.warningDialogSummary = R.string.notification_listener_security_warning_summary;
+        c.emptyText = R.string.no_notification_listeners;
+        return c;
+    }
+}
\ No newline at end of file