List apps that advertise notification settings.

Apps that have a CATEGORY_NOTIFICATION_PREFERENCES +
CATEGORY_DEFAULT activity will be listed in notification
settings, with a convenient link to that activity so the
user can tweak those settings.

Change-Id: Idc97b2aee3f070225822ebee1ecbeab79e7b9c2d
This commit is contained in:
Dan Sandler
2014-03-26 19:09:21 -04:00
parent 8ce107effa
commit b19460f4a1
4 changed files with 248 additions and 6 deletions

View File

@@ -0,0 +1,84 @@
<!--
Copyright (C) 2014 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/divider"
>
<ImageView
android:id="@android:id/icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_centerVertical="true"
android:layout_marginBottom="10dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="6dp"
android:layout_marginTop="10dp"
android:contentDescription="@null"
android:maxHeight="@android:dimen/app_icon_size"
android:maxWidth="@android:dimen/app_icon_size"
android:scaleType="fitCenter" />
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@android:id/button1"
android:layout_toEndOf="@android:id/icon"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textAlignment="viewStart"
android:labelFor="@android:id/button2" />
</RelativeLayout>
<!-- Divider -->
<ImageView
android:id="@id/divider"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toStartOf="@android:id/button2"
android:contentDescription="@null"
android:src="@drawable/nav_divider" />
<!-- Settings icon -->
<ImageView
android:id="@android:id/button2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignBottom="@android:id/widget_frame"
android:layout_alignParentEnd="true"
android:layout_alignTop="@android:id/widget_frame"
android:layout_centerVertical="true"
android:layout_margin="0dip"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/notification_app_settings_button"
android:padding="8dip"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_bt_config" />
</RelativeLayout>

View File

@@ -5041,4 +5041,8 @@
<!-- [CHAR LIMIT=20] Notifications settings: Apps section header -->
<string name="notification_settings_apps">Apps</string>
<!-- [CHAR LIMIT=NONE] Content description for per-app notification
settings button -->
<string name="notification_app_settings_button">Notification settings</string>
</resources>

View File

@@ -75,14 +75,11 @@
<Preference
android:title="Coming soon"
/>
-->
<PreferenceCategory
android:key="category_apps"
android:title="@string/notification_settings_apps"/>
<Preference
android:title="Coming soon"
/>
-->
android:title="@string/notification_settings_apps">
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -17,9 +17,16 @@
package com.android.settings;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.media.RingtoneManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -30,12 +37,26 @@ import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
public class NotificationSettings extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener, OnPreferenceClickListener {
private static final String TAG = "NotificationSettings";
private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
= new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_NOTIFICATION_PREFERENCES);
private static final String KEY_NOTIFICATION_SOUND = "notification_sound";
private static final String KEY_ZEN_MODE = "zen_mode";
private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access";
@@ -44,6 +65,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
private static final String KEY_SECURITY_CATEGORY = "category_security";
private static final String KEY_APPS_CATEGORY = "category_apps";
private static final String KEY_TWEAKS_CATEGORY = "category_tweaks"; // power toys, eng only
private static final int MSG_UPDATE_SOUND_SUMMARY = 2;
@@ -81,6 +103,84 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
}
};
private final ArrayList<AppNotificationInfo> mAppNotificationInfo
= new ArrayList<AppNotificationInfo>();
private final HashSet<String> mAppNotificationInfoPackages = new HashSet<String>();
private final Comparator<AppNotificationInfo> mAppComparator = new Comparator<AppNotificationInfo>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppNotificationInfo lhs, AppNotificationInfo rhs) {
return sCollator.compare(lhs.label, rhs.label);
}
};
private final Runnable mCollectAppsRunnable = new Runnable() {
@Override
public void run() {
synchronized (mAppNotificationInfo) {
mAppNotificationInfo.clear();
mAppNotificationInfoPackages.clear();
final PackageManager pm = getPackageManager();
final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo ri : resolveInfos) {
final ActivityInfo activityInfo = ri.activityInfo;
final ApplicationInfo appInfo = activityInfo.applicationInfo;
if (mAppNotificationInfoPackages.contains(activityInfo.packageName)) {
Log.v(TAG, "Ignoring duplicate notification preference activity ("
+ activityInfo.name + ") for package "
+ activityInfo.packageName);
continue;
}
final AppNotificationInfo info = new AppNotificationInfo();
mAppNotificationInfoPackages.add(activityInfo.packageName);
info.label = appInfo.loadLabel(pm);
info.icon = appInfo.loadIcon(pm);
info.name = activityInfo.name;
info.pkg = activityInfo.packageName;
mAppNotificationInfo.add(info);
}
Collections.sort(mAppNotificationInfo, mAppComparator);
mHandler.post(mRefreshAppsListRunnable);
}
}
};
private final Runnable mRefreshAppsListRunnable = new Runnable() {
@Override
public void run() {
final PreferenceScreen root = getPreferenceScreen();
final PreferenceGroup appsCategory = (PreferenceGroup)
root.findPreference(KEY_APPS_CATEGORY);
appsCategory.removeAll();
synchronized (mAppNotificationInfo) {
if (mAppNotificationInfo.size() == 0) {
root.removePreference(appsCategory);
return;
}
final int N = mAppNotificationInfo.size();
for (int i = 0; i < N; i++) {
final AppNotificationInfo info = mAppNotificationInfo.get(i);
Preference pref = new AppNotificationPreference(root.getContext());
pref.setTitle(info.label);
pref.setIcon(info.icon);
pref.setIntent(new Intent(Intent.ACTION_MAIN)
.setClassName(info.pkg, info.name));
appsCategory.addPreference(pref);
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -156,6 +256,11 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
refreshNotificationListeners();
lookupRingtoneNames();
loadAppsList();
}
private void loadAppsList() {
AsyncTask.execute(mCollectAppsRunnable);
}
@Override
@@ -252,4 +357,56 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private void lookupRingtoneNames() {
new Thread(mRingtoneLookupRunnable).start();
}
// === Per-app notification settings row ==
private static class AppNotificationPreference extends Preference {
private Intent mIntent;
public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.notification_app);
}
public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public AppNotificationPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AppNotificationPreference(Context context) {
this(context, null);
}
public void setIntent(Intent intent) {
mIntent = intent;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
icon.setImageDrawable(getIcon());
TextView title = (TextView) view.findViewById(android.R.id.title);
title.setText(getTitle());
ImageView settingsButton = (ImageView) view.findViewById(android.R.id.button2);
settingsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getContext().startActivity(mIntent);
}
});
}
}
private static class AppNotificationInfo {
public Drawable icon;
public CharSequence label;
public String name;
public String pkg;
}
}