App-level notification configuration settings page.

New sub-page off of notification settings to ban/unban
apps and navigate to an app's notification configuration
activity (if configured).

Centralized all notification settings artifacts under a new
settings subpackage.

Bug: 13935172
Change-Id: I53b75c02f0091900734d17dc9217035d0df9b466
This commit is contained in:
John Spurlock
2014-04-08 14:08:21 -04:00
parent 7476f5b904
commit 4a35051565
22 changed files with 820 additions and 427 deletions

View File

@@ -93,6 +93,10 @@ import com.android.settings.inputmethod.UserDictionaryList;
import com.android.settings.location.LocationSettings;
import com.android.settings.nfc.AndroidBeam;
import com.android.settings.nfc.PaymentSettings;
import com.android.settings.notification.NotificationAccessSettings;
import com.android.settings.notification.NotificationSettings;
import com.android.settings.notification.NotificationStation;
import com.android.settings.notification.ZenModeSettings;
import com.android.settings.print.PrintJobSettingsFragment;
import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.tts.TextToSpeechSettings;

View File

@@ -0,0 +1,550 @@
/*
* 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.
*/
package com.android.settings.notification;
import android.animation.LayoutTransition;
import android.app.AlertDialog;
import android.app.INotificationManager;
import android.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.PathShape;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SectionIndexer;
import android.widget.TextView;
import com.android.settings.R;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class AppNotificationSettings extends ListFragment {
private static final String TAG = "AppNotificationSettings";
private static final boolean DEBUG = true;
private static final String SECTION_BEFORE_A = "*";
private static final String SECTION_AFTER_Z = "**";
private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
= new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_NOTIFICATION_PREFERENCES);
private final Handler mHandler = new Handler();
private final ArrayMap<String, AppRow> mRows = new ArrayMap<String, AppRow>();
private final ArrayList<AppRow> mSortedRows = new ArrayList<AppRow>();
private final ArrayList<String> mSections = new ArrayList<String>();
private Context mContext;
private LayoutInflater mInflater;
private NotificationAppAdapter mAdapter;
private Signature[] mSystemSignature;
private Parcelable mListViewState;
private Backend mBackend = new Backend();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mAdapter = new NotificationAppAdapter(mContext);
getActivity().setTitle(R.string.app_notifications_title);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.notification_app_list, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
repositionScrollbar();
getListView().setAdapter(mAdapter);
}
@Override
public void onPause() {
super.onPause();
if (DEBUG) Log.d(TAG, "Saving listView state");
mListViewState = getListView().onSaveInstanceState();
}
@Override
public void onResume() {
super.onResume();
loadAppsList();
}
public void setBackend(Backend backend) {
mBackend = backend;
}
private void loadAppsList() {
AsyncTask.execute(mCollectAppsRunnable);
}
private String getSection(CharSequence label) {
if (label == null || label.length() == 0) return SECTION_BEFORE_A;
final char c = Character.toUpperCase(label.charAt(0));
if (c < 'A') return SECTION_BEFORE_A;
if (c > 'Z') return SECTION_AFTER_Z;
return Character.toString(c);
}
private void repositionScrollbar() {
final int sbWidthPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
getListView().getScrollBarSize(),
getResources().getDisplayMetrics());
final View parent = (View)getView().getParent();
final int eat = Math.min(sbWidthPx, parent.getPaddingEnd());
if (eat <= 0) return;
if (DEBUG) Log.d(TAG, String.format("Eating %dpx into %dpx padding for %dpx scroll, ld=%d",
eat, parent.getPaddingEnd(), sbWidthPx, getListView().getLayoutDirection()));
parent.setPaddingRelative(parent.getPaddingStart(), parent.getPaddingTop(),
parent.getPaddingEnd() - eat, parent.getPaddingBottom());
}
private boolean isSystemApp(PackageInfo pkg) {
if (mSystemSignature == null) {
mSystemSignature = new Signature[]{ getSystemSignature() };
}
return mSystemSignature[0] != null && mSystemSignature[0].equals(getFirstSignature(pkg));
}
private static Signature getFirstSignature(PackageInfo pkg) {
if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
return pkg.signatures[0];
}
return null;
}
private Signature getSystemSignature() {
final PackageManager pm = mContext.getPackageManager();
try {
final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
return getFirstSignature(sys);
} catch (NameNotFoundException e) {
}
return null;
}
private void showDialog(final View v, final AppRow row) {
final RelativeLayout layout = (RelativeLayout)
mInflater.inflate(R.layout.notification_app_dialog, null);
final ImageView icon = (ImageView) layout.findViewById(android.R.id.icon);
icon.setImageDrawable(row.icon);
final TextView title = (TextView) layout.findViewById(android.R.id.title);
title.setText(row.label);
final CheckBox showBox = (CheckBox) layout.findViewById(android.R.id.button1);
showBox.setChecked(!row.banned);
final OnCheckedChangeListener showListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
boolean success = mBackend.setNotificationsBanned(row.pkg, row.uid, !isChecked);
if (success) {
row.banned = !isChecked;
mAdapter.bindView(v, row, true /*animate*/);
} else {
showBox.setOnCheckedChangeListener(null);
showBox.setChecked(!isChecked);
showBox.setOnCheckedChangeListener(this);
}
}
};
showBox.setOnCheckedChangeListener(showListener);
final AlertDialog d = new AlertDialog.Builder(mContext)
.setView(layout)
.setPositiveButton(R.string.app_notifications_dialog_done, null)
.create();
d.show();
}
private static class ViewHolder {
ViewGroup row;
ViewGroup appButton;
ImageView icon;
ImageView banBadge;
ImageView priBadge;
TextView title;
View settingsDivider;
ImageView settingsButton;
View rowDivider;
}
private class NotificationAppAdapter extends ArrayAdapter<Row> implements SectionIndexer {
private final ShapeDrawable mBanShape, mPriShape;
public NotificationAppAdapter(Context context) {
super(context, 0, 0);
final int s = context.getResources()
.getDimensionPixelSize(R.dimen.notification_app_icon_badge_size);
mBanShape = shape(banPath(s), s);
mPriShape = shape(priPath(s), s);
}
private ShapeDrawable shape(Path path, int s) {
final ShapeDrawable sd = new ShapeDrawable(new PathShape(path, s, s));
sd.getPaint().setStyle(Paint.Style.STROKE);
sd.getPaint().setColor(0xffffffff);
sd.getPaint().setStrokeWidth(s / 12);
sd.setIntrinsicWidth(s);
sd.setIntrinsicHeight(s);
return sd;
}
private Path banPath(int s) {
final Path p = new Path();
final int d = s / 5;
p.moveTo(d, d); p.lineTo(s - d, s - d);
p.moveTo(d, s - d); p.lineTo(s - d, d);
return p;
}
private Path priPath(int s) {
final Path p = new Path();
final int d = s / 5;
p.moveTo(s / 2, d); p.lineTo(s / 2, s - d);
return p;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
Row r = getItem(position);
return r instanceof AppRow ? 1 : 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
Row r = getItem(position);
View v;
if (convertView == null) {
v = newView(parent, r);
} else {
v = convertView;
}
bindView(v, r, false /*animate*/);
return v;
}
public View newView(ViewGroup parent, Row r) {
if (!(r instanceof AppRow)) {
return mInflater.inflate(R.layout.notification_app_section, parent, false);
}
final View v = mInflater.inflate(R.layout.notification_app, parent, false);
final ViewHolder vh = new ViewHolder();
vh.row = (ViewGroup) v;
vh.row.setLayoutTransition(new LayoutTransition());
vh.appButton = (ViewGroup) v.findViewById(android.R.id.button1);
vh.appButton.setLayoutTransition(new LayoutTransition());
vh.icon = (ImageView) v.findViewById(android.R.id.icon);
vh.banBadge = (ImageView) v.findViewById(android.R.id.icon1);
vh.banBadge.setImageDrawable(mBanShape);
vh.priBadge = (ImageView) v.findViewById(android.R.id.icon2);
vh.priBadge.setImageDrawable(mPriShape);
vh.title = (TextView) v.findViewById(android.R.id.title);
vh.settingsDivider = v.findViewById(R.id.settings_divider);
vh.settingsButton = (ImageView) v.findViewById(android.R.id.button2);
vh.rowDivider = v.findViewById(R.id.row_divider);
v.setTag(vh);
return v;
}
private void enableLayoutTransitions(ViewGroup vg, boolean enabled) {
if (enabled) {
vg.getLayoutTransition().enableTransitionType(LayoutTransition.APPEARING);
vg.getLayoutTransition().enableTransitionType(LayoutTransition.DISAPPEARING);
} else {
vg.getLayoutTransition().disableTransitionType(LayoutTransition.APPEARING);
vg.getLayoutTransition().disableTransitionType(LayoutTransition.DISAPPEARING);
}
}
public void bindView(final View view, Row r, boolean animate) {
if (!(r instanceof AppRow)) {
TextView tv = (TextView)view;
tv.setText(r.section);
return;
}
final AppRow row = (AppRow)r;
final ViewHolder vh = (ViewHolder) view.getTag();
enableLayoutTransitions(vh.row, animate);
vh.rowDivider.setVisibility(row.first ? View.GONE : View.VISIBLE);
vh.appButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showDialog(view, row);
}
});
enableLayoutTransitions(vh.appButton, animate);
vh.icon.setImageDrawable(row.icon);
vh.banBadge.setVisibility(row.banned ? View.VISIBLE : View.GONE);
vh.priBadge.setVisibility(row.priority ? View.VISIBLE : View.GONE);
vh.title.setText(row.label);
final boolean showSettings = !row.banned && row.settingsIntent != null;
vh.settingsDivider.setVisibility(showSettings ? View.VISIBLE : View.GONE);
vh.settingsButton.setVisibility(showSettings ? View.VISIBLE : View.GONE);
vh.settingsButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (row.settingsIntent != null) {
getContext().startActivity(row.settingsIntent);
}
}
});
}
@Override
public Object[] getSections() {
return mSections.toArray(new Object[mSections.size()]);
}
@Override
public int getPositionForSection(int sectionIndex) {
final String section = mSections.get(sectionIndex);
final int n = getCount();
for (int i = 0; i < n; i++) {
final Row r = getItem(i);
if (r.section.equals(section)) {
return i;
}
}
return 0;
}
@Override
public int getSectionForPosition(int position) {
Row row = getItem(position);
return mSections.indexOf(row.section);
}
}
private static class Row {
public String section;
}
private static class AppRow extends Row {
public String pkg;
public int uid;
public Drawable icon;
public CharSequence label;
public Intent settingsIntent;
public boolean banned;
public boolean priority;
public boolean first;
}
private static final Comparator<AppRow> mRowComparator = new Comparator<AppRow>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppRow lhs, AppRow rhs) {
return sCollator.compare(lhs.label, rhs.label);
}
};
private final Runnable mCollectAppsRunnable = new Runnable() {
@Override
public void run() {
synchronized (mRows) {
final long start = SystemClock.uptimeMillis();
if (DEBUG) Log.d(TAG, "Collecting apps...");
mRows.clear();
mSortedRows.clear();
// collect all non-system apps
final PackageManager pm = mContext.getPackageManager();
for (PackageInfo pkg : pm.getInstalledPackages(PackageManager.GET_SIGNATURES)) {
if (pkg.applicationInfo == null || isSystemApp(pkg)) {
if (DEBUG) Log.d(TAG, "Skipping " + pkg.packageName);
continue;
}
final AppRow row = new AppRow();
row.pkg = pkg.packageName;
row.uid = pkg.applicationInfo.uid;
try {
row.label = pkg.applicationInfo.loadLabel(pm);
} catch (Throwable t) {
Log.e(TAG, "Error loading application label for " + row.pkg, t);
row.label = row.pkg;
}
row.icon = pkg.applicationInfo.loadIcon(pm);
row.banned = mBackend.getNotificationsBanned(row.pkg, row.uid);
row.priority = mBackend.getHighPriority(row.pkg, row.uid);
mRows.put(row.pkg, row);
}
// collect config activities
Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is " + APP_NOTIFICATION_PREFS_CATEGORY_INTENT);
final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
PackageManager.MATCH_DEFAULT_ONLY);
if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities");
for (ResolveInfo ri : resolveInfos) {
final ActivityInfo activityInfo = ri.activityInfo;
final ApplicationInfo appInfo = activityInfo.applicationInfo;
final AppRow row = mRows.get(appInfo.packageName);
if (row == null) {
Log.v(TAG, "Ignoring notification preference activity ("
+ activityInfo.name + ") for unknown package "
+ activityInfo.packageName);
continue;
}
if (row.settingsIntent != null) {
Log.v(TAG, "Ignoring duplicate notification preference activity ("
+ activityInfo.name + ") for package "
+ activityInfo.packageName);
continue;
}
row.settingsIntent = new Intent(Intent.ACTION_MAIN)
.setClassName(activityInfo.packageName, activityInfo.name);
}
// sort rows
mSortedRows.addAll(mRows.values());
Collections.sort(mSortedRows, mRowComparator);
// compute sections
mSections.clear();
String section = null;
for (AppRow r : mSortedRows) {
r.section = getSection(r.label);
if (!r.section.equals(section)) {
section = r.section;
mSections.add(section);
}
}
mHandler.post(mRefreshAppsListRunnable);
final long elapsed = SystemClock.uptimeMillis() - start;
if (DEBUG) Log.d(TAG, "Collected " + mRows.size() + " apps in " + elapsed + "ms");
}
}
};
private void refreshDisplayedItems() {
if (DEBUG) Log.d(TAG, "Refreshing apps...");
mAdapter.clear();
synchronized (mSortedRows) {
String section = null;
final int N = mSortedRows.size();
boolean first = true;
for (int i = 0; i < N; i++) {
final AppRow row = mSortedRows.get(i);
if (!row.section.equals(section)) {
section = row.section;
Row r = new Row();
r.section = section;
mAdapter.add(r);
first = true;
}
row.first = first;
mAdapter.add(row);
first = false;
}
}
if (mListViewState != null) {
if (DEBUG) Log.d(TAG, "Restoring listView state");
getListView().onRestoreInstanceState(mListViewState);
mListViewState = null;
}
if (DEBUG) Log.d(TAG, "Refreshed " + mSortedRows.size() + " displayed items");
}
private final Runnable mRefreshAppsListRunnable = new Runnable() {
@Override
public void run() {
refreshDisplayedItems();
}
};
public static class Backend {
public boolean setNotificationsBanned(String pkg, int uid, boolean banned) {
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
nm.setNotificationsEnabledForPackage(pkg, uid, !banned);
return true;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return false;
}
}
public boolean getNotificationsBanned(String pkg, int uid) {
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
final boolean enabled = nm.areNotificationsEnabledForPackage(pkg, uid);
return !enabled;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return false;
}
}
public boolean getHighPriority(String pkg, int uid) {
// TODO get high-pri state from NoMan
return false;
}
public boolean setHighPriority(String pkg, int uid, boolean priority) {
// TODO save high-pri state to NoMan
return true;
}
}
}

View File

@@ -14,41 +14,42 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.ListFragment;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.util.Slog;
import android.widget.ArrayAdapter;
import android.app.ListFragment;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.provider.Settings;
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.HashSet;
import java.util.List;

View File

@@ -14,57 +14,40 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
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;
import android.os.Message;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.preference.TwoStatePreference;
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;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.SoundSettings;
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_NOTIFICATION_ACCESS = "manage_notification_access";
private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "toggle_lock_screen_notifications";
private static final String KEY_HEADS_UP = "heads_up";
private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
private static final String KEY_HEADS_UP = "heads_up";
private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "toggle_lock_screen_notifications";
private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access";
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;
@@ -74,10 +57,9 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private Preference mNotificationSoundPreference;
private Preference mNotificationAccess;
private CheckBoxPreference mLockscreenNotifications;
private CheckBoxPreference mHeadsUp;
private CheckBoxPreference mNotificationPulse;
private PreferenceGroup mAppsPreference;
private TwoStatePreference mLockscreenNotifications;
private TwoStatePreference mHeadsUp;
private TwoStatePreference mNotificationPulse;
private final Runnable mRingtoneLookupRunnable = new Runnable() {
@Override
@@ -104,80 +86,6 @@ 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() {
synchronized (mAppNotificationInfo) {
mAppsPreference.removeAll();
Preference p = getPreferenceScreen().findPreference(mAppsPreference.getKey());
final int N = mAppNotificationInfo.size();
if (N == 0 && p != null) {
getPreferenceScreen().removePreference(p);
} else if (N > 0 && p == null) {
getPreferenceScreen().addPreference(mAppsPreference);
}
for (int i = 0; i < N; i++) {
final AppNotificationInfo info = mAppNotificationInfo.get(i);
Preference pref = new AppNotificationPreference(mContext);
pref.setTitle(info.label);
pref.setIcon(info.icon);
pref.setIntent(new Intent(Intent.ACTION_MAIN)
.setClassName(info.pkg, info.name));
mAppsPreference.addPreference(pref);
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -189,8 +97,6 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
addPreferencesFromResource(R.xml.notification_settings);
final PreferenceScreen root = getPreferenceScreen();
final PreferenceGroup securityCategory = (PreferenceGroup)
root.findPreference(KEY_SECURITY_CATEGORY);
PreferenceGroup tweaksCategory = (PreferenceGroup)
root.findPreference(KEY_TWEAKS_CATEGORY);
@@ -207,18 +113,16 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
refreshNotificationListeners();
mLockscreenNotifications
= (CheckBoxPreference) root.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
= (TwoStatePreference) root.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
if (mLockscreenNotifications != null) {
if (!getDeviceLockscreenNotificationsEnabled()) {
if (securityCategory != null) {
securityCategory.removePreference(mLockscreenNotifications);
}
root.removePreference(mLockscreenNotifications);
} else {
mLockscreenNotifications.setChecked(getLockscreenAllowPrivateNotifications());
}
}
mHeadsUp = (CheckBoxPreference) findPreference(KEY_HEADS_UP);
mHeadsUp = (TwoStatePreference) findPreference(KEY_HEADS_UP);
if (mHeadsUp != null) {
updateHeadsUpMode(resolver);
mHeadsUp.setOnPreferenceChangeListener(this);
@@ -231,7 +135,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
}
});
}
mNotificationPulse = (CheckBoxPreference) findPreference(KEY_NOTIFICATION_PULSE);
mNotificationPulse = (TwoStatePreference) findPreference(KEY_NOTIFICATION_PULSE);
if (mNotificationPulse != null
&& getResources().getBoolean(
@@ -246,8 +150,6 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
Log.e(TAG, Settings.System.NOTIFICATION_LIGHT_PULSE + " not found");
}
}
mAppsPreference = (PreferenceGroup) root.findPreference(KEY_APPS_CATEGORY);
root.removePreference(mAppsPreference);
}
@Override
@@ -256,11 +158,6 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
refreshNotificationListeners();
lookupRingtoneNames();
loadAppsList();
}
private void loadAppsList() {
AsyncTask.execute(mCollectAppsRunnable);
}
@Override
@@ -330,14 +227,9 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private void refreshNotificationListeners() {
if (mNotificationAccess != null) {
final PreferenceGroup securityCategory
= (PreferenceGroup) getPreferenceScreen().findPreference(KEY_SECURITY_CATEGORY);
final int total = NotificationAccessSettings.getListenersCount(mPM);
if (total == 0) {
if (securityCategory != null) {
securityCategory.removePreference(mNotificationAccess);
}
getPreferenceScreen().removePreference(mNotificationAccess);
} else {
final int n = getNumEnabledNotificationListeners();
if (n == 0) {
@@ -357,56 +249,4 @@ 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;
}
}

View File

@@ -14,16 +14,14 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.service.notification.INotificationListener;
import android.app.INotificationManager;
import android.app.Notification;
import android.service.notification.StatusBarNotification;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -37,6 +35,8 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.INotificationListener;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,6 +48,9 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

View File

@@ -14,13 +14,13 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.database.ContentObserver;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -28,6 +28,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings.Global;
import android.provider.SearchIndexableResource;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
@@ -45,6 +46,9 @@ import android.widget.ScrollView;
import android.widget.Switch;
import android.widget.TextView;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;

View File

@@ -17,27 +17,27 @@
package com.android.settings.search;
import android.provider.SearchIndexableResource;
import com.android.settings.DataUsageSummary;
import com.android.settings.DateTimeSettings;
import com.android.settings.DevelopmentSettings;
import com.android.settings.DeviceInfoSettings;
import com.android.settings.DisplaySettings;
import com.android.settings.HomeSettings;
import com.android.settings.NotificationSettings;
import com.android.settings.PrivacySettings;
import com.android.settings.R;
import com.android.settings.SecuritySettings;
import com.android.settings.SoundSettings;
import com.android.settings.WallpaperTypeSettings;
import com.android.settings.WirelessSettings;
import com.android.settings.ZenModeSettings;
import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.deviceinfo.Memory;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
import com.android.settings.location.LocationSettings;
import com.android.settings.net.DataUsageMeteredSettings;
import com.android.settings.notification.NotificationSettings;
import com.android.settings.notification.ZenModeSettings;
import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.users.UserSettings;
import com.android.settings.wifi.WifiSettings;