diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 883ded3d915..125e90edc4b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2084,7 +2084,7 @@
android:exported="true"
android:taskAffinity="">
+ android:value="com.android.settings.applications.ManageApplications" />
diff --git a/res/layout/notification_app_list.xml b/res/layout/notification_app_list.xml
deleted file mode 100644
index 2eac287ce6f..00000000000
--- a/res/layout/notification_app_list.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index be27f83a05d..ec93db3bbc5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6103,6 +6103,12 @@
Personal
Work
+
+ Blocked
+
+ Priority
+
+ Sensitive
Reset preferences across all apps to defaults
diff --git a/res/xml/notification_settings.xml b/res/xml/notification_settings.xml
index ac61b001b3e..f35d248c636 100644
--- a/res/xml/notification_settings.xml
+++ b/res/xml/notification_settings.xml
@@ -114,7 +114,11 @@
+ android:fragment="com.android.settings.applications.ManageApplications">
+
+
apps) {
+ // No op.
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ // No op.
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ // No op.
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ // No op.
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ // No op.
+ }
+
+ private class MainHandler extends Handler {
+ private static final int MSG_NOTIF_UPDATED = 1;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_NOTIF_UPDATED:
+ mCallback.onNotificationInfoUpdated();
+ break;
+ }
+ }
+ }
+
+ private class BackgroundHandler extends Handler {
+ private static final int MSG_LOAD_ALL = 1;
+ private static final int MSG_FORCE_LOAD_PKG = 2;
+
+ public BackgroundHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ List apps = mAppSession.getAllApps();
+ final int N = apps.size();
+ switch (msg.what) {
+ case MSG_LOAD_ALL:
+ for (int i = 0; i < N; i++) {
+ AppEntry app = apps.get(i);
+ app.extraInfo = mNotifBackend.loadAppRow(mPm, app.info);
+ }
+ mMainHandler.sendEmptyMessage(MainHandler.MSG_NOTIF_UPDATED);
+ break;
+ case MSG_FORCE_LOAD_PKG:
+ String pkg = (String) msg.obj;
+ int uid = msg.arg1;
+ for (int i = 0; i < N; i++) {
+ AppEntry app = apps.get(i);
+ if (app.info.uid == uid && pkg.equals(app.info.packageName)) {
+ app.extraInfo = mNotifBackend.loadAppRow(mPm, app.info);
+ break;
+ }
+ }
+ mMainHandler.sendEmptyMessage(MainHandler.MSG_NOTIF_UPDATED);
+ break;
+ }
+ }
+ }
+
+ public interface Callback {
+ void onNotificationInfoUpdated();
+ }
+
+ public static final AppFilter FILTER_APP_NOTIFICATION_BLOCKED = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return info.extraInfo != null && ((AppRow) info.extraInfo).banned;
+ }
+ };
+
+ public static final AppFilter FILTER_APP_NOTIFICATION_PRIORITY = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return info.extraInfo != null && ((AppRow) info.extraInfo).priority;
+ }
+ };
+
+ public static final AppFilter FILTER_APP_NOTIFICATION_SENSITIVE = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return info.extraInfo != null && ((AppRow) info.extraInfo).sensitive;
+ }
+ };
+}
diff --git a/src/com/android/settings/applications/AppViewHolder.java b/src/com/android/settings/applications/AppViewHolder.java
index c4324d1bc2f..176ccca729f 100644
--- a/src/com/android/settings/applications/AppViewHolder.java
+++ b/src/com/android/settings/applications/AppViewHolder.java
@@ -15,7 +15,7 @@ public class AppViewHolder {
public View rootView;
public TextView appName;
public ImageView appIcon;
- public TextView appSize;
+ public TextView summary;
public TextView disabled;
public CheckBox checkBox;
@@ -29,7 +29,7 @@ public class AppViewHolder {
holder.rootView = convertView;
holder.appName = (TextView) convertView.findViewById(R.id.app_name);
holder.appIcon = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.appSize = (TextView) convertView.findViewById(R.id.app_size);
+ holder.summary = (TextView) convertView.findViewById(R.id.app_size);
holder.disabled = (TextView) convertView.findViewById(R.id.app_disabled);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.app_on_sdcard);
convertView.setTag(holder);
@@ -42,22 +42,22 @@ public class AppViewHolder {
}
void updateSizeText(CharSequence invalidSizeStr, int whichSize) {
- if (ManageApplications.DEBUG) Log.i(ManageApplications.TAG, "updateSizeText of " + entry.label + " " + entry
- + ": " + entry.sizeStr);
+ if (ManageApplications.DEBUG) Log.i(ManageApplications.TAG, "updateSizeText of "
+ + entry.label + " " + entry + ": " + entry.sizeStr);
if (entry.sizeStr != null) {
switch (whichSize) {
case ManageApplications.SIZE_INTERNAL:
- appSize.setText(entry.internalSizeStr);
+ summary.setText(entry.internalSizeStr);
break;
case ManageApplications.SIZE_EXTERNAL:
- appSize.setText(entry.externalSizeStr);
+ summary.setText(entry.externalSizeStr);
break;
default:
- appSize.setText(entry.sizeStr);
+ summary.setText(entry.sizeStr);
break;
}
} else if (entry.size == ApplicationsState.SIZE_INVALID) {
- appSize.setText(invalidSizeStr);
+ summary.setText(invalidSizeStr);
}
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java
index 51a15cf8145..1aca69adc98 100644
--- a/src/com/android/settings/applications/ApplicationsState.java
+++ b/src/com/android/settings/applications/ApplicationsState.java
@@ -57,6 +57,7 @@ public class ApplicationsState {
public void onPackageSizeChanged(String packageName);
public void onAllSizesComputed();
public void onLauncherInfoChanged();
+ public void onLoadEntriesCompleted();
}
public static interface AppFilter {
@@ -125,6 +126,9 @@ public class ApplicationsState {
String normalizedLabel;
+ // A location where extra info can be placed to be used by custom filters.
+ Object extraInfo;
+
AppEntry(Context context, ApplicationInfo info, long id) {
apkFile = new File(info.sourceDir);
this.id = id;
@@ -444,6 +448,7 @@ public class ApplicationsState {
static final int MSG_ALL_SIZES_COMPUTED = 5;
static final int MSG_RUNNING_STATE_CHANGED = 6;
static final int MSG_LAUNCHER_INFO_CHANGED = 7;
+ static final int MSG_LOAD_ENTRIES_COMPLETE = 8;
@Override
public void handleMessage(Message msg) {
@@ -487,6 +492,11 @@ public class ApplicationsState {
mActiveSessions.get(i).mCallbacks.onLauncherInfoChanged();
}
} break;
+ case MSG_LOAD_ENTRIES_COMPLETE: {
+ for (int i=0; i= 6) {
sendEmptyMessage(MSG_LOAD_ENTRIES);
} else {
+ if (!mMainHandler.hasMessages(MainHandler.MSG_LOAD_ENTRIES_COMPLETE)) {
+ mMainHandler.sendEmptyMessage(MainHandler.MSG_LOAD_ENTRIES_COMPLETE);
+ }
sendEmptyMessage(MSG_LOAD_LAUNCHER);
}
} break;
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 85b35235c0f..93168103d90 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -62,9 +62,8 @@ import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry;
import com.android.settings.net.ChartData;
import com.android.settings.net.ChartDataLoader;
-import com.android.settings.notification.NotificationAppList;
-import com.android.settings.notification.NotificationAppList.AppRow;
-import com.android.settings.notification.NotificationAppList.Backend;
+import com.android.settings.notification.NotificationBackend;
+import com.android.settings.notification.NotificationBackend.AppRow;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -122,7 +121,7 @@ public class InstalledAppDetails extends AppInfoBase
private boolean mDisableAfterUninstall;
// Used for updating notification preference.
- private final Backend mBackend = new Backend();
+ private final NotificationBackend mBackend = new NotificationBackend();
private ChartData mChartData;
private INetworkStatsSession mStatsSession;
@@ -636,13 +635,16 @@ public class InstalledAppDetails extends AppInfoBase
}
public static CharSequence getNotificationSummary(AppEntry appEntry, Context context) {
- return getNotificationSummary(appEntry, context, new Backend());
+ return getNotificationSummary(appEntry, context, new NotificationBackend());
}
public static CharSequence getNotificationSummary(AppEntry appEntry, Context context,
- Backend backend) {
- AppRow appRow = NotificationAppList.loadAppRow(context.getPackageManager(), appEntry.info,
- backend);
+ NotificationBackend backend) {
+ AppRow appRow = backend.loadAppRow(context.getPackageManager(), appEntry.info);
+ return getNotificationSummary(appRow, context);
+ }
+
+ public static CharSequence getNotificationSummary(AppRow appRow, Context context) {
if (appRow.banned) {
return context.getString(R.string.notifications_disabled);
} else if (appRow.priority) {
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 14d48c8faf9..a034964494d 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -54,10 +54,13 @@ import android.widget.Spinner;
import com.android.internal.content.PackageHelper;
import com.android.settings.R;
import com.android.settings.Settings.AllApplicationsActivity;
+import com.android.settings.Settings.NotificationAppListActivity;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.ApplicationsState.AppEntry;
import com.android.settings.applications.ApplicationsState.AppFilter;
+import com.android.settings.notification.NotificationBackend;
+import com.android.settings.notification.NotificationBackend.AppRow;
import java.util.ArrayList;
import java.util.Collections;
@@ -135,8 +138,11 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
public static final int FILTER_APPS_ALL = 1;
public static final int FILTER_APPS_ENABLED = 2;
public static final int FILTER_APPS_DISABLED = 3;
- public static final int FILTER_APPS_PERSONAL = 4;
- public static final int FILTER_APPS_WORK = 5;
+ public static final int FILTER_APPS_BLOCKED = 4;
+ public static final int FILTER_APPS_PRIORITY = 5;
+ public static final int FILTER_APPS_SENSITIVE = 6;
+ public static final int FILTER_APPS_PERSONAL = 7;
+ public static final int FILTER_APPS_WORK = 8;
// This is the string labels for the filter modes above, the order must be kept in sync.
public static final int[] FILTER_LABELS = new int[] {
@@ -144,6 +150,9 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
R.string.filter_all_apps, // All apps
R.string.filter_enabled_apps, // Enabled
R.string.filter_apps_disabled, // Disabled
+ R.string.filter_notif_blocked_apps, // Blocked Notifications
+ R.string.filter_notif_priority_apps, // Priority Notifications
+ R.string.filter_notif_sensitive_apps, // Sensitive Notifications
R.string.filter_personal_apps, // Personal
R.string.filter_work_apps, // Work
};
@@ -154,6 +163,9 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
ApplicationsState.FILTER_EVERYTHING, // All apps
ApplicationsState.FILTER_ALL_ENABLED, // Enabled
ApplicationsState.FILTER_DISABLED, // Disabled
+ AppStateNotificationBridge.FILTER_APP_NOTIFICATION_BLOCKED, // Blocked Notifications
+ AppStateNotificationBridge.FILTER_APP_NOTIFICATION_PRIORITY, // Priority Notifications
+ AppStateNotificationBridge.FILTER_APP_NOTIFICATION_SENSITIVE, // Sensitive Notifications
ApplicationsState.FILTER_PERSONAL, // Personal
ApplicationsState.FILTER_WORK, // Work
};
@@ -194,12 +206,14 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
public static final int LIST_TYPE_MAIN = 0;
public static final int LIST_TYPE_ALL = 1;
+ public static final int LIST_TYPE_NOTIFICATION = 2;
private View mRootView;
private View mSpinnerHeader;
private Spinner mFilterSpinner;
private FilterSpinnerAdapter mFilterAdapter;
+ private NotificationBackend mNotifBackend;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -214,9 +228,11 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
if (className == null) {
className = intent.getComponent().getClassName();
}
- if (Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS.equals(action)
- || className.equals(AllApplicationsActivity.class.getName())) {
+ if (className.equals(AllApplicationsActivity.class.getName())) {
mListType = LIST_TYPE_ALL;
+ } else if (className.equals(NotificationAppListActivity.class.getName())) {
+ mListType = LIST_TYPE_NOTIFICATION;
+ mNotifBackend = new NotificationBackend();
} else {
mListType = LIST_TYPE_MAIN;
}
@@ -289,6 +305,11 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
mFilterAdapter.enableFilter(FILTER_APPS_WORK);
}
}
+ if (mListType == LIST_TYPE_NOTIFICATION) {
+ mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED);
+ mFilterAdapter.enableFilter(FILTER_APPS_PRIORITY);
+ mFilterAdapter.enableFilter(FILTER_APPS_SENSITIVE);
+ }
}
private int getDefaultFilter() {
@@ -335,19 +356,30 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
- mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid));
+ if (mListType == LIST_TYPE_NOTIFICATION) {
+ mApplications.mNotifBridge.forceUpdate(mCurrentPkgName, mCurrentUid);
+ } else {
+ mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid));
+ }
}
}
// utility method used to start sub activity
private void startApplicationDetailsActivity() {
- // TODO: Figure out if there is a way where we can spin up the profile's settings
- // process ahead of time, to avoid a long load of data when user clicks on a managed app.
- // Maybe when they load the list of apps that contains managed profile apps.
- Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
- intent.setData(Uri.fromParts("package", mCurrentPkgName, null));
- getActivity().startActivityAsUser(intent,
- new UserHandle(UserHandle.getUserId(mCurrentUid)));
+ if (mListType == LIST_TYPE_NOTIFICATION) {
+ getActivity().startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
+ .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, mCurrentPkgName)
+ .putExtra(Settings.EXTRA_APP_UID, mCurrentUid));
+ } else {
+ // TODO: Figure out if there is a way where we can spin up the profile's settings
+ // process ahead of time, to avoid a long load of data when user clicks on a managed app.
+ // Maybe when they load the list of apps that contains managed profile apps.
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.fromParts("package", mCurrentPkgName, null));
+ getActivity().startActivityAsUser(intent,
+ new UserHandle(UserHandle.getUserId(mCurrentUid)));
+ }
}
@Override
@@ -517,12 +549,14 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
* The order of applications in the list is mirrored in mAppLocalList
*/
static class ApplicationsAdapter extends BaseAdapter implements Filterable,
- ApplicationsState.Callbacks, AbsListView.RecyclerListener {
+ ApplicationsState.Callbacks, AppStateNotificationBridge.Callback,
+ AbsListView.RecyclerListener {
private final ApplicationsState mState;
private final ApplicationsState.Session mSession;
private final ManageApplications mManageApplications;
private final Context mContext;
private final ArrayList mActive = new ArrayList();
+ private final AppStateNotificationBridge mNotifBridge;
private int mFilterMode;
private ArrayList mBaseEntries;
private ArrayList mEntries;
@@ -558,6 +592,13 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
mManageApplications = manageApplications;
mContext = manageApplications.getActivity();
mFilterMode = filterMode;
+ if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
+ mNotifBridge = new AppStateNotificationBridge(
+ mContext.getPackageManager(), mState,
+ manageApplications.mNotifBackend, this);
+ } else {
+ mNotifBridge = null;
+ }
}
public void setFilter(int filter) {
@@ -571,6 +612,9 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
mResumed = true;
mSession.resume();
mLastSortMode = sort;
+ if (mNotifBridge != null) {
+ mNotifBridge.resume();
+ }
rebuild(true);
} else {
rebuild(sort);
@@ -581,11 +625,17 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
if (mResumed) {
mResumed = false;
mSession.pause();
+ if (mNotifBridge != null) {
+ mNotifBridge.pause();
+ }
}
}
public void release() {
mSession.release();
+ if (mNotifBridge != null) {
+ mNotifBridge.release();
+ }
}
public void rebuild(int sort) {
@@ -680,6 +730,13 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
}
}
+ @Override
+ public void onNotificationInfoUpdated() {
+ if (mFilterMode != mManageApplications.getDefaultFilter()) {
+ rebuild(false);
+ }
+ }
+
@Override
public void onRunningStateChanged(boolean running) {
mManageApplications.getActivity().setProgressBarIndeterminateVisibility(running);
@@ -711,13 +768,20 @@ public class ManageApplications extends Fragment implements OnItemClickListener,
// don't care about icons loaded in the background.
}
+ @Override
+ public void onLoadEntriesCompleted() {
+ // No op.
+ }
+
@Override
public void onPackageSizeChanged(String packageName) {
for (int i=0; i rows = new ArrayMap();
rows.put(mAppRow.pkg, mAppRow);
- NotificationAppList.collectConfigActivities(getPackageManager(), rows);
+ collectConfigActivities(getPackageManager(), rows);
}
mBlock.setChecked(mAppRow.banned);
@@ -225,4 +235,44 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
}
return null;
}
+
+ public static List queryNotificationConfigActivities(PackageManager pm) {
+ if (DEBUG) Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is "
+ + APP_NOTIFICATION_PREFS_CATEGORY_INTENT);
+ final List resolveInfos = pm.queryIntentActivities(
+ APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
+ 0 //PackageManager.MATCH_DEFAULT_ONLY
+ );
+ return resolveInfos;
+ }
+
+ public static void collectConfigActivities(PackageManager pm, ArrayMap rows) {
+ final List resolveInfos = queryNotificationConfigActivities(pm);
+ applyConfigActivities(pm, rows, resolveInfos);
+ }
+
+ public static void applyConfigActivities(PackageManager pm, ArrayMap rows,
+ List resolveInfos) {
+ if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities"
+ + (resolveInfos.size() == 0 ? " ;_;" : ""));
+ for (ResolveInfo ri : resolveInfos) {
+ final ActivityInfo activityInfo = ri.activityInfo;
+ final ApplicationInfo appInfo = activityInfo.applicationInfo;
+ final AppRow row = rows.get(appInfo.packageName);
+ if (row == null) {
+ if (DEBUG) Log.v(TAG, "Ignoring notification preference activity ("
+ + activityInfo.name + ") for unknown package "
+ + activityInfo.packageName);
+ continue;
+ }
+ if (row.settingsIntent != null) {
+ if (DEBUG) Log.v(TAG, "Ignoring duplicate notification preference activity ("
+ + activityInfo.name + ") for package "
+ + activityInfo.packageName);
+ continue;
+ }
+ row.settingsIntent = new Intent(APP_NOTIFICATION_PREFS_CATEGORY_INTENT)
+ .setClassName(activityInfo.packageName, activityInfo.name);
+ }
+ }
}
diff --git a/src/com/android/settings/notification/NotificationAppList.java b/src/com/android/settings/notification/NotificationAppList.java
deleted file mode 100644
index 27eb9145ec3..00000000000
--- a/src/com/android/settings/notification/NotificationAppList.java
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * 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 static com.android.settings.notification.AppNotificationSettings.EXTRA_HAS_SETTINGS_INTENT;
-import static com.android.settings.notification.AppNotificationSettings.EXTRA_SETTINGS_INTENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import android.animation.LayoutTransition;
-import android.app.INotificationManager;
-import android.app.Notification;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.Signature;
-import android.graphics.drawable.Drawable;
-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.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
-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.view.ViewGroup.LayoutParams;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.SectionIndexer;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import com.android.settings.PinnedHeaderListFragment;
-import com.android.settings.R;
-import com.android.settings.Settings.NotificationAppListActivity;
-import com.android.settings.UserSpinnerAdapter;
-import com.android.settings.Utils;
-
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-/** Just a sectioned list of installed applications, nothing else to index **/
-public class NotificationAppList extends PinnedHeaderListFragment
- implements OnItemSelectedListener {
- private static final String TAG = "NotificationAppList";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private static final String EMPTY_SUBTITLE = "";
- 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(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES);
-
- private final Handler mHandler = new Handler();
- private final ArrayMap mRows = new ArrayMap();
- private final ArrayList mSortedRows = new ArrayList();
- private final ArrayList mSections = new ArrayList();
-
- private Context mContext;
- private LayoutInflater mInflater;
- private NotificationAppAdapter mAdapter;
- private Signature[] mSystemSignature;
- private Parcelable mListViewState;
- private Backend mBackend = new Backend();
- private UserSpinnerAdapter mProfileSpinnerAdapter;
- private Spinner mSpinner;
-
- private PackageManager mPM;
- private UserManager mUM;
- private LauncherApps mLauncherApps;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mContext = getActivity();
- mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mAdapter = new NotificationAppAdapter(mContext);
- mUM = UserManager.get(mContext);
- mPM = mContext.getPackageManager();
- mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
- getActivity().setTitle(R.string.app_notifications_title);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.notification_app_list, container, false);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- mProfileSpinnerAdapter = Utils.createUserSpinnerAdapter(mUM, mContext);
- if (mProfileSpinnerAdapter != null) {
- mSpinner = (Spinner) getActivity().getLayoutInflater().inflate(
- R.layout.spinner_view, null);
- mSpinner.setAdapter(mProfileSpinnerAdapter);
- mSpinner.setOnItemSelectedListener(this);
- // Set layout parameters, otherwise we get the default ones
- mSpinner.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- setPinnedHeaderView(mSpinner);
- }
- }
-
- @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 onDestroyView() {
- super.onDestroyView();
- mListViewState = null; // you're dead to me
- }
-
- @Override
- public void onResume() {
- super.onResume();
- loadAppsList();
- }
-
- @Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
- UserHandle selectedUser = mProfileSpinnerAdapter.getUserHandle(position);
- if (selectedUser.getIdentifier() != UserHandle.myUserId()) {
- Intent intent = new Intent(getActivity(), NotificationAppListActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivityAsUser(intent, selectedUser);
- // Go back to default selection, which is the first one; this makes sure that pressing
- // the back button takes you into a consistent state
- mSpinner.setSelection(0);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView> parent) {
- }
-
- 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 static class ViewHolder {
- ViewGroup row;
- ImageView icon;
- TextView title;
- TextView subtitle;
- View rowDivider;
- }
-
- private class NotificationAppAdapter extends ArrayAdapter implements SectionIndexer {
- public NotificationAppAdapter(Context context) {
- super(context, 0, 0);
- }
-
- @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.row.setLayoutTransition(new LayoutTransition());
- vh.icon = (ImageView) v.findViewById(android.R.id.icon);
- vh.title = (TextView) v.findViewById(android.R.id.title);
- vh.subtitle = (TextView) v.findViewById(android.R.id.text1);
- 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)) {
- // it's a section row
- final TextView tv = (TextView)view.findViewById(android.R.id.title);
- 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.row.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
- .putExtra(Settings.EXTRA_APP_PACKAGE, row.pkg)
- .putExtra(Settings.EXTRA_APP_UID, row.uid)
- .putExtra(EXTRA_HAS_SETTINGS_INTENT, row.settingsIntent != null)
- .putExtra(EXTRA_SETTINGS_INTENT, row.settingsIntent));
- }
- });
- enableLayoutTransitions(vh.row, animate);
- vh.icon.setImageDrawable(row.icon);
- vh.title.setText(row.label);
- final String sub = getSubtitle(row);
- vh.subtitle.setText(sub);
- vh.subtitle.setVisibility(!sub.isEmpty() ? View.VISIBLE : View.GONE);
- }
-
- private String getSubtitle(AppRow row) {
- if (row.banned) {
- return mContext.getString(R.string.app_notification_row_banned);
- }
- if (!row.priority && !row.sensitive) {
- return EMPTY_SUBTITLE;
- }
- final String priString = mContext.getString(R.string.app_notification_row_priority);
- final String senString = mContext.getString(R.string.app_notification_row_sensitive);
- if (row.priority != row.sensitive) {
- return row.priority ? priString : senString;
- }
- return priString + mContext.getString(R.string.summary_divider_text) + senString;
- }
-
- @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;
- }
-
- public 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 peekable;
- public boolean sensitive;
- public boolean first; // first app in section
- }
-
- private static final Comparator mRowComparator = new Comparator() {
- private final Collator sCollator = Collator.getInstance();
- @Override
- public int compare(AppRow lhs, AppRow rhs) {
- return sCollator.compare(lhs.label, rhs.label);
- }
- };
-
-
- public static AppRow loadAppRow(PackageManager pm, ApplicationInfo app,
- Backend backend) {
- final AppRow row = new AppRow();
- row.pkg = app.packageName;
- row.uid = app.uid;
- try {
- row.label = app.loadLabel(pm);
- } catch (Throwable t) {
- Log.e(TAG, "Error loading application label for " + row.pkg, t);
- row.label = row.pkg;
- }
- row.icon = app.loadIcon(pm);
- row.banned = backend.getNotificationsBanned(row.pkg, row.uid);
- row.priority = backend.getHighPriority(row.pkg, row.uid);
- row.peekable = backend.getPeekable(row.pkg, row.uid);
- row.sensitive = backend.getSensitive(row.pkg, row.uid);
- return row;
- }
-
- public static List queryNotificationConfigActivities(PackageManager pm) {
- if (DEBUG) Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is "
- + APP_NOTIFICATION_PREFS_CATEGORY_INTENT);
- final List resolveInfos = pm.queryIntentActivities(
- APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
- 0 //PackageManager.MATCH_DEFAULT_ONLY
- );
- return resolveInfos;
- }
- public static void collectConfigActivities(PackageManager pm, ArrayMap rows) {
- final List resolveInfos = queryNotificationConfigActivities(pm);
- applyConfigActivities(pm, rows, resolveInfos);
- }
-
- public static void applyConfigActivities(PackageManager pm, ArrayMap rows,
- List resolveInfos) {
- if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities"
- + (resolveInfos.size() == 0 ? " ;_;" : ""));
- for (ResolveInfo ri : resolveInfos) {
- final ActivityInfo activityInfo = ri.activityInfo;
- final ApplicationInfo appInfo = activityInfo.applicationInfo;
- final AppRow row = rows.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(APP_NOTIFICATION_PREFS_CATEGORY_INTENT)
- .setClassName(activityInfo.packageName, activityInfo.name);
- }
- }
-
- 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 launchable apps, plus any packages that have notification settings
- final List appInfos = new ArrayList();
-
- final List lais
- = mLauncherApps.getActivityList(null /* all */,
- UserHandle.getCallingUserHandle());
- if (DEBUG) Log.d(TAG, " launchable activities:");
- for (LauncherActivityInfo lai : lais) {
- if (DEBUG) Log.d(TAG, " " + lai.getComponentName().toString());
- appInfos.add(lai.getApplicationInfo());
- }
-
- final List resolvedConfigActivities
- = queryNotificationConfigActivities(mPM);
- if (DEBUG) Log.d(TAG, " config activities:");
- for (ResolveInfo ri : resolvedConfigActivities) {
- if (DEBUG) Log.d(TAG, " "
- + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
- appInfos.add(ri.activityInfo.applicationInfo);
- }
-
- for (ApplicationInfo info : appInfos) {
- final String key = info.packageName;
- if (mRows.containsKey(key)) {
- // we already have this app, thanks
- continue;
- }
-
- final AppRow row = loadAppRow(mPM, info, mBackend);
- mRows.put(key, row);
- }
-
- // add config activities to the list
- applyConfigActivities(mPM, mRows, resolvedConfigActivities);
-
- // 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 {
- static INotificationManager sINM = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-
- public boolean setNotificationsBanned(String pkg, int uid, boolean banned) {
- try {
- sINM.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) {
- try {
- final boolean enabled = sINM.areNotificationsEnabledForPackage(pkg, uid);
- return !enabled;
- } catch (Exception e) {
- Log.w(TAG, "Error calling NoMan", e);
- return false;
- }
- }
-
- public boolean getHighPriority(String pkg, int uid) {
- try {
- return sINM.getPackagePriority(pkg, uid) == Notification.PRIORITY_MAX;
- } catch (Exception e) {
- Log.w(TAG, "Error calling NoMan", e);
- return false;
- }
- }
-
- public boolean setHighPriority(String pkg, int uid, boolean highPriority) {
- try {
- sINM.setPackagePriority(pkg, uid,
- highPriority ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT);
- return true;
- } catch (Exception e) {
- Log.w(TAG, "Error calling NoMan", e);
- return false;
- }
- }
-
- public boolean getPeekable(String pkg, int uid) {
- try {
- return sINM.getPackagePeekable(pkg, uid);
- } catch (Exception e) {
- Log.w(TAG, "Error calling NoMan", e);
- return false;
- }
- }
-
- public boolean setPeekable(String pkg, int uid, boolean peekable) {
- try {
- sINM.setPackagePeekable(pkg, uid, peekable);
- return true;
- } catch (Exception e) {
- Log.w(TAG, "Error calling NoMan", e);
- return false;
- }
- }
-
- public boolean getSensitive(String pkg, int uid) {
- try {
- return sINM.getPackageVisibilityOverride(pkg, uid) == Notification.VISIBILITY_PRIVATE;
- } catch (Exception e) {
- Log.w(TAG, "Error calling NoMan", e);
- return false;
- }
- }
-
- public boolean setSensitive(String pkg, int uid, boolean sensitive) {
- try {
- sINM.setPackageVisibilityOverride(pkg, uid,
- sensitive ? Notification.VISIBILITY_PRIVATE
- : NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
- return true;
- } catch (Exception e) {
- Log.w(TAG, "Error calling NoMan", e);
- return false;
- }
- }
- }
-}
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
new file mode 100644
index 00000000000..2060719b530
--- /dev/null
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -0,0 +1,150 @@
+/*
+ * 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.INotificationManager;
+import android.app.Notification;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService;
+import android.util.Log;
+
+public class NotificationBackend {
+ private static final String TAG = "NotificationBackend";
+
+ static INotificationManager sINM = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+
+ public AppRow loadAppRow(PackageManager pm, ApplicationInfo app) {
+ final AppRow row = new AppRow();
+ row.pkg = app.packageName;
+ row.uid = app.uid;
+ try {
+ row.label = app.loadLabel(pm);
+ } catch (Throwable t) {
+ Log.e(TAG, "Error loading application label for " + row.pkg, t);
+ row.label = row.pkg;
+ }
+ row.icon = app.loadIcon(pm);
+ row.banned = getNotificationsBanned(row.pkg, row.uid);
+ row.priority = getHighPriority(row.pkg, row.uid);
+ row.peekable = getPeekable(row.pkg, row.uid);
+ row.sensitive = getSensitive(row.pkg, row.uid);
+ return row;
+ }
+
+ public boolean setNotificationsBanned(String pkg, int uid, boolean banned) {
+ try {
+ sINM.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) {
+ try {
+ final boolean enabled = sINM.areNotificationsEnabledForPackage(pkg, uid);
+ return !enabled;
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return false;
+ }
+ }
+
+ public boolean getHighPriority(String pkg, int uid) {
+ try {
+ return sINM.getPackagePriority(pkg, uid) == Notification.PRIORITY_MAX;
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return false;
+ }
+ }
+
+ public boolean setHighPriority(String pkg, int uid, boolean highPriority) {
+ try {
+ sINM.setPackagePriority(pkg, uid,
+ highPriority ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT);
+ return true;
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return false;
+ }
+ }
+
+ public boolean getPeekable(String pkg, int uid) {
+ try {
+ return sINM.getPackagePeekable(pkg, uid);
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return false;
+ }
+ }
+
+ public boolean setPeekable(String pkg, int uid, boolean peekable) {
+ try {
+ sINM.setPackagePeekable(pkg, uid, peekable);
+ return true;
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return false;
+ }
+ }
+
+ public boolean getSensitive(String pkg, int uid) {
+ try {
+ return sINM.getPackageVisibilityOverride(pkg, uid) == Notification.VISIBILITY_PRIVATE;
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return false;
+ }
+ }
+
+ public boolean setSensitive(String pkg, int uid, boolean sensitive) {
+ try {
+ sINM.setPackageVisibilityOverride(pkg, uid,
+ sensitive ? Notification.VISIBILITY_PRIVATE
+ : NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
+ return true;
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return false;
+ }
+ }
+
+ static class Row {
+ public String section;
+ }
+
+ public 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 peekable;
+ public boolean sensitive;
+ public boolean first; // first app in section
+ }
+
+}