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