• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.NotificationChannel;
20 import android.app.NotificationChannelGroup;
21 import android.app.settings.SettingsEnums;
22 import android.content.Context;
23 import android.os.AsyncTask;
24 import android.os.Bundle;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import androidx.preference.Preference;
29 import androidx.preference.PreferenceCategory;
30 import androidx.preference.PreferenceGroup;
31 import androidx.preference.PreferenceScreen;
32 import androidx.preference.SwitchPreference;
33 
34 import com.android.internal.widget.LockPatternUtils;
35 import com.android.settings.R;
36 import com.android.settings.widget.MasterSwitchPreference;
37 import com.android.settingslib.RestrictedSwitchPreference;
38 import com.android.settingslib.core.AbstractPreferenceController;
39 
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.Comparator;
43 import java.util.List;
44 
45 /** These settings are per app, so should not be returned in global search results. */
46 public class AppNotificationSettings extends NotificationSettingsBase {
47     private static final String TAG = "AppNotificationSettings";
48     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
49 
50     private static String KEY_GENERAL_CATEGORY = "categories";
51     private static String KEY_ADVANCED_CATEGORY = "app_advanced";
52     private static String KEY_BADGE = "badge";
53     private static String KEY_APP_LINK = "app_link";
54     private static String KEY_BUBBLE = "bubble_link_pref";
55     private static String[] LEGACY_NON_ADVANCED_KEYS = {KEY_BADGE, KEY_APP_LINK, KEY_BUBBLE};
56 
57     private List<NotificationChannelGroup> mChannelGroupList;
58 
59     @Override
getMetricsCategory()60     public int getMetricsCategory() {
61         return SettingsEnums.NOTIFICATION_APP_NOTIFICATION;
62     }
63 
64     @Override
onCreate(Bundle savedInstanceState)65     public void onCreate(Bundle savedInstanceState) {
66         super.onCreate(savedInstanceState);
67         final PreferenceScreen screen = getPreferenceScreen();
68         if (mShowLegacyChannelConfig && screen != null) {
69             // if showing legacy settings, pull advanced settings out of the advanced category
70             PreferenceGroup advanced = (PreferenceGroup) findPreference(KEY_ADVANCED_CATEGORY);
71             removePreference(KEY_ADVANCED_CATEGORY);
72             if (advanced != null) {
73                 for (String key : LEGACY_NON_ADVANCED_KEYS) {
74                     Preference pref = advanced.findPreference(key);
75                     advanced.removePreference(pref);
76                     if (pref != null) {
77                         screen.addPreference(pref);
78                     }
79                 }
80             }
81         }
82     }
83 
84     @Override
onResume()85     public void onResume() {
86         super.onResume();
87 
88         if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
89             Log.w(TAG, "Missing package or uid or packageinfo");
90             finish();
91             return;
92         }
93 
94         if (!mShowLegacyChannelConfig) {
95             // Load channel settings
96             new AsyncTask<Void, Void, Void>() {
97                 @Override
98                 protected Void doInBackground(Void... unused) {
99                     mChannelGroupList = mBackend.getGroups(mPkg, mUid).getList();
100                     Collections.sort(mChannelGroupList, mChannelGroupComparator);
101                     return null;
102                 }
103 
104                 @Override
105                 protected void onPostExecute(Void unused) {
106                     if (getHost() == null) {
107                         return;
108                     }
109                     populateList();
110                 }
111             }.execute();
112         }
113 
114         for (NotificationPreferenceController controller : mControllers) {
115             controller.onResume(mAppRow, mChannel, mChannelGroup, mSuspendedAppsAdmin);
116             controller.displayPreference(getPreferenceScreen());
117         }
118         updatePreferenceStates();
119     }
120 
121     @Override
getLogTag()122     protected String getLogTag() {
123         return TAG;
124     }
125 
126     @Override
getPreferenceScreenResId()127     protected int getPreferenceScreenResId() {
128         return R.xml.app_notification_settings;
129     }
130 
131     @Override
createPreferenceControllers(Context context)132     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
133         mControllers = new ArrayList<>();
134         mControllers.add(new HeaderPreferenceController(context, this));
135         mControllers.add(new BlockPreferenceController(context, mImportanceListener, mBackend));
136         mControllers.add(new BadgePreferenceController(context, mBackend));
137         mControllers.add(new AllowSoundPreferenceController(
138                 context, mImportanceListener, mBackend));
139         mControllers.add(new ImportancePreferenceController(
140                 context, mImportanceListener, mBackend));
141         mControllers.add(new MinImportancePreferenceController(
142                 context, mImportanceListener, mBackend));
143         mControllers.add(new HighImportancePreferenceController(
144                 context, mImportanceListener, mBackend));
145         mControllers.add(new SoundPreferenceController(context, this,
146                 mImportanceListener, mBackend));
147         mControllers.add(new LightsPreferenceController(context, mBackend));
148         mControllers.add(new VibrationPreferenceController(context, mBackend));
149         mControllers.add(new VisibilityPreferenceController(context, new LockPatternUtils(context),
150                 mBackend));
151         mControllers.add(new DndPreferenceController(context, mBackend));
152         mControllers.add(new AppLinkPreferenceController(context));
153         mControllers.add(new DescriptionPreferenceController(context));
154         mControllers.add(new NotificationsOffPreferenceController(context));
155         mControllers.add(new DeletedChannelsPreferenceController(context, mBackend));
156         mControllers.add(new BubbleSummaryPreferenceController(context, mBackend));
157         return new ArrayList<>(mControllers);
158     }
159 
populateList()160     private void populateList() {
161         if (!mDynamicPreferences.isEmpty()) {
162             for (Preference p : mDynamicPreferences) {
163                 getPreferenceScreen().removePreference(p);
164             }
165             mDynamicPreferences.clear();
166         }
167         if (mChannelGroupList.isEmpty()) {
168             PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
169             groupCategory.setTitle(R.string.notification_channels);
170             groupCategory.setKey(KEY_GENERAL_CATEGORY);
171             getPreferenceScreen().addPreference(groupCategory);
172             mDynamicPreferences.add(groupCategory);
173 
174             Preference empty = new Preference(getPrefContext());
175             empty.setTitle(R.string.no_channels);
176             empty.setEnabled(false);
177             groupCategory.addPreference(empty);
178         } else {
179             populateGroupList();
180             mImportanceListener.onImportanceChanged();
181         }
182     }
183 
populateGroupList()184     private void populateGroupList() {
185         for (NotificationChannelGroup group : mChannelGroupList) {
186             PreferenceCategory groupCategory = new PreferenceCategory(getPrefContext());
187             groupCategory.setOrderingAsAdded(true);
188             getPreferenceScreen().addPreference(groupCategory);
189             mDynamicPreferences.add(groupCategory);
190             if (group.getId() == null) {
191                 if (mChannelGroupList.size() > 1) {
192                     groupCategory.setTitle(R.string.notification_channels_other);
193                 }
194                 groupCategory.setKey(KEY_GENERAL_CATEGORY);
195             } else {
196                 groupCategory.setTitle(group.getName());
197                 groupCategory.setKey(group.getId());
198                 populateGroupToggle(groupCategory, group);
199             }
200             if (!group.isBlocked()) {
201                 final List<NotificationChannel> channels = group.getChannels();
202                 Collections.sort(channels, mChannelComparator);
203                 int N = channels.size();
204                 for (int i = 0; i < N; i++) {
205                     final NotificationChannel channel = channels.get(i);
206                     populateSingleChannelPrefs(groupCategory, channel, group.isBlocked());
207                 }
208             }
209         }
210     }
211 
populateGroupToggle(final PreferenceGroup parent, NotificationChannelGroup group)212     protected void populateGroupToggle(final PreferenceGroup parent,
213             NotificationChannelGroup group) {
214         RestrictedSwitchPreference preference = new RestrictedSwitchPreference(getPrefContext());
215         preference.setTitle(R.string.notification_switch_label);
216         preference.setEnabled(mSuspendedAppsAdmin == null
217                 && isChannelGroupBlockable(group));
218         preference.setChecked(!group.isBlocked());
219         preference.setOnPreferenceClickListener(preference1 -> {
220             final boolean allowGroup = ((SwitchPreference) preference1).isChecked();
221             group.setBlocked(!allowGroup);
222             mBackend.updateChannelGroup(mAppRow.pkg, mAppRow.uid, group);
223 
224             onGroupBlockStateChanged(group);
225             return true;
226         });
227 
228         parent.addPreference(preference);
229     }
230 
231     private Comparator<NotificationChannelGroup> mChannelGroupComparator =
232             new Comparator<NotificationChannelGroup>() {
233 
234                 @Override
235                 public int compare(NotificationChannelGroup left, NotificationChannelGroup right) {
236                     // Non-grouped channels (in placeholder group with a null id) come last
237                     if (left.getId() == null && right.getId() != null) {
238                         return 1;
239                     } else if (right.getId() == null && left.getId() != null) {
240                         return -1;
241                     }
242                     return left.getId().compareTo(right.getId());
243                 }
244             };
245 
onGroupBlockStateChanged(NotificationChannelGroup group)246     protected void onGroupBlockStateChanged(NotificationChannelGroup group) {
247         if (group == null) {
248             return;
249         }
250         PreferenceGroup groupGroup = (
251                 PreferenceGroup) getPreferenceScreen().findPreference(group.getId());
252 
253         if (groupGroup != null) {
254             if (group.isBlocked()) {
255                 List<Preference> toRemove = new ArrayList<>();
256                 int childCount = groupGroup.getPreferenceCount();
257                 for (int i = 0; i < childCount; i++) {
258                     Preference pref = groupGroup.getPreference(i);
259                     if (pref instanceof MasterSwitchPreference) {
260                         toRemove.add(pref);
261                     }
262                 }
263                 for (Preference pref : toRemove) {
264                     groupGroup.removePreference(pref);
265                 }
266             } else {
267                 final List<NotificationChannel> channels = group.getChannels();
268                 Collections.sort(channels, mChannelComparator);
269                 int N = channels.size();
270                 for (int i = 0; i < N; i++) {
271                     final NotificationChannel channel = channels.get(i);
272                     populateSingleChannelPrefs(groupGroup, channel, group.isBlocked());
273                 }
274             }
275         }
276     }
277 
278 }
279