OSDN Git Service

[automerger skipped] Merge "Do not allow draw on top for App notification settings...
[android-x86/packages-apps-Settings.git] / src / com / android / settings / notification / ChannelNotificationSettings.java
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 android.app.Activity;
20 import android.app.NotificationChannel;
21 import android.app.NotificationChannelGroup;
22 import android.app.NotificationManager;
23 import android.content.Intent;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.os.AsyncTask;
27 import android.provider.Settings;
28 import android.support.v7.preference.Preference;
29 import android.support.v7.preference.PreferenceGroup;
30 import android.text.TextUtils;
31 import android.text.BidiFormatter;
32 import android.text.SpannableStringBuilder;
33 import android.util.ArrayMap;
34 import android.util.Log;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.widget.Switch;
38
39 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
40 import com.android.settings.R;
41 import com.android.settings.RingtonePreference;
42 import com.android.settings.Utils;
43 import com.android.settings.applications.AppInfoBase;
44 import com.android.settings.applications.LayoutPreference;
45 import com.android.settings.widget.EntityHeaderController;
46 import com.android.settings.widget.SwitchBar;
47 import com.android.settingslib.RestrictedSwitchPreference;
48 import com.android.settingslib.widget.FooterPreference;
49
50 import static android.app.NotificationManager.IMPORTANCE_LOW;
51 import static android.app.NotificationManager.IMPORTANCE_NONE;
52 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
53
54 public class ChannelNotificationSettings extends NotificationSettingsBase {
55     private static final String TAG = "ChannelSettings";
56
57     private static final String KEY_LIGHTS = "lights";
58     private static final String KEY_VIBRATE = "vibrate";
59     private static final String KEY_RINGTONE = "ringtone";
60     private static final String KEY_IMPORTANCE = "importance";
61     private static final String KEY_ADVANCED = "advanced";
62
63     private Preference mImportance;
64     private RestrictedSwitchPreference mLights;
65     private RestrictedSwitchPreference mVibrate;
66     private NotificationSoundPreference mRingtone;
67     private FooterPreference mFooter;
68     private NotificationChannelGroup mChannelGroup;
69     private EntityHeaderController mHeaderPref;
70     private PreferenceGroup mAdvanced;
71
72     @Override
73     public int getMetricsCategory() {
74         return MetricsEvent.NOTIFICATION_TOPIC_NOTIFICATION;
75     }
76
77     @Override
78     public void onResume() {
79         super.onResume();
80         if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannel == null) {
81             Log.w(TAG, "Missing package or uid or packageinfo or channel");
82             finish();
83             return;
84         }
85
86         if (getPreferenceScreen() != null) {
87             getPreferenceScreen().removeAll();
88         }
89         addPreferencesFromResource(R.xml.notification_settings);
90         setupBlock();
91         addHeaderPref();
92         addAppLinkPref();
93         addFooterPref();
94
95         if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(mChannel.getId())) {
96             populateDefaultChannelPrefs();
97             mShowLegacyChannelConfig = true;
98         } else {
99             populateUpgradedChannelPrefs();
100
101             if (mChannel.getGroup() != null) {
102                 // Go look up group name
103                 new AsyncTask<Void, Void, Void>() {
104                     @Override
105                     protected Void doInBackground(Void... unused) {
106                         if (mChannel.getGroup() != null) {
107                             mChannelGroup = mBackend.getGroup(mChannel.getGroup(), mPkg, mUid);
108                         }
109                         return null;
110                     }
111
112                     @Override
113                     protected void onPostExecute(Void unused) {
114                         if (getHost() == null || mChannelGroup == null) {
115                             return;
116                         }
117                         setChannelGroupLabel(mChannelGroup.getName());
118                     }
119                 }.execute();
120             }
121         }
122
123         updateDependents(mChannel.getImportance() == IMPORTANCE_NONE);
124     }
125
126     private void populateUpgradedChannelPrefs() {
127         addPreferencesFromResource(R.xml.upgraded_channel_notification_settings);
128         setupBadge();
129         setupPriorityPref(mChannel.canBypassDnd());
130         setupVisOverridePref(mChannel.getLockscreenVisibility());
131         setupLights();
132         setupVibrate();
133         setupRingtone();
134         setupImportance();
135         mAdvanced = (PreferenceGroup) findPreference(KEY_ADVANCED);
136     }
137
138     private void addHeaderPref() {
139         ArrayMap<String, NotificationBackend.AppRow> rows = new ArrayMap<>();
140         rows.put(mAppRow.pkg, mAppRow);
141         collectConfigActivities(rows);
142         final Activity activity = getActivity();
143         mHeaderPref = EntityHeaderController
144                 .newInstance(activity, this /* fragment */, null /* header */)
145                 .setRecyclerView(getListView(), getLifecycle());
146         final Preference pref = mHeaderPref
147                 .setIcon(mAppRow.icon)
148                 .setLabel(mChannel.getName())
149                 .setSummary(mAppRow.label)
150                 .setPackageName(mAppRow.pkg)
151                 .setUid(mAppRow.uid)
152                 .setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
153                         EntityHeaderController.ActionType.ACTION_NONE)
154                 .setHasAppInfoLink(true)
155                 .done(activity, getPrefContext());
156         getPreferenceScreen().addPreference(pref);
157     }
158
159     private void setChannelGroupLabel(CharSequence groupName) {
160         final SpannableStringBuilder summary = new SpannableStringBuilder();
161         BidiFormatter bidi = BidiFormatter.getInstance();
162         summary.append(bidi.unicodeWrap(mAppRow.label.toString()));
163         if (groupName != null) {
164             summary.append(bidi.unicodeWrap(mContext.getText(
165                     R.string.notification_header_divider_symbol_with_spaces)));
166             summary.append(bidi.unicodeWrap(groupName.toString()));
167         }
168         final Activity activity = getActivity();
169         mHeaderPref.setSummary(summary.toString());
170         mHeaderPref.done(activity, getPrefContext());
171     }
172
173     private void addFooterPref() {
174         if (!TextUtils.isEmpty(mChannel.getDescription())) {
175             FooterPreference descPref = new FooterPreference(getPrefContext());
176             descPref.setOrder(ORDER_LAST);
177             descPref.setSelectable(false);
178             descPref.setTitle(mChannel.getDescription());
179             getPreferenceScreen().addPreference(descPref);
180         }
181     }
182
183     protected void setupBadge() {
184         mBadge = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BADGE);
185         mBadge.setDisabledByAdmin(mSuspendedAppsAdmin);
186         mBadge.setEnabled(mAppRow.showBadge);
187         mBadge.setChecked(mChannel.canShowBadge());
188
189         mBadge.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
190             @Override
191             public boolean onPreferenceChange(Preference preference, Object newValue) {
192                 final boolean value = (Boolean) newValue;
193                 mChannel.setShowBadge(value);
194                 mChannel.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
195                 mBackend.updateChannel(mPkg, mUid, mChannel);
196                 return true;
197             }
198         });
199     }
200
201     private void setupLights() {
202         mLights = (RestrictedSwitchPreference) findPreference(KEY_LIGHTS);
203         mLights.setDisabledByAdmin(mSuspendedAppsAdmin);
204         mLights.setChecked(mChannel.shouldShowLights());
205         mLights.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
206             @Override
207             public boolean onPreferenceChange(Preference preference, Object newValue) {
208                 final boolean lights = (Boolean) newValue;
209                 mChannel.enableLights(lights);
210                 mChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
211                 mBackend.updateChannel(mPkg, mUid, mChannel);
212                 return true;
213             }
214         });
215     }
216
217     private void setupVibrate() {
218         mVibrate = (RestrictedSwitchPreference) findPreference(KEY_VIBRATE);
219         mVibrate.setDisabledByAdmin(mSuspendedAppsAdmin);
220         mVibrate.setEnabled(!mVibrate.isDisabledByAdmin() && isChannelConfigurable(mChannel));
221         mVibrate.setChecked(mChannel.shouldVibrate());
222         mVibrate.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
223             @Override
224             public boolean onPreferenceChange(Preference preference, Object newValue) {
225                 final boolean vibrate = (Boolean) newValue;
226                 mChannel.enableVibration(vibrate);
227                 mChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
228                 mBackend.updateChannel(mPkg, mUid, mChannel);
229                 return true;
230             }
231         });
232     }
233
234     private void setupRingtone() {
235         mRingtone = (NotificationSoundPreference) findPreference(KEY_RINGTONE);
236         mRingtone.setRingtone(mChannel.getSound());
237         mRingtone.setEnabled(isChannelConfigurable(mChannel));
238         mRingtone.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
239             @Override
240             public boolean onPreferenceChange(Preference preference, Object newValue) {
241                 mChannel.setSound((Uri) newValue, mChannel.getAudioAttributes());
242                 mChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
243                 mBackend.updateChannel(mPkg, mUid, mChannel);
244                 return false;
245             }
246         });
247     }
248
249     private void setupBlock() {
250         View switchBarContainer = LayoutInflater.from(
251                 getPrefContext()).inflate(R.layout.styled_switch_bar, null);
252         mSwitchBar = switchBarContainer.findViewById(R.id.switch_bar);
253         mSwitchBar.show();
254         mSwitchBar.setDisabledByAdmin(mSuspendedAppsAdmin);
255         mSwitchBar.setChecked(mChannel.getImportance() != NotificationManager.IMPORTANCE_NONE);
256         mSwitchBar.addOnSwitchChangeListener(new SwitchBar.OnSwitchChangeListener() {
257             @Override
258             public void onSwitchChanged(Switch switchView, boolean isChecked) {
259                 int importance = 0;
260                 if (mShowLegacyChannelConfig) {
261                     importance = isChecked ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_NONE;
262                     mImportanceToggle.setChecked(importance == IMPORTANCE_UNSPECIFIED);
263                 } else {
264                     importance = isChecked ? IMPORTANCE_LOW : IMPORTANCE_NONE;
265                     mImportance.setSummary(getImportanceSummary(importance));
266                 }
267                 mChannel.setImportance(importance);
268                 mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
269                 mBackend.updateChannel(mPkg, mUid, mChannel);
270                 updateDependents(mChannel.getImportance() == IMPORTANCE_NONE);
271             }
272         });
273
274         mBlockBar = new LayoutPreference(getPrefContext(), switchBarContainer);
275         mBlockBar.setOrder(ORDER_FIRST);
276         mBlockBar.setKey(KEY_BLOCK);
277         getPreferenceScreen().addPreference(mBlockBar);
278
279         if (!isChannelBlockable(mAppRow.systemApp, mChannel)) {
280             setVisible(mBlockBar, false);
281         }
282
283         setupBlockDesc(R.string.channel_notifications_off_desc);
284     }
285
286     private void setupImportance() {
287         mImportance = findPreference(KEY_IMPORTANCE);
288         Bundle channelArgs = new Bundle();
289         channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
290         channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
291         channelArgs.putString(Settings.EXTRA_CHANNEL_ID, mChannel.getId());
292         mImportance.setEnabled(mSuspendedAppsAdmin == null && isChannelConfigurable(mChannel));
293         // Set up intent to show importance selection only if this setting is enabled.
294         if (mImportance.isEnabled()) {
295             Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
296                     ChannelImportanceSettings.class.getName(),
297                     channelArgs, null, R.string.notification_importance_title, null,
298                     false, getMetricsCategory());
299             mImportance.setIntent(channelIntent);
300         }
301         mImportance.setSummary(getImportanceSummary(mChannel.getImportance()));
302     }
303
304     private String getImportanceSummary(int importance) {
305         String title;
306         String summary = null;
307         switch (importance) {
308             case IMPORTANCE_UNSPECIFIED:
309                 title = getContext().getString(R.string.notification_importance_unspecified);
310                 break;
311             case NotificationManager.IMPORTANCE_MIN:
312                 title = getContext().getString(R.string.notification_importance_min_title);
313                 summary = getContext().getString(R.string.notification_importance_min);
314                 break;
315             case NotificationManager.IMPORTANCE_LOW:
316                 title = getContext().getString(R.string.notification_importance_low_title);
317                 summary = getContext().getString(R.string.notification_importance_low);
318                 break;
319             case NotificationManager.IMPORTANCE_DEFAULT:
320                 title = getContext().getString(R.string.notification_importance_default_title);
321                 if (hasValidSound(mChannel)) {
322                     summary = getContext().getString(R.string.notification_importance_default);
323                 } else {
324                     summary = getContext().getString(R.string.notification_importance_low);
325                 }
326                 break;
327             case NotificationManager.IMPORTANCE_HIGH:
328             case NotificationManager.IMPORTANCE_MAX:
329                 title = getContext().getString(R.string.notification_importance_high_title);
330                 if (hasValidSound(mChannel)) {
331                     summary = getContext().getString(R.string.notification_importance_high);
332                 } else {
333                     summary = getContext().getString(R.string.notification_importance_high_silent);
334                 }
335                 break;
336             default:
337                 return "";
338         }
339
340         if (summary != null) {
341             return getContext().getString(R.string.notification_importance_divider, title, summary);
342         } else {
343             return title;
344         }
345     }
346
347     @Override
348     public boolean onPreferenceTreeClick(Preference preference) {
349         if (preference instanceof RingtonePreference) {
350             mRingtone.onPrepareRingtonePickerIntent(mRingtone.getIntent());
351             startActivityForResult(preference.getIntent(), 200);
352             return true;
353         }
354         return super.onPreferenceTreeClick(preference);
355     }
356
357     @Override
358     public void onActivityResult(int requestCode, int resultCode, Intent data) {
359         if (mRingtone != null) {
360             mRingtone.onActivityResult(requestCode, resultCode, data);
361         }
362         if (mChannel != null) {
363             mImportance.setSummary(getImportanceSummary(mChannel.getImportance()));
364         }
365     }
366
367     boolean canPulseLight() {
368         if (!getResources()
369                 .getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) {
370             return false;
371         }
372         return Settings.System.getInt(getContentResolver(),
373                 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) == 1;
374     }
375
376     void updateDependents(boolean banned) {
377         PreferenceGroup parent;
378         if (mShowLegacyChannelConfig) {
379             parent = getPreferenceScreen();
380             setVisible(mImportanceToggle, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
381         } else {
382             setVisible(mAdvanced, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
383             setVisible(mImportance, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
384             setVisible(mAdvanced, mLights, checkCanBeVisible(
385                     NotificationManager.IMPORTANCE_DEFAULT) && canPulseLight());
386             setVisible(mVibrate, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT));
387             setVisible(mRingtone, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT));
388             parent = mAdvanced;
389         }
390         setVisible(parent, mBadge, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
391         setVisible(parent, mPriority, checkCanBeVisible(NotificationManager.IMPORTANCE_DEFAULT)
392                 || (checkCanBeVisible(NotificationManager.IMPORTANCE_LOW)
393                 && mDndVisualEffectsSuppressed));
394         setVisible(parent, mVisibilityOverride, isLockScreenSecure()
395                 &&checkCanBeVisible(NotificationManager.IMPORTANCE_LOW));
396         setVisible(mBlockedDesc, mChannel.getImportance() == IMPORTANCE_NONE);
397         if (mAppLink != null) {
398             setVisible(mAppLink, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
399         }
400         if (mFooter != null) {
401             setVisible(mFooter, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
402         }
403     }
404 }