1/* 2 * Copyright (C) 2014 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 17package com.android.settings.notification; 18 19import android.content.Context; 20import android.content.Intent; 21import android.content.pm.PackageInfo; 22import android.content.pm.PackageManager; 23import android.content.pm.PackageManager.NameNotFoundException; 24import android.os.Bundle; 25import android.preference.Preference; 26import android.preference.Preference.OnPreferenceChangeListener; 27import android.preference.SwitchPreference; 28import android.provider.Settings; 29import android.text.TextUtils; 30import android.util.ArrayMap; 31import android.util.Log; 32import android.view.View; 33import android.view.View.OnClickListener; 34import android.view.ViewGroup; 35import android.widget.ImageView; 36import android.widget.TextView; 37import android.widget.Toast; 38 39import com.android.internal.widget.LockPatternUtils; 40import com.android.settings.R; 41import com.android.settings.SettingsPreferenceFragment; 42import com.android.settings.Utils; 43import com.android.settings.notification.NotificationAppList.AppRow; 44import com.android.settings.notification.NotificationAppList.Backend; 45 46/** These settings are per app, so should not be returned in global search results. */ 47public class AppNotificationSettings extends SettingsPreferenceFragment { 48 private static final String TAG = "AppNotificationSettings"; 49 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 50 51 private static final String KEY_BLOCK = "block"; 52 private static final String KEY_PRIORITY = "priority"; 53 private static final String KEY_SENSITIVE = "sensitive"; 54 55 static final String EXTRA_HAS_SETTINGS_INTENT = "has_settings_intent"; 56 static final String EXTRA_SETTINGS_INTENT = "settings_intent"; 57 58 private final Backend mBackend = new Backend(); 59 60 private Context mContext; 61 private SwitchPreference mBlock; 62 private SwitchPreference mPriority; 63 private SwitchPreference mSensitive; 64 private AppRow mAppRow; 65 private boolean mCreated; 66 67 @Override 68 public void onActivityCreated(Bundle savedInstanceState) { 69 super.onActivityCreated(savedInstanceState); 70 if (DEBUG) Log.d(TAG, "onActivityCreated mCreated=" + mCreated); 71 if (mCreated) { 72 Log.w(TAG, "onActivityCreated: ignoring duplicate call"); 73 return; 74 } 75 mCreated = true; 76 if (mAppRow == null) return; 77 final View content = getActivity().findViewById(R.id.main_content); 78 final ViewGroup contentParent = (ViewGroup) content.getParent(); 79 final View bar = getActivity().getLayoutInflater().inflate(R.layout.app_notification_header, 80 contentParent, false); 81 82 final ImageView appIcon = (ImageView) bar.findViewById(R.id.app_icon); 83 appIcon.setImageDrawable(mAppRow.icon); 84 85 final TextView appName = (TextView) bar.findViewById(R.id.app_name); 86 appName.setText(mAppRow.label); 87 88 final View appSettings = bar.findViewById(R.id.app_settings); 89 if (mAppRow.settingsIntent == null) { 90 appSettings.setVisibility(View.GONE); 91 } else { 92 appSettings.setClickable(true); 93 appSettings.setOnClickListener(new OnClickListener() { 94 @Override 95 public void onClick(View v) { 96 mContext.startActivity(mAppRow.settingsIntent); 97 } 98 }); 99 } 100 contentParent.addView(bar, 0); 101 } 102 103 @Override 104 public void onCreate(Bundle savedInstanceState) { 105 super.onCreate(savedInstanceState); 106 mContext = getActivity(); 107 Intent intent = getActivity().getIntent(); 108 if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent); 109 if (intent == null) { 110 Log.w(TAG, "No intent"); 111 toastAndFinish(); 112 return; 113 } 114 115 final int uid = intent.getIntExtra(Settings.EXTRA_APP_UID, -1); 116 final String pkg = intent.getStringExtra(Settings.EXTRA_APP_PACKAGE); 117 if (uid == -1 || TextUtils.isEmpty(pkg)) { 118 Log.w(TAG, "Missing extras: " + Settings.EXTRA_APP_PACKAGE + " was " + pkg + ", " 119 + Settings.EXTRA_APP_UID + " was " + uid); 120 toastAndFinish(); 121 return; 122 } 123 124 if (DEBUG) Log.d(TAG, "Load details for pkg=" + pkg + " uid=" + uid); 125 final PackageManager pm = getPackageManager(); 126 final PackageInfo info = findPackageInfo(pm, pkg, uid); 127 if (info == null) { 128 Log.w(TAG, "Failed to find package info: " + Settings.EXTRA_APP_PACKAGE + " was " + pkg 129 + ", " + Settings.EXTRA_APP_UID + " was " + uid); 130 toastAndFinish(); 131 return; 132 } 133 134 addPreferencesFromResource(R.xml.app_notification_settings); 135 mBlock = (SwitchPreference) findPreference(KEY_BLOCK); 136 mPriority = (SwitchPreference) findPreference(KEY_PRIORITY); 137 mSensitive = (SwitchPreference) findPreference(KEY_SENSITIVE); 138 139 final boolean secure = new LockPatternUtils(getActivity()).isSecure(); 140 final boolean enabled = getLockscreenNotificationsEnabled(); 141 final boolean allowPrivate = getLockscreenAllowPrivateNotifications(); 142 if (!secure || !enabled || !allowPrivate) { 143 getPreferenceScreen().removePreference(mSensitive); 144 } 145 146 mAppRow = NotificationAppList.loadAppRow(pm, info.applicationInfo, mBackend); 147 if (intent.hasExtra(EXTRA_HAS_SETTINGS_INTENT)) { 148 // use settings intent from extra 149 if (intent.getBooleanExtra(EXTRA_HAS_SETTINGS_INTENT, false)) { 150 mAppRow.settingsIntent = intent.getParcelableExtra(EXTRA_SETTINGS_INTENT); 151 } 152 } else { 153 // load settings intent 154 ArrayMap<String, AppRow> rows = new ArrayMap<String, AppRow>(); 155 rows.put(mAppRow.pkg, mAppRow); 156 NotificationAppList.collectConfigActivities(getPackageManager(), rows); 157 } 158 159 mBlock.setChecked(mAppRow.banned); 160 mPriority.setChecked(mAppRow.priority); 161 if (mSensitive != null) { 162 mSensitive.setChecked(mAppRow.sensitive); 163 } 164 165 mBlock.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 166 @Override 167 public boolean onPreferenceChange(Preference preference, Object newValue) { 168 final boolean block = (Boolean) newValue; 169 return mBackend.setNotificationsBanned(pkg, uid, block); 170 } 171 }); 172 173 mPriority.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 174 @Override 175 public boolean onPreferenceChange(Preference preference, Object newValue) { 176 final boolean priority = (Boolean) newValue; 177 return mBackend.setHighPriority(pkg, uid, priority); 178 } 179 }); 180 181 if (mSensitive != null) { 182 mSensitive.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 183 @Override 184 public boolean onPreferenceChange(Preference preference, Object newValue) { 185 final boolean sensitive = (Boolean) newValue; 186 return mBackend.setSensitive(pkg, uid, sensitive); 187 } 188 }); 189 } 190 191 // Users cannot block notifications from system/signature packages 192 if (Utils.isSystemPackage(pm, info)) { 193 getPreferenceScreen().removePreference(mBlock); 194 mPriority.setDependency(null); // don't have it depend on a preference that's gone 195 } 196 } 197 198 private boolean getLockscreenNotificationsEnabled() { 199 return Settings.Secure.getInt(getContentResolver(), 200 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0; 201 } 202 203 private boolean getLockscreenAllowPrivateNotifications() { 204 return Settings.Secure.getInt(getContentResolver(), 205 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0; 206 } 207 208 private void toastAndFinish() { 209 Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show(); 210 getActivity().finish(); 211 } 212 213 private static PackageInfo findPackageInfo(PackageManager pm, String pkg, int uid) { 214 final String[] packages = pm.getPackagesForUid(uid); 215 if (packages != null && pkg != null) { 216 final int N = packages.length; 217 for (int i = 0; i < N; i++) { 218 final String p = packages[i]; 219 if (pkg.equals(p)) { 220 try { 221 return pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES); 222 } catch (NameNotFoundException e) { 223 Log.w(TAG, "Failed to load package " + pkg, e); 224 } 225 } 226 } 227 } 228 return null; 229 } 230} 231