diff options
-rw-r--r-- | AndroidManifest.xml | 16 | ||||
-rw-r--r-- | src/com/android/settings/notification/AppNotificationDialog.java | 180 | ||||
-rw-r--r-- | src/com/android/settings/notification/AppNotificationSettings.java | 144 |
3 files changed, 218 insertions, 122 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5457d724b..67e34f100 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1836,17 +1836,23 @@ android:label="@string/app_notifications_title" android:exported="true" android:taskAffinity=""> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <action android:name="android.settings.ACTION_APP_NOTIFICATION_SETTINGS" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> <meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.android.settings.notification.AppNotificationSettings" /> <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID" android:resource="@id/notification_settings" /> </activity> + <activity android:name=".notification.AppNotificationDialog" + android:theme="@style/Theme.AlertDialog" + android:launchMode="singleTop" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <action android:name="android.settings.APP_NOTIFICATION_SETTINGS" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <!-- Show regulatory info (from settings item or dialing "*#07#") --> <activity android:name="RegulatoryInfoDisplayActivity" android:label="@string/regulatory_information" diff --git a/src/com/android/settings/notification/AppNotificationDialog.java b/src/com/android/settings/notification/AppNotificationDialog.java new file mode 100644 index 000000000..55f25c28d --- /dev/null +++ b/src/com/android/settings/notification/AppNotificationDialog.java @@ -0,0 +1,180 @@ +/* + * 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.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.CompoundButton.OnCheckedChangeListener; + +import com.android.internal.app.AlertActivity; +import com.android.internal.app.AlertController; +import com.android.settings.R; +import com.android.settings.notification.AppNotificationSettings.Backend; +import com.android.settings.notification.AppNotificationSettings.AppRow; + +public class AppNotificationDialog extends AlertActivity { + private static final String TAG = "AppNotificationDialog"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + /** + * Show a checkbox in the per-app notification control dialog to allow the user to + * selectively redact this app's notifications on the lockscreen. + */ + private static final boolean ENABLE_APP_NOTIFICATION_PRIVACY_OPTION = false; + + private final Context mContext = this; + private final Backend mBackend = new Backend(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + getIntent()); + if (!buildDialog()) { + Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show(); + finish(); + } + } + + private boolean buildDialog() { + final Intent intent = getIntent(); + if (intent != null) { + final int uid = intent.getIntExtra(Settings.EXTRA_APP_UID, -1); + final String pkg = intent.getStringExtra(Settings.EXTRA_APP_PACKAGE); + if (uid != -1 && !TextUtils.isEmpty(pkg)) { + if (DEBUG) Log.d(TAG, "Load details for pkg=" + pkg + " uid=" + uid); + final PackageManager pm = getPackageManager(); + final PackageInfo info = findPackageInfo(pm, pkg, uid); + if (info != null) { + final AppRow row = AppNotificationSettings.loadAppRow(pm, info, mBackend); + final AlertController.AlertParams p = mAlertParams; + p.mView = getLayoutInflater().inflate(R.layout.notification_app_dialog, + null, false); + p.mPositiveButtonText = getString(R.string.app_notifications_dialog_done); + bindDialog(p.mView, row); + setupAlert(); + return true; + } else { + Log.w(TAG, "Failed to find package info"); + } + } else { + Log.w(TAG, "Missing extras: " + Settings.EXTRA_APP_PACKAGE + " was " + pkg + ", " + + Settings.EXTRA_APP_UID + " was " + uid); + } + } else { + Log.w(TAG, "No intent"); + } + return false; + } + + private static PackageInfo findPackageInfo(PackageManager pm, String pkg, int uid) { + final String[] packages = pm.getPackagesForUid(uid); + if (packages != null && pkg != null) { + final int N = packages.length; + for (int i = 0; i < N; i++) { + final String p = packages[i]; + if (pkg.equals(p)) { + try { + return pm.getPackageInfo(pkg, 0); + } catch (NameNotFoundException e) { + Log.w(TAG, "Failed to load package " + pkg, e); + } + } + } + } + return null; + } + + private void bindDialog(final View v, final AppRow row) { + final ImageView icon = (ImageView) v.findViewById(android.R.id.icon); + icon.setImageDrawable(row.icon); + final TextView title = (TextView) v.findViewById(android.R.id.title); + title.setText(row.label); + final CheckBox showNotifications = (CheckBox) v.findViewById(android.R.id.button1); + final CheckBox highPriority = (CheckBox) v.findViewById(android.R.id.button2); + final CheckBox sensitive = (CheckBox) v.findViewById(android.R.id.button3); + + if (!ENABLE_APP_NOTIFICATION_PRIVACY_OPTION) { + sensitive.setVisibility(View.GONE); + } + + showNotifications.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; + highPriority.setEnabled(!row.banned); + sensitive.setEnabled(!row.banned); + } else { + showNotifications.setOnCheckedChangeListener(null); + showNotifications.setChecked(!isChecked); + showNotifications.setOnCheckedChangeListener(this); + } + } + }; + showNotifications.setOnCheckedChangeListener(showListener); + + highPriority.setChecked(row.priority); + final OnCheckedChangeListener priListener = new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + boolean success = mBackend.setHighPriority(row.pkg, row.uid, isChecked); + if (success) { + row.priority = isChecked; + } else { + highPriority.setOnCheckedChangeListener(null); + highPriority.setChecked(!isChecked); + highPriority.setOnCheckedChangeListener(this); + } + } + }; + highPriority.setOnCheckedChangeListener(priListener); + + sensitive.setChecked(row.sensitive); + final OnCheckedChangeListener senListener = new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + boolean success = mBackend.setSensitive(row.pkg, row.uid, isChecked); + if (success) { + row.sensitive = isChecked; + } else { + sensitive.setOnCheckedChangeListener(null); + sensitive.setChecked(!isChecked); + sensitive.setOnCheckedChangeListener(this); + } + } + }; + sensitive.setOnCheckedChangeListener(senListener); + + highPriority.setEnabled(!row.banned); + sensitive.setEnabled(!row.banned); + } +} diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java index eb868b446..25047a476 100644 --- a/src/com/android/settings/notification/AppNotificationSettings.java +++ b/src/com/android/settings/notification/AppNotificationSettings.java @@ -17,9 +17,7 @@ package com.android.settings.notification; import android.animation.LayoutTransition; -import android.app.AlertDialog; import android.app.INotificationManager; -import android.app.ListFragment; import android.app.Notification; import android.content.Context; import android.content.Intent; @@ -37,6 +35,7 @@ import android.os.Handler; import android.os.Parcelable; import android.os.ServiceManager; import android.os.SystemClock; +import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; import android.util.TypedValue; @@ -45,11 +44,7 @@ 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; @@ -65,18 +60,7 @@ import java.util.List; /** Just a sectioned list of installed applications, nothing else to index **/ public class AppNotificationSettings extends PinnedHeaderListFragment { private static final String TAG = "AppNotificationSettings"; - private static final boolean DEBUG = true; - - /** - * Show a checkbox in the per-app notification control dialog to allow the user - * to promote this app's notifications to higher priority. - */ - private static final boolean ENABLE_APP_NOTIFICATION_PRIORITY_OPTION = true; - /** - * Show a checkbox in the per-app notification control dialog to allow the user to - * selectively redact this app's notifications on the lockscreen. - */ - private static final boolean ENABLE_APP_NOTIFICATION_PRIVACY_OPTION = false; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String SECTION_BEFORE_A = "*"; private static final String SECTION_AFTER_Z = "**"; @@ -189,89 +173,6 @@ public class AppNotificationSettings extends PinnedHeaderListFragment { 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); - final CheckBox priBox = (CheckBox) layout.findViewById(android.R.id.button2); - final CheckBox senBox = (CheckBox) layout.findViewById(android.R.id.button3); - - if (!ENABLE_APP_NOTIFICATION_PRIORITY_OPTION) { - priBox.setVisibility(View.GONE); - } - - if (!ENABLE_APP_NOTIFICATION_PRIVACY_OPTION) { - senBox.setVisibility(View.GONE); - } - - 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*/); - priBox.setEnabled(!row.banned); - senBox.setEnabled(!row.banned); - } else { - showBox.setOnCheckedChangeListener(null); - showBox.setChecked(!isChecked); - showBox.setOnCheckedChangeListener(this); - } - } - }; - showBox.setOnCheckedChangeListener(showListener); - - priBox.setChecked(row.priority); - final OnCheckedChangeListener priListener = new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - boolean success = mBackend.setHighPriority(row.pkg, row.uid, isChecked); - if (success) { - row.priority = isChecked; - mAdapter.bindView(v, row, true /*animate*/); - } else { - priBox.setOnCheckedChangeListener(null); - priBox.setChecked(!isChecked); - priBox.setOnCheckedChangeListener(this); - } - } - }; - priBox.setOnCheckedChangeListener(priListener); - - senBox.setChecked(row.sensitive); - final OnCheckedChangeListener senListener = new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - boolean success = mBackend.setSensitive(row.pkg, row.uid, isChecked); - if (success) { - row.sensitive = isChecked; - mAdapter.bindView(v, row, true /*animate*/); - } else { - senBox.setOnCheckedChangeListener(null); - senBox.setChecked(!isChecked); - senBox.setOnCheckedChangeListener(this); - } - } - }; - senBox.setOnCheckedChangeListener(senListener); - - priBox.setEnabled(!row.banned); - senBox.setEnabled(!row.banned); - - 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; @@ -366,7 +267,10 @@ public class AppNotificationSettings extends PinnedHeaderListFragment { vh.appButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - showDialog(view, row); + mContext.startActivity(new Intent(mContext, AppNotificationDialog.class) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(Settings.EXTRA_APP_PACKAGE, row.pkg) + .putExtra(Settings.EXTRA_APP_UID, row.uid)); } }); enableLayoutTransitions(vh.appButton, animate); @@ -428,7 +332,7 @@ public class AppNotificationSettings extends PinnedHeaderListFragment { public String section; } - private static class AppRow extends Row { + public static class AppRow extends Row { public String pkg; public int uid; public Drawable icon; @@ -448,6 +352,23 @@ public class AppNotificationSettings extends PinnedHeaderListFragment { } }; + public static AppRow loadAppRow(PackageManager pm, PackageInfo pkg, Backend backend) { + 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 = backend.getNotificationsBanned(row.pkg, row.uid); + row.priority = backend.getHighPriority(row.pkg, row.uid); + row.sensitive = backend.getSensitive(row.pkg, row.uid); + return row; + } + private final Runnable mCollectAppsRunnable = new Runnable() { @Override public void run() { @@ -464,23 +385,12 @@ public class AppNotificationSettings extends PinnedHeaderListFragment { 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); - row.sensitive = mBackend.getSensitive(row.pkg, row.uid); + final AppRow row = loadAppRow(pm, pkg, mBackend); mRows.put(row.pkg, row); } // collect config activities - Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is " + APP_NOTIFICATION_PREFS_CATEGORY_INTENT); + if (DEBUG) 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); |