1 /* 2 * Copyright (C) 2018 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.Application; 20 import android.app.NotificationChannel; 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.os.Bundle; 24 import android.provider.Settings; 25 26 import androidx.annotation.VisibleForTesting; 27 import androidx.core.text.BidiFormatter; 28 import androidx.fragment.app.Fragment; 29 import androidx.preference.Preference; 30 import androidx.preference.PreferenceScreen; 31 32 import com.android.settings.R; 33 import com.android.settings.applications.AppInfoBase; 34 import com.android.settings.core.PreferenceControllerMixin; 35 import com.android.settings.core.SubSettingLauncher; 36 import com.android.settingslib.applications.ApplicationsState; 37 import com.android.settingslib.core.AbstractPreferenceController; 38 import com.android.settingslib.widget.apppreference.AppPreference; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 43 /** 44 * Adds a preference to the PreferenceScreen for each notification channel that can bypass DND. 45 */ 46 public class ZenModeAllBypassingAppsPreferenceController extends AbstractPreferenceController 47 implements PreferenceControllerMixin { 48 49 private final String KEY = "zen_mode_bypassing_apps_category"; 50 51 @VisibleForTesting ApplicationsState mApplicationsState; 52 @VisibleForTesting PreferenceScreen mPreferenceScreen; 53 @VisibleForTesting Context mPrefContext; 54 55 private ApplicationsState.Session mAppSession; 56 private NotificationBackend mNotificationBackend = new NotificationBackend(); 57 private Fragment mHostFragment; 58 ZenModeAllBypassingAppsPreferenceController(Context context, Application app, Fragment host)59 public ZenModeAllBypassingAppsPreferenceController(Context context, Application app, 60 Fragment host) { 61 62 this(context, app == null ? null : ApplicationsState.getInstance(app), host); 63 } 64 ZenModeAllBypassingAppsPreferenceController(Context context, ApplicationsState appState, Fragment host)65 private ZenModeAllBypassingAppsPreferenceController(Context context, ApplicationsState appState, 66 Fragment host) { 67 super(context); 68 mApplicationsState = appState; 69 mHostFragment = host; 70 71 if (mApplicationsState != null && host != null) { 72 mAppSession = mApplicationsState.newSession(mAppSessionCallbacks, host.getLifecycle()); 73 } 74 } 75 76 @Override displayPreference(PreferenceScreen screen)77 public void displayPreference(PreferenceScreen screen) { 78 mPreferenceScreen = screen; 79 mPrefContext = mPreferenceScreen.getContext(); 80 updateNotificationChannelList(); 81 super.displayPreference(screen); 82 } 83 84 @Override isAvailable()85 public boolean isAvailable() { 86 return true; 87 } 88 89 @Override getPreferenceKey()90 public String getPreferenceKey() { 91 return KEY; 92 } 93 94 /** 95 * Call this method to trigger the notification channels list to refresh. 96 */ updateNotificationChannelList()97 public void updateNotificationChannelList() { 98 if (mAppSession == null) { 99 return; 100 } 101 102 ApplicationsState.AppFilter filter = ApplicationsState.FILTER_ALL_ENABLED; 103 List<ApplicationsState.AppEntry> apps = mAppSession.rebuild(filter, 104 ApplicationsState.ALPHA_COMPARATOR); 105 if (apps != null) { 106 updateNotificationChannelList(apps); 107 } 108 } 109 110 @VisibleForTesting updateNotificationChannelList(List<ApplicationsState.AppEntry> apps)111 void updateNotificationChannelList(List<ApplicationsState.AppEntry> apps) { 112 if (mPreferenceScreen == null || apps == null) { 113 return; 114 } 115 116 List<Preference> channelsBypassingDnd = new ArrayList<>(); 117 for (ApplicationsState.AppEntry entry : apps) { 118 String pkg = entry.info.packageName; 119 mApplicationsState.ensureIcon(entry); 120 for (NotificationChannel channel : mNotificationBackend 121 .getNotificationChannelsBypassingDnd(pkg, entry.info.uid).getList()) { 122 Preference pref = new AppPreference(mPrefContext); 123 pref.setKey(pkg + "|" + channel.getId()); 124 pref.setTitle(BidiFormatter.getInstance().unicodeWrap(entry.label)); 125 pref.setIcon(entry.icon); 126 pref.setSummary(BidiFormatter.getInstance().unicodeWrap(channel.getName())); 127 128 pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 129 @Override 130 public boolean onPreferenceClick(Preference preference) { 131 Bundle args = new Bundle(); 132 args.putString(AppInfoBase.ARG_PACKAGE_NAME, entry.info.packageName); 133 args.putInt(AppInfoBase.ARG_PACKAGE_UID, entry.info.uid); 134 args.putString(Settings.EXTRA_CHANNEL_ID, channel.getId()); 135 new SubSettingLauncher(mContext) 136 .setDestination(ChannelNotificationSettings.class.getName()) 137 .setArguments(args) 138 .setTitleRes(R.string.notification_channel_title) 139 .setResultListener(mHostFragment, 0) 140 .setSourceMetricsCategory( 141 SettingsEnums.NOTIFICATION_ZEN_MODE_OVERRIDING_APP) 142 .launch(); 143 return true; 144 } 145 }); 146 channelsBypassingDnd.add(pref); 147 } 148 149 mPreferenceScreen.removeAll(); 150 if (channelsBypassingDnd.size() > 0) { 151 for (Preference prefToAdd : channelsBypassingDnd) { 152 mPreferenceScreen.addPreference(prefToAdd); 153 } 154 } 155 } 156 } 157 158 private final ApplicationsState.Callbacks mAppSessionCallbacks = 159 new ApplicationsState.Callbacks() { 160 161 @Override 162 public void onRunningStateChanged(boolean running) { 163 updateNotificationChannelList(); 164 } 165 166 @Override 167 public void onPackageListChanged() { 168 updateNotificationChannelList(); 169 } 170 171 @Override 172 public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) { 173 updateNotificationChannelList(apps); 174 } 175 176 @Override 177 public void onPackageIconChanged() { 178 updateNotificationChannelList(); 179 } 180 181 @Override 182 public void onPackageSizeChanged(String packageName) { 183 updateNotificationChannelList(); 184 } 185 186 @Override 187 public void onAllSizesComputed() { } 188 189 @Override 190 public void onLauncherInfoChanged() { 191 updateNotificationChannelList(); 192 } 193 194 @Override 195 public void onLoadEntriesCompleted() { 196 updateNotificationChannelList(); 197 } 198 }; 199 } 200