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