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 package com.android.internal.telephony.util;
17 
18 import android.annotation.NonNull;
19 import android.app.NotificationChannel;
20 import android.app.NotificationManager;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.media.AudioAttributes;
26 import android.net.Uri;
27 import android.provider.Settings;
28 import android.telephony.SubscriptionManager;
29 
30 import com.android.internal.R;
31 
32 import java.util.Arrays;
33 
34 
35 public class NotificationChannelController {
36 
37     /**
38      * list of {@link android.app.NotificationChannel} for telephony service.
39      */
40     public static final String CHANNEL_ID_ALERT = "alert";
41     public static final String CHANNEL_ID_CALL_FORWARD = "callForwardNew";
42     public static final String CHANNEL_ID_MOBILE_DATA_STATUS = "mobileDataAlertNew";
43     public static final String CHANNEL_ID_SIM = "sim";
44     public static final String CHANNEL_ID_SMS = "sms";
45     public static final String CHANNEL_ID_VOICE_MAIL = "voiceMail";
46     public static final String CHANNEL_ID_WFC = "wfc";
47 
48     /** deprecated channel, replaced with @see #CHANNEL_ID_MOBILE_DATA_STATUS */
49     private static final String CHANNEL_ID_MOBILE_DATA_ALERT_DEPRECATED = "mobileDataAlert";
50     /**
51      * deprecated channel, replaced with @see #CHANNEL_ID_CALL_FORWARD
52      * change the importance to default to make sure notification icon shown in the status bar.
53      */
54     private static final String CHANNEL_ID_CALL_FORWARD_DEPRECATED = "callForward";
55 
56     /**
57      * Creates all notification channels and registers with NotificationManager. If a channel
58      * with the same ID is already registered, NotificationManager will ignore this call.
59      */
createAll(Context context)60     private static void createAll(Context context) {
61         final NotificationChannel alertChannel = new NotificationChannel(
62                 CHANNEL_ID_ALERT,
63                 context.getText(R.string.notification_channel_network_alert),
64                 NotificationManager.IMPORTANCE_DEFAULT);
65         alertChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
66                 new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
67         // allow users to block notifications from system
68         alertChannel.setBlockableSystem(true);
69 
70         final NotificationChannel mobileDataStatusChannel = new NotificationChannel(
71                 CHANNEL_ID_MOBILE_DATA_STATUS,
72                 context.getText(R.string.notification_channel_mobile_data_status),
73                 NotificationManager.IMPORTANCE_LOW);
74         // allow users to block notifications from system
75         mobileDataStatusChannel.setBlockableSystem(true);
76 
77         final NotificationChannel simChannel = new NotificationChannel(
78                 CHANNEL_ID_SIM,
79                 context.getText(R.string.notification_channel_sim),
80                 NotificationManager.IMPORTANCE_LOW
81         );
82         simChannel.setSound(null, null);
83 
84         final NotificationChannel callforwardChannel = new NotificationChannel(
85                 CHANNEL_ID_CALL_FORWARD,
86                 context.getText(R.string.notification_channel_call_forward),
87                 NotificationManager.IMPORTANCE_DEFAULT);
88         migrateCallFowardNotificationChannel(context, callforwardChannel);
89 
90         context.getSystemService(NotificationManager.class)
91                 .createNotificationChannels(Arrays.asList(
92                 new NotificationChannel(CHANNEL_ID_SMS,
93                         context.getText(R.string.notification_channel_sms),
94                         NotificationManager.IMPORTANCE_HIGH),
95                 new NotificationChannel(CHANNEL_ID_WFC,
96                         context.getText(R.string.notification_channel_wfc),
97                         NotificationManager.IMPORTANCE_LOW),
98                 alertChannel, mobileDataStatusChannel,
99                 simChannel, callforwardChannel));
100 
101         // only for update
102         if (getChannel(CHANNEL_ID_VOICE_MAIL, context) != null) {
103             migrateVoicemailNotificationSettings(context);
104         }
105 
106         // after channel has been created there is no way to change the channel setting
107         // programmatically. delete the old channel and create a new one with a new ID.
108         if (getChannel(CHANNEL_ID_MOBILE_DATA_ALERT_DEPRECATED, context) != null) {
109             context.getSystemService(NotificationManager.class)
110                     .deleteNotificationChannel(CHANNEL_ID_MOBILE_DATA_ALERT_DEPRECATED);
111         }
112         if (getChannel(CHANNEL_ID_CALL_FORWARD_DEPRECATED, context) != null) {
113             context.getSystemService(NotificationManager.class)
114                     .deleteNotificationChannel(CHANNEL_ID_CALL_FORWARD_DEPRECATED);
115         }
116     }
117 
NotificationChannelController(Context context)118     public NotificationChannelController(Context context) {
119         IntentFilter intentFilter = new IntentFilter();
120         intentFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
121         intentFilter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
122         context.registerReceiver(mBroadcastReceiver, intentFilter);
123         createAll(context);
124     }
125 
getChannel(String channelId, Context context)126     public static NotificationChannel getChannel(String channelId, Context context) {
127         return context.getSystemService(NotificationManager.class)
128                 .getNotificationChannel(channelId);
129     }
130 
131     /**
132      * migrate deprecated voicemail notification settings to initial notification channel settings
133      * {@link VoicemailNotificationSettingsUtil#getRingTonePreference(Context)}}
134      * {@link VoicemailNotificationSettingsUtil#getVibrationPreference(Context)}
135      * notification settings are based on subId, only migrate if sub id matches.
136      * otherwise fallback to predefined voicemail channel settings.
137      * @param context
138      */
migrateVoicemailNotificationSettings(Context context)139     private static void migrateVoicemailNotificationSettings(Context context) {
140         final NotificationChannel voiceMailChannel = new NotificationChannel(
141                 CHANNEL_ID_VOICE_MAIL,
142                 context.getText(R.string.notification_channel_voice_mail),
143                 NotificationManager.IMPORTANCE_DEFAULT);
144         voiceMailChannel.enableVibration(
145                 VoicemailNotificationSettingsUtil.getVibrationPreference(context));
146         Uri sound = VoicemailNotificationSettingsUtil.getRingTonePreference(context);
147         voiceMailChannel.setSound(
148                 (sound == null) ? Settings.System.DEFAULT_NOTIFICATION_URI : sound,
149                 new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
150         context.getSystemService(NotificationManager.class)
151                 .createNotificationChannel(voiceMailChannel);
152     }
153 
154     /**
155      * migrate deprecated call forward notification channel.
156      * @param context
157      */
migrateCallFowardNotificationChannel( Context context, @NonNull NotificationChannel callforwardChannel)158     private static void migrateCallFowardNotificationChannel(
159             Context context, @NonNull NotificationChannel callforwardChannel) {
160         final NotificationChannel deprecatedChannel =
161                 getChannel(CHANNEL_ID_CALL_FORWARD_DEPRECATED, context);
162         if (deprecatedChannel != null) {
163             callforwardChannel.setSound(deprecatedChannel.getSound(),
164                     deprecatedChannel.getAudioAttributes());
165             callforwardChannel.setVibrationPattern(deprecatedChannel.getVibrationPattern());
166             callforwardChannel.enableVibration(deprecatedChannel.shouldVibrate());
167         }
168     }
169 
170     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
171         @Override
172         public void onReceive(Context context, Intent intent) {
173             if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
174                 // rename all notification channels on locale change
175                 createAll(context);
176             } else if (Intent.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
177                 // migrate voicemail notification settings on sim load
178                 if (SubscriptionManager.INVALID_SUBSCRIPTION_ID !=
179                         SubscriptionManager.getDefaultSubscriptionId()) {
180                     migrateVoicemailNotificationSettings(context);
181                 }
182             }
183         }
184     };
185 }
186