• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.app;
18 
19 import static android.app.NotificationManager.IMPORTANCE_NONE;
20 import static android.os.UserHandle.USER_SYSTEM;
21 
22 import android.annotation.Nullable;
23 import android.app.NotificationChannel;
24 import android.app.NotificationChannelGroup;
25 import android.app.NotificationManager;
26 import android.content.Context;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ShortcutInfo;
30 import android.graphics.drawable.Drawable;
31 import android.os.UserManager;
32 import android.provider.Settings;
33 import android.util.Log;
34 
35 import androidx.preference.Preference;
36 
37 import com.android.settings.notification.NotificationBackend;
38 import com.android.settingslib.RestrictedLockUtils;
39 import com.android.settingslib.core.AbstractPreferenceController;
40 
41 import java.util.Comparator;
42 import java.util.List;
43 import java.util.Objects;
44 
45 /**
46  * Parent class for preferences appearing on notification setting pages at the app,
47  * notification channel group, or notification channel level.
48  */
49 public abstract class NotificationPreferenceController extends AbstractPreferenceController {
50     private static final String TAG = "ChannelPrefContr";
51     @Nullable
52     protected NotificationChannel mChannel;
53     @Nullable
54     protected NotificationChannelGroup mChannelGroup;
55     protected RestrictedLockUtils.EnforcedAdmin mAdmin;
56     protected NotificationBackend.AppRow mAppRow;
57     protected final NotificationManager mNm;
58     protected final NotificationBackend mBackend;
59     protected final Context mContext;
60     protected final UserManager mUm;
61     protected final PackageManager mPm;
62     protected Preference mPreference;
63     @Nullable
64     protected Drawable mConversationDrawable;
65     @Nullable
66     protected ShortcutInfo mConversationInfo;
67     protected List<String> mPreferenceFilter;
68 
69     boolean overrideCanBlock;
70     boolean overrideCanConfigure;
71     boolean overrideCanBlockValue;
72     boolean overrideCanConfigureValue;
73 
NotificationPreferenceController(Context context, NotificationBackend backend)74     public NotificationPreferenceController(Context context, NotificationBackend backend) {
75         super(context);
76         mContext = context;
77         mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
78         mBackend = backend;
79         mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
80         mPm = mContext.getPackageManager();
81     }
82 
83     /**
84      * Returns true if field's parent object is not blocked.
85      */
86     @Override
isAvailable()87     public boolean isAvailable() {
88         if (mAppRow == null) {
89             return false;
90         }
91         if (mAppRow.banned) {
92             return false;
93         }
94         if (mChannelGroup != null) {
95             if (mChannelGroup.isBlocked()) {
96                 return false;
97             }
98         }
99         if (mChannel != null) {
100             if (mPreferenceFilter != null && !isIncludedInFilter()) {
101                 return false;
102             }
103             return mChannel.getImportance() != IMPORTANCE_NONE;
104         }
105         return true;
106     }
107 
onResume(NotificationBackend.AppRow appRow, @Nullable NotificationChannel channel, @Nullable NotificationChannelGroup group, Drawable conversationDrawable, ShortcutInfo conversationInfo, RestrictedLockUtils.EnforcedAdmin admin, List<String> preferenceFilter)108     protected void onResume(NotificationBackend.AppRow appRow,
109             @Nullable NotificationChannel channel, @Nullable NotificationChannelGroup group,
110             Drawable conversationDrawable,
111             ShortcutInfo conversationInfo,
112             RestrictedLockUtils.EnforcedAdmin admin,
113             List<String> preferenceFilter) {
114         mAppRow = appRow;
115         mChannel = channel;
116         mChannelGroup = group;
117         mAdmin = admin;
118         mConversationDrawable = conversationDrawable;
119         mConversationInfo = conversationInfo;
120         mPreferenceFilter = preferenceFilter;
121     }
122 
isIncludedInFilter()123     abstract boolean isIncludedInFilter();
124 
checkCanBeVisible(int minImportanceVisible)125     protected boolean checkCanBeVisible(int minImportanceVisible) {
126         if (mChannel == null) {
127             Log.w(TAG, "No channel");
128             return false;
129         }
130 
131         int importance = mChannel.getImportance();
132         if (importance == NotificationManager.IMPORTANCE_UNSPECIFIED) {
133             return true;
134         }
135         return importance >= minImportanceVisible;
136     }
137 
saveChannel()138     protected void saveChannel() {
139         if (mChannel != null && mAppRow != null) {
140             mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, mChannel);
141         }
142     }
143 
isChannelBlockable()144     protected boolean isChannelBlockable() {
145         return isChannelBlockable(mChannel);
146     }
147 
isChannelBlockable(NotificationChannel channel)148     protected boolean isChannelBlockable(NotificationChannel channel) {
149         if (overrideCanBlock) {
150             return overrideCanBlockValue;
151         }
152         if (overrideCanConfigure) {
153             return overrideCanConfigureValue;
154         }
155         if (channel != null && mAppRow != null) {
156             boolean locked = mAppRow.lockedImportance;
157             if (locked) {
158                 return channel.isBlockable() || channel.getImportance() == IMPORTANCE_NONE;
159             }
160 
161             return channel.isBlockable() || !mAppRow.systemApp
162                     || channel.getImportance() == IMPORTANCE_NONE;
163         }
164         return false;
165     }
166 
isAppBlockable()167     protected boolean isAppBlockable() {
168         if (overrideCanBlock) {
169             return overrideCanBlockValue;
170         }
171         if (overrideCanConfigure) {
172             return overrideCanConfigureValue;
173         }
174         if (mAppRow != null) {
175             boolean systemBlockable = !mAppRow.systemApp || (mAppRow.systemApp && mAppRow.banned);
176             return systemBlockable && !mAppRow.lockedImportance;
177         }
178         return true;
179     }
180 
isChannelConfigurable(NotificationChannel channel)181     protected boolean isChannelConfigurable(NotificationChannel channel) {
182         if (overrideCanConfigure) {
183             return overrideCanConfigureValue;
184         }
185         if (channel != null && mAppRow != null) {
186             boolean locked = mAppRow.lockedImportance;
187             return !locked || channel.isBlockable();
188         }
189         return false;
190     }
191 
isChannelGroupBlockable()192     protected boolean isChannelGroupBlockable() {
193         return isChannelGroupBlockable(mChannelGroup);
194     }
195 
isChannelGroupBlockable(NotificationChannelGroup group)196     protected boolean isChannelGroupBlockable(NotificationChannelGroup group) {
197         if (overrideCanBlock) {
198             return overrideCanBlockValue;
199         }
200         if (overrideCanConfigure) {
201             return overrideCanConfigureValue;
202         }
203         if (group != null && mAppRow != null) {
204             if (!mAppRow.systemApp && !mAppRow.lockedImportance) {
205                 return true;
206             }
207 
208             return group.isBlocked();
209         }
210         return false;
211     }
212 
hasValidGroup()213     protected boolean hasValidGroup() {
214         return mChannelGroup != null;
215     }
216 
isDefaultChannel()217     protected final boolean isDefaultChannel() {
218         if (mChannel == null) {
219             return false;
220         }
221         return Objects.equals(NotificationChannel.DEFAULT_CHANNEL_ID, mChannel.getId());
222     }
223 
setOverrideCanBlock(boolean canBlock)224     protected final void setOverrideCanBlock(boolean canBlock) {
225         overrideCanBlock = true;
226         overrideCanBlockValue = canBlock;
227     }
228 
setOverrideCanConfigure(boolean canConfigure)229     protected final void setOverrideCanConfigure(boolean canConfigure) {
230         overrideCanConfigure = true;
231         overrideCanConfigureValue = canConfigure;
232     }
233 
234     public static final Comparator<NotificationChannelGroup> CHANNEL_GROUP_COMPARATOR =
235             new Comparator<NotificationChannelGroup>() {
236         @Override
237         public int compare(NotificationChannelGroup left, NotificationChannelGroup right) {
238             // Non-grouped channels (in placeholder group with a null id) come last
239             if (left.getId() == null && right.getId() != null) {
240                 return 1;
241             } else if (right.getId() == null && left.getId() != null) {
242                 return -1;
243             }
244             return left.getId().compareTo(right.getId());
245         }
246     };
247 
248     public static final Comparator<NotificationChannel> CHANNEL_COMPARATOR = (left, right) -> {
249         if (left.isDeleted() != right.isDeleted()) {
250             return Boolean.compare(left.isDeleted(), right.isDeleted());
251         } else if (left.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
252             // Uncategorized/miscellaneous legacy channel goes last
253             return 1;
254         } else if (right.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
255             return -1;
256         }
257 
258         return left.getId().compareTo(right.getId());
259     };
260 }
261