Refinements to notification controls in Settings.

- the switch is now a checkbox
- a dialog is posted to explain the ramifications of
  disabling notifications
- the user may no longer disable notifications from system
  apps (signed with the system cert); this is roughly the
  same as the constraint on disabling packages (with the
  exception that launchers may not be disabled entirely, but
  their notifications may still be disabled).

Bug: 6493120 (checkbox)
Bug: 6448988 (confirmation dialog & protect system apps)
Change-Id: I6c7a47ba2eb943936d7f59cfc807a4390acc980d
This commit is contained in:
Daniel Sandler
2012-05-15 15:48:09 -04:00
parent 8cbfe4036e
commit 70b5999839
3 changed files with 70 additions and 48 deletions

View File

@@ -50,35 +50,12 @@
android:id="@+id/control_buttons_panel"/> android:id="@+id/control_buttons_panel"/>
<!-- Ban notifications for this package --> <!-- Ban notifications for this package -->
<LinearLayout <CheckBox android:id="@+id/notification_switch"
android:orientation="horizontal" android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="48dp" android:layout_marginLeft="12dip"
android:paddingLeft="6dip" android:layout_gravity="left"
android:paddingTop="8dip" android:text="@string/app_notifications_switch_label" />
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="14dip"
android:text="@string/app_notifications_switch_label"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<Switch android:id="@+id/notification_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="8dip"
android:switchTextAppearance="@style/TextAppearance.Switch"
android:textOn="@string/app_notifications_switch_on"
android:textOff="@string/app_notifications_switch_off"
android:focusable="false"
android:clickable="true" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -2508,6 +2508,12 @@
<!-- [CHAR LIMIT=200] Manage applications, text for dialog when disabling apps --> <!-- [CHAR LIMIT=200] Manage applications, text for dialog when disabling apps -->
<string name="app_disable_dlg_text">If you disable a built-in app, other apps <string name="app_disable_dlg_text">If you disable a built-in app, other apps
may misbehave.</string> may misbehave.</string>
<!-- [CHAR LIMIT=30] Manage applications, title for dialog when disabling notifications for an app -->
<string name="app_disable_notifications_dlg_title">Turn off notifications?</string>
<!-- [CHAR LIMIT=200] Manage applications, text for dialog when disabling notifications for an app -->
<string name="app_disable_notifications_dlg_text">
If you turn off notifications for this app, you may miss important alerts and updates.
</string>
<!-- [CHAR LIMIT=25] Services settings screen, setting option name for the user to go to the screen to view app storage use --> <!-- [CHAR LIMIT=25] Services settings screen, setting option name for the user to go to the screen to view app storage use -->
<string name="storageuse_settings_title">Storage use</string> <string name="storageuse_settings_title">Storage use</string>
@@ -4025,13 +4031,8 @@
<!-- User removal confirmation message [CHAR LIMIT=none] --> <!-- User removal confirmation message [CHAR LIMIT=none] -->
<string name="user_confirm_remove_message">Are you sure you want to remove the user and all associated data from the device?</string> <string name="user_confirm_remove_message">Are you sure you want to remove the user and all associated data from the device?</string>
<!-- Label for "notifications enabled" switch in app details [CHAR LIMIT=20] --> <!-- Label for are-notifications-enabled checkbox in app details [CHAR LIMIT=20] -->
<string name="app_notifications_switch_label">Notifications</string> <string name="app_notifications_switch_label">Show notifications</string>
<!-- Label for enabled state of "notifications enabled" switch in app details [CHAR LIMIT=10] -->
<string name="app_notifications_switch_on">Enabled</string>
<!-- Label for disabled state "notifications enabled" switch in app details [CHAR LIMIT=10] -->
<string name="app_notifications_switch_off">Disabled</string>
<!-- Help URLs for some screens. Not specified here. Specified in product overlays --><skip/> <!-- Help URLs for some screens. Not specified here. Specified in product overlays --><skip/>
<!-- Help menu label [CHAR LIMIT=20] --> <!-- Help menu label [CHAR LIMIT=20] -->

View File

@@ -125,7 +125,7 @@ public class InstalledAppDetails extends Fragment
private Button mForceStopButton; private Button mForceStopButton;
private Button mClearDataButton; private Button mClearDataButton;
private Button mMoveAppButton; private Button mMoveAppButton;
private Switch mNotificationSwitch; private CompoundButton mNotificationSwitch;
private PackageMoveObserver mPackageMoveObserver; private PackageMoveObserver mPackageMoveObserver;
@@ -161,6 +161,7 @@ public class InstalledAppDetails extends Fragment
private static final int DLG_FORCE_STOP = DLG_BASE + 5; private static final int DLG_FORCE_STOP = DLG_BASE + 5;
private static final int DLG_MOVE_FAILED = DLG_BASE + 6; private static final int DLG_MOVE_FAILED = DLG_BASE + 6;
private static final int DLG_DISABLE = DLG_BASE + 7; private static final int DLG_DISABLE = DLG_BASE + 7;
private static final int DLG_DISABLE_NOTIFICATIONS = DLG_BASE + 8;
private Handler mHandler = new Handler() { private Handler mHandler = new Handler() {
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
@@ -279,6 +280,16 @@ public class InstalledAppDetails extends Fragment
} }
} }
private boolean isThisASystemPackage() {
try {
PackageInfo sys = mPm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
return (mPackageInfo != null && mPackageInfo.signatures != null &&
sys.signatures[0].equals(mPackageInfo.signatures[0]));
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
private void initUninstallButtons() { private void initUninstallButtons() {
mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
boolean enabled = true; boolean enabled = true;
@@ -298,9 +309,7 @@ public class InstalledAppDetails extends Fragment
intent.addCategory(Intent.CATEGORY_HOME); intent.addCategory(Intent.CATEGORY_HOME);
intent.setPackage(mAppEntry.info.packageName); intent.setPackage(mAppEntry.info.packageName);
List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0); List<ResolveInfo> homes = mPm.queryIntentActivities(intent, 0);
if ((homes != null && homes.size() > 0) || if ((homes != null && homes.size() > 0) || isThisASystemPackage()) {
(mPackageInfo != null && mPackageInfo.signatures != null &&
sys.signatures[0].equals(mPackageInfo.signatures[0]))) {
// Disable button for core system applications. // Disable button for core system applications.
mUninstallButton.setText(R.string.disable_text); mUninstallButton.setText(R.string.disable_text);
} else if (mAppEntry.info.enabled) { } else if (mAppEntry.info.enabled) {
@@ -340,7 +349,12 @@ public class InstalledAppDetails extends Fragment
// this does not bode well // this does not bode well
} }
mNotificationSwitch.setChecked(enabled); mNotificationSwitch.setChecked(enabled);
mNotificationSwitch.setOnCheckedChangeListener(this); if (isThisASystemPackage()) {
mNotificationSwitch.setEnabled(false);
} else {
mNotificationSwitch.setEnabled(true);
mNotificationSwitch.setOnCheckedChangeListener(this);
}
} }
/** Called when the activity is first created. */ /** Called when the activity is first created. */
@@ -395,7 +409,7 @@ public class InstalledAppDetails extends Fragment
mAskCompatibilityCB = (CheckBox)view.findViewById(R.id.ask_compatibility_cb); mAskCompatibilityCB = (CheckBox)view.findViewById(R.id.ask_compatibility_cb);
mEnableCompatibilityCB = (CheckBox)view.findViewById(R.id.enable_compatibility_cb); mEnableCompatibilityCB = (CheckBox)view.findViewById(R.id.enable_compatibility_cb);
mNotificationSwitch = (Switch) view.findViewById(R.id.notification_switch); mNotificationSwitch = (CompoundButton) view.findViewById(R.id.notification_switch);
return view; return view;
} }
@@ -851,6 +865,26 @@ public class InstalledAppDetails extends Fragment
}) })
.setNegativeButton(R.string.dlg_cancel, null) .setNegativeButton(R.string.dlg_cancel, null)
.create(); .create();
case DLG_DISABLE_NOTIFICATIONS:
return new AlertDialog.Builder(getActivity())
.setTitle(getActivity().getText(R.string.app_disable_notifications_dlg_title))
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(getActivity().getText(R.string.app_disable_notifications_dlg_text))
.setPositiveButton(R.string.dlg_ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Disable the package's notifications
getOwner().setNotificationsEnabled(false);
}
})
.setNegativeButton(R.string.dlg_cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Re-enable the checkbox
getOwner().mNotificationSwitch.setChecked(true);
}
})
.create();
} }
throw new IllegalArgumentException("unknown id " + id); throw new IllegalArgumentException("unknown id " + id);
} }
@@ -905,7 +939,7 @@ public class InstalledAppDetails extends Fragment
Activity.RESULT_CANCELED, null, null); Activity.RESULT_CANCELED, null, null);
} }
} }
static class DisableChanger extends AsyncTask<Object, Object, Object> { static class DisableChanger extends AsyncTask<Object, Object, Object> {
final PackageManager mPm; final PackageManager mPm;
final WeakReference<InstalledAppDetails> mActivity; final WeakReference<InstalledAppDetails> mActivity;
@@ -926,6 +960,18 @@ public class InstalledAppDetails extends Fragment
} }
} }
private void setNotificationsEnabled(boolean enabled) {
String packageName = mAppEntry.info.packageName;
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
final boolean enable = mNotificationSwitch.isChecked();
nm.setNotificationsEnabledForPackage(packageName, enabled);
} catch (android.os.RemoteException ex) {
mNotificationSwitch.setChecked(!enabled); // revert
}
}
/* /*
* Method implementing functionality of buttons clicked * Method implementing functionality of buttons clicked
* @see android.view.View.OnClickListener#onClick(android.view.View) * @see android.view.View.OnClickListener#onClick(android.view.View)
@@ -1003,12 +1049,10 @@ public class InstalledAppDetails extends Fragment
am.setPackageScreenCompatMode(packageName, isChecked ? am.setPackageScreenCompatMode(packageName, isChecked ?
ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED); ActivityManager.COMPAT_MODE_ENABLED : ActivityManager.COMPAT_MODE_DISABLED);
} else if (buttonView == mNotificationSwitch) { } else if (buttonView == mNotificationSwitch) {
INotificationManager nm = INotificationManager.Stub.asInterface( if (!isChecked) {
ServiceManager.getService(Context.NOTIFICATION_SERVICE)); showDialogInner(DLG_DISABLE_NOTIFICATIONS, 0);
try { } else {
nm.setNotificationsEnabledForPackage(packageName, isChecked); setNotificationsEnabled(true);
} catch (android.os.RemoteException ex) {
mNotificationSwitch.setChecked(!isChecked); // revert
} }
} }
} }