1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui.util; 16 17 import android.app.NotificationChannel; 18 import android.app.NotificationManager; 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.media.AudioAttributes; 22 import android.net.Uri; 23 import android.provider.Settings; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.systemui.R; 27 import com.android.systemui.SystemUI; 28 import com.android.wm.shell.pip.tv.TvPipNotificationController; 29 30 import java.util.Arrays; 31 32 public class NotificationChannels extends SystemUI { 33 public static String ALERTS = "ALR"; 34 public static String SCREENSHOTS_LEGACY = "SCN"; 35 public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP"; 36 public static String GENERAL = "GEN"; 37 public static String STORAGE = "DSK"; 38 public static String BATTERY = "BAT"; 39 public static String TVPIP = TvPipNotificationController.NOTIFICATION_CHANNEL; // "TVPIP" 40 public static String HINTS = "HNT"; 41 NotificationChannels(Context context)42 public NotificationChannels(Context context) { 43 super(context); 44 } 45 createAll(Context context)46 public static void createAll(Context context) { 47 final NotificationManager nm = context.getSystemService(NotificationManager.class); 48 final NotificationChannel batteryChannel = new NotificationChannel(BATTERY, 49 context.getString(R.string.notification_channel_battery), 50 NotificationManager.IMPORTANCE_MAX); 51 final String soundPath = Settings.Global.getString(context.getContentResolver(), 52 Settings.Global.LOW_BATTERY_SOUND); 53 batteryChannel.setSound(Uri.parse("file://" + soundPath), new AudioAttributes.Builder() 54 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 55 .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT) 56 .build()); 57 batteryChannel.setBlockable(true); 58 59 final NotificationChannel alerts = new NotificationChannel( 60 ALERTS, 61 context.getString(R.string.notification_channel_alerts), 62 NotificationManager.IMPORTANCE_HIGH); 63 64 final NotificationChannel general = new NotificationChannel( 65 GENERAL, 66 context.getString(R.string.notification_channel_general), 67 NotificationManager.IMPORTANCE_MIN); 68 69 final NotificationChannel storage = new NotificationChannel( 70 STORAGE, 71 context.getString(R.string.notification_channel_storage), 72 isTv(context) 73 ? NotificationManager.IMPORTANCE_DEFAULT 74 : NotificationManager.IMPORTANCE_LOW); 75 76 final NotificationChannel hint = new NotificationChannel( 77 HINTS, 78 context.getString(R.string.notification_channel_hints), 79 NotificationManager.IMPORTANCE_DEFAULT); 80 // No need to bypass DND. 81 82 nm.createNotificationChannels(Arrays.asList( 83 alerts, 84 general, 85 storage, 86 createScreenshotChannel( 87 context.getString(R.string.notification_channel_screenshot), 88 nm.getNotificationChannel(SCREENSHOTS_LEGACY)), 89 batteryChannel, 90 hint 91 )); 92 93 // Delete older SS channel if present. 94 // Screenshots promoted to heads-up in P, this cleans up the lower priority channel from O. 95 // This line can be deleted in Q. 96 nm.deleteNotificationChannel(SCREENSHOTS_LEGACY); 97 98 99 if (isTv(context)) { 100 // TV specific notification channel for TV PIP controls. 101 // Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest 102 // priority, so it can be shown in all times. 103 nm.createNotificationChannel(new NotificationChannel( 104 TVPIP, 105 context.getString(R.string.notification_channel_tv_pip), 106 NotificationManager.IMPORTANCE_MAX)); 107 } 108 } 109 110 /** 111 * Set up screenshot channel, respecting any previously committed user settings on legacy 112 * channel. 113 * @return 114 */ createScreenshotChannel( String name, NotificationChannel legacySS)115 @VisibleForTesting static NotificationChannel createScreenshotChannel( 116 String name, NotificationChannel legacySS) { 117 NotificationChannel screenshotChannel = new NotificationChannel(SCREENSHOTS_HEADSUP, 118 name, NotificationManager.IMPORTANCE_HIGH); // pop on screen 119 120 screenshotChannel.setSound(null, // silent 121 new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build()); 122 screenshotChannel.setBlockable(true); 123 124 if (legacySS != null) { 125 // Respect any user modified fields from the old channel. 126 int userlock = legacySS.getUserLockedFields(); 127 if ((userlock & NotificationChannel.USER_LOCKED_IMPORTANCE) != 0) { 128 screenshotChannel.setImportance(legacySS.getImportance()); 129 } 130 if ((userlock & NotificationChannel.USER_LOCKED_SOUND) != 0) { 131 screenshotChannel.setSound(legacySS.getSound(), legacySS.getAudioAttributes()); 132 } 133 if ((userlock & NotificationChannel.USER_LOCKED_VIBRATION) != 0) { 134 screenshotChannel.setVibrationPattern(legacySS.getVibrationPattern()); 135 } 136 if ((userlock & NotificationChannel.USER_LOCKED_LIGHTS) != 0) { 137 screenshotChannel.setLightColor(legacySS.getLightColor()); 138 } 139 // skip show_badge, irrelevant for system channel 140 } 141 142 return screenshotChannel; 143 } 144 145 @Override start()146 public void start() { 147 createAll(mContext); 148 } 149 isTv(Context context)150 private static boolean isTv(Context context) { 151 PackageManager packageManager = context.getPackageManager(); 152 return packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK); 153 } 154 } 155