OSDN Git Service

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