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