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