1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.notification; 18 19 import com.android.settings.R; 20 import com.android.settings.SettingsPreferenceFragment; 21 import com.android.settings.applications.AppInfoBase; 22 import com.android.settingslib.RestrictedLockUtils; 23 import com.android.settingslib.RestrictedSwitchPreference; 24 25 import android.app.Notification; 26 import android.app.admin.DevicePolicyManager; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.PackageInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageManager.NameNotFoundException; 32 import android.os.Bundle; 33 import android.os.UserHandle; 34 import android.os.UserManager; 35 import android.provider.Settings; 36 import android.service.notification.NotificationListenerService.Ranking; 37 import android.support.v7.preference.Preference; 38 import android.text.TextUtils; 39 import android.util.Log; 40 import android.widget.Toast; 41 42 import java.util.ArrayList; 43 44 import static com.android.settings.notification.RestrictedDropDownPreference.RestrictedItem; 45 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 46 47 abstract public class NotificationSettingsBase extends SettingsPreferenceFragment { 48 private static final String TAG = "NotifiSettingsBase"; 49 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 50 private static final String TUNER_SETTING = "show_importance_slider"; 51 52 protected static final String KEY_BYPASS_DND = "bypass_dnd"; 53 protected static final String KEY_VISIBILITY_OVERRIDE = "visibility_override"; 54 protected static final String KEY_IMPORTANCE = "importance"; 55 protected static final String KEY_BLOCK = "block"; 56 protected static final String KEY_SILENT = "silent"; 57 58 protected PackageManager mPm; 59 protected UserManager mUm; 60 protected final NotificationBackend mBackend = new NotificationBackend(); 61 protected Context mContext; 62 protected boolean mCreated; 63 protected int mUid; 64 protected int mUserId; 65 protected String mPkg; 66 protected PackageInfo mPkgInfo; 67 protected ImportanceSeekBarPreference mImportance; 68 protected RestrictedSwitchPreference mPriority; 69 protected RestrictedDropDownPreference mVisibilityOverride; 70 protected RestrictedSwitchPreference mBlock; 71 protected RestrictedSwitchPreference mSilent; 72 protected EnforcedAdmin mSuspendedAppsAdmin; 73 protected boolean mShowSlider = false; 74 75 @Override onActivityCreated(Bundle savedInstanceState)76 public void onActivityCreated(Bundle savedInstanceState) { 77 super.onActivityCreated(savedInstanceState); 78 if (DEBUG) Log.d(TAG, "onActivityCreated mCreated=" + mCreated); 79 if (mCreated) { 80 Log.w(TAG, "onActivityCreated: ignoring duplicate call"); 81 return; 82 } 83 mCreated = true; 84 } 85 86 @Override onCreate(Bundle savedInstanceState)87 public void onCreate(Bundle savedInstanceState) { 88 super.onCreate(savedInstanceState); 89 mContext = getActivity(); 90 Intent intent = getActivity().getIntent(); 91 Bundle args = getArguments(); 92 if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent); 93 if (intent == null && args == null) { 94 Log.w(TAG, "No intent"); 95 toastAndFinish(); 96 return; 97 } 98 99 mPm = getPackageManager(); 100 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 101 102 mPkg = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_NAME) 103 ? args.getString(AppInfoBase.ARG_PACKAGE_NAME) 104 : intent.getStringExtra(Settings.EXTRA_APP_PACKAGE); 105 mUid = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_UID) 106 ? args.getInt(AppInfoBase.ARG_PACKAGE_UID) 107 : intent.getIntExtra(Settings.EXTRA_APP_UID, -1); 108 if (mUid == -1 || TextUtils.isEmpty(mPkg)) { 109 Log.w(TAG, "Missing extras: " + Settings.EXTRA_APP_PACKAGE + " was " + mPkg + ", " 110 + Settings.EXTRA_APP_UID + " was " + mUid); 111 toastAndFinish(); 112 return; 113 } 114 mUserId = UserHandle.getUserId(mUid); 115 116 if (DEBUG) Log.d(TAG, "Load details for pkg=" + mPkg + " uid=" + mUid); 117 mPkgInfo = findPackageInfo(mPkg, mUid); 118 if (mPkgInfo == null) { 119 Log.w(TAG, "Failed to find package info: " + Settings.EXTRA_APP_PACKAGE + " was " + mPkg 120 + ", " + Settings.EXTRA_APP_UID + " was " + mUid); 121 toastAndFinish(); 122 return; 123 } 124 125 mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended( 126 mContext, mPkg, mUserId); 127 mShowSlider = Settings.Secure.getInt(getContentResolver(), TUNER_SETTING, 0) == 1; 128 } 129 130 @Override onResume()131 public void onResume() { 132 super.onResume(); 133 if ((mUid != -1 && getPackageManager().getPackagesForUid(mUid) == null)) { 134 // App isn't around anymore, must have been removed. 135 finish(); 136 return; 137 } 138 mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended( 139 mContext, mPkg, mUserId); 140 if (mImportance != null) { 141 mImportance.setDisabledByAdmin(mSuspendedAppsAdmin); 142 } 143 if (mPriority != null) { 144 mPriority.setDisabledByAdmin(mSuspendedAppsAdmin); 145 } 146 if (mBlock != null) { 147 mBlock.setDisabledByAdmin(mSuspendedAppsAdmin); 148 } 149 if (mSilent != null) { 150 mSilent.setDisabledByAdmin(mSuspendedAppsAdmin); 151 } 152 if (mVisibilityOverride != null) { 153 mVisibilityOverride.setDisabledByAdmin(mSuspendedAppsAdmin); 154 } 155 } 156 setupImportancePrefs(boolean notBlockable, boolean notSilenceable, int importance, boolean banned)157 protected void setupImportancePrefs(boolean notBlockable, boolean notSilenceable, 158 int importance, boolean banned) { 159 if (mShowSlider && !notSilenceable) { 160 setVisible(mBlock, false); 161 setVisible(mSilent, false); 162 mImportance.setDisabledByAdmin(mSuspendedAppsAdmin); 163 mImportance.setMinimumProgress( 164 notBlockable ? Ranking.IMPORTANCE_MIN : Ranking.IMPORTANCE_NONE); 165 mImportance.setMax(Ranking.IMPORTANCE_MAX); 166 mImportance.setProgress(importance); 167 mImportance.setAutoOn(importance == Ranking.IMPORTANCE_UNSPECIFIED); 168 mImportance.setCallback(new ImportanceSeekBarPreference.Callback() { 169 @Override 170 public void onImportanceChanged(int progress, boolean fromUser) { 171 if (fromUser) { 172 mBackend.setImportance(mPkg, mUid, progress); 173 } 174 updateDependents(progress); 175 } 176 }); 177 } else { 178 setVisible(mImportance, false); 179 // Hide controls that are not settable, unless they are already switched on. 180 final boolean blocked = (importance == Ranking.IMPORTANCE_NONE || banned); 181 if (notBlockable && !blocked) { 182 setVisible(mBlock, false); 183 } else { 184 mBlock.setChecked(blocked); 185 mBlock.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 186 @Override 187 public boolean onPreferenceChange(Preference preference, Object newValue) { 188 final boolean blocked = (Boolean) newValue; 189 final int importance = 190 blocked ? Ranking.IMPORTANCE_NONE : Ranking.IMPORTANCE_UNSPECIFIED; 191 mBackend.setImportance(mPkgInfo.packageName, mUid, importance); 192 updateDependents(importance); 193 return true; 194 } 195 }); 196 } 197 final boolean silenced = (importance == Ranking.IMPORTANCE_LOW); 198 if (notSilenceable && !silenced) { 199 setVisible(mSilent, false); 200 } else { 201 mSilent.setChecked(silenced); 202 mSilent.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 203 @Override 204 public boolean onPreferenceChange(Preference preference, Object newValue) { 205 final boolean silenced = (Boolean) newValue; 206 final int importance = 207 silenced ? Ranking.IMPORTANCE_LOW : Ranking.IMPORTANCE_UNSPECIFIED; 208 mBackend.setImportance(mPkgInfo.packageName, mUid, importance); 209 updateDependents(importance); 210 return true; 211 } 212 }); 213 } 214 updateDependents(banned ? Ranking.IMPORTANCE_NONE : importance); 215 } 216 } 217 setupPriorityPref(boolean priority)218 protected void setupPriorityPref(boolean priority) { 219 mPriority.setDisabledByAdmin(mSuspendedAppsAdmin); 220 mPriority.setChecked(priority); 221 mPriority.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 222 @Override 223 public boolean onPreferenceChange(Preference preference, Object newValue) { 224 final boolean bypassZenMode = (Boolean) newValue; 225 return mBackend.setBypassZenMode(mPkgInfo.packageName, mUid, bypassZenMode); 226 } 227 }); 228 } 229 setupVisOverridePref(int sensitive)230 protected void setupVisOverridePref(int sensitive) { 231 ArrayList<CharSequence> entries = new ArrayList<>(); 232 ArrayList<CharSequence> values = new ArrayList<>(); 233 234 mVisibilityOverride.clearRestrictedItems(); 235 if (getLockscreenNotificationsEnabled() && getLockscreenAllowPrivateNotifications()) { 236 final String summaryShowEntry = 237 getString(R.string.lock_screen_notifications_summary_show); 238 final String summaryShowEntryValue = Integer.toString(Ranking.VISIBILITY_NO_OVERRIDE); 239 entries.add(summaryShowEntry); 240 values.add(summaryShowEntryValue); 241 setRestrictedIfNotificationFeaturesDisabled(summaryShowEntry, summaryShowEntryValue, 242 DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS 243 | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS); 244 } 245 246 final String summaryHideEntry = getString(R.string.lock_screen_notifications_summary_hide); 247 final String summaryHideEntryValue = Integer.toString(Notification.VISIBILITY_PRIVATE); 248 entries.add(summaryHideEntry); 249 values.add(summaryHideEntryValue); 250 setRestrictedIfNotificationFeaturesDisabled(summaryHideEntry, summaryHideEntryValue, 251 DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); 252 entries.add(getString(R.string.lock_screen_notifications_summary_disable)); 253 values.add(Integer.toString(Notification.VISIBILITY_SECRET)); 254 mVisibilityOverride.setEntries(entries.toArray(new CharSequence[entries.size()])); 255 mVisibilityOverride.setEntryValues(values.toArray(new CharSequence[values.size()])); 256 257 if (sensitive == Ranking.VISIBILITY_NO_OVERRIDE) { 258 mVisibilityOverride.setValue(Integer.toString(getGlobalVisibility())); 259 } else { 260 mVisibilityOverride.setValue(Integer.toString(sensitive)); 261 } 262 mVisibilityOverride.setSummary("%s"); 263 264 mVisibilityOverride.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 265 @Override 266 public boolean onPreferenceChange(Preference preference, Object newValue) { 267 int sensitive = Integer.parseInt((String) newValue); 268 if (sensitive == getGlobalVisibility()) { 269 sensitive = Ranking.VISIBILITY_NO_OVERRIDE; 270 } 271 mBackend.setVisibilityOverride(mPkgInfo.packageName, mUid, sensitive); 272 return true; 273 } 274 }); 275 } 276 setRestrictedIfNotificationFeaturesDisabled(CharSequence entry, CharSequence entryValue, int keyguardNotificationFeatures)277 private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry, 278 CharSequence entryValue, int keyguardNotificationFeatures) { 279 EnforcedAdmin admin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled( 280 mContext, keyguardNotificationFeatures, mUserId); 281 if (admin != null) { 282 RestrictedItem item = new RestrictedItem(entry, entryValue, admin); 283 mVisibilityOverride.addRestrictedItem(item); 284 } 285 } 286 getGlobalVisibility()287 private int getGlobalVisibility() { 288 int globalVis = Ranking.VISIBILITY_NO_OVERRIDE; 289 if (!getLockscreenNotificationsEnabled()) { 290 globalVis = Notification.VISIBILITY_SECRET; 291 } else if (!getLockscreenAllowPrivateNotifications()) { 292 globalVis = Notification.VISIBILITY_PRIVATE; 293 } 294 return globalVis; 295 } 296 getLockscreenNotificationsEnabled()297 protected boolean getLockscreenNotificationsEnabled() { 298 return Settings.Secure.getInt(getContentResolver(), 299 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0; 300 } 301 getLockscreenAllowPrivateNotifications()302 protected boolean getLockscreenAllowPrivateNotifications() { 303 return Settings.Secure.getInt(getContentResolver(), 304 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0; 305 } 306 updateDependents(int progress)307 abstract void updateDependents(int progress); 308 setVisible(Preference p, boolean visible)309 protected void setVisible(Preference p, boolean visible) { 310 final boolean isVisible = getPreferenceScreen().findPreference(p.getKey()) != null; 311 if (isVisible == visible) return; 312 if (visible) { 313 getPreferenceScreen().addPreference(p); 314 } else { 315 getPreferenceScreen().removePreference(p); 316 } 317 } 318 toastAndFinish()319 protected void toastAndFinish() { 320 Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show(); 321 getActivity().finish(); 322 } 323 findPackageInfo(String pkg, int uid)324 private PackageInfo findPackageInfo(String pkg, int uid) { 325 final String[] packages = mPm.getPackagesForUid(uid); 326 if (packages != null && pkg != null) { 327 final int N = packages.length; 328 for (int i = 0; i < N; i++) { 329 final String p = packages[i]; 330 if (pkg.equals(p)) { 331 try { 332 return mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES); 333 } catch (NameNotFoundException e) { 334 Log.w(TAG, "Failed to load package " + pkg, e); 335 } 336 } 337 } 338 } 339 return null; 340 } 341 } 342