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 
17 package com.android.settings.notification;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.PackageManager.NameNotFoundException;
24 import android.os.Bundle;
25 import android.preference.Preference;
26 import android.preference.Preference.OnPreferenceChangeListener;
27 import android.preference.SwitchPreference;
28 import android.provider.Settings;
29 import android.text.TextUtils;
30 import android.util.ArrayMap;
31 import android.util.Log;
32 import android.view.View;
33 import android.view.View.OnClickListener;
34 import android.view.ViewGroup;
35 import android.widget.ImageView;
36 import android.widget.TextView;
37 import android.widget.Toast;
38 
39 import com.android.internal.widget.LockPatternUtils;
40 import com.android.settings.R;
41 import com.android.settings.SettingsPreferenceFragment;
42 import com.android.settings.Utils;
43 import com.android.settings.notification.NotificationAppList.AppRow;
44 import com.android.settings.notification.NotificationAppList.Backend;
45 
46 /** These settings are per app, so should not be returned in global search results. */
47 public 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
onActivityCreated(Bundle savedInstanceState)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
onCreate(Bundle savedInstanceState)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 
getLockscreenNotificationsEnabled()198     private boolean getLockscreenNotificationsEnabled() {
199         return Settings.Secure.getInt(getContentResolver(),
200                 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0;
201     }
202 
getLockscreenAllowPrivateNotifications()203     private boolean getLockscreenAllowPrivateNotifications() {
204         return Settings.Secure.getInt(getContentResolver(),
205                 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0;
206     }
207 
toastAndFinish()208     private void toastAndFinish() {
209         Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show();
210         getActivity().finish();
211     }
212 
findPackageInfo(PackageManager pm, String pkg, int uid)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