1 /*
2  * Copyright (C) 2016 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.internal.telephony;
18 
19 import android.app.PendingIntent;
20 import android.app.Notification;
21 import android.app.NotificationManager;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.os.Handler;
27 import android.os.Message;
28 import android.os.PersistableBundle;
29 import android.provider.Settings;
30 import android.telephony.CarrierConfigManager;
31 import android.telephony.Rlog;
32 
33 import com.android.internal.telephony.util.NotificationChannelController;
34 
35 /**
36  * This contains Carrier specific logic based on the states/events
37  * managed in ServiceStateTracker.
38  * {@hide}
39  */
40 public class CarrierServiceStateTracker extends Handler {
41     private static final String LOG_TAG = "CSST";
42     protected static final int CARRIER_EVENT_BASE = 100;
43     protected static final int CARRIER_EVENT_VOICE_REGISTRATION = CARRIER_EVENT_BASE + 1;
44     protected static final int CARRIER_EVENT_VOICE_DEREGISTRATION = CARRIER_EVENT_BASE + 2;
45     protected static final int CARRIER_EVENT_DATA_REGISTRATION = CARRIER_EVENT_BASE + 3;
46     protected static final int CARRIER_EVENT_DATA_DEREGISTRATION = CARRIER_EVENT_BASE + 4;
47     private static final int SHOW_NOTIFICATION = 200;
48     private static final int NOTIFICATION_ID = 1000;
49     private static final int UNINITIALIZED_DELAY_VALUE = -1;
50     private int mDelay = UNINITIALIZED_DELAY_VALUE;
51     private Phone mPhone;
52     private boolean mIsPhoneRegistered = false;
53     private ServiceStateTracker mSST;
54 
CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst)55     public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst) {
56         this.mPhone = phone;
57         this.mSST = sst;
58         phone.getContext().registerReceiver(mBroadcastReceiver, new IntentFilter(
59                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
60     }
61 
62     @Override
handleMessage(Message msg)63     public void handleMessage(Message msg) {
64         switch (msg.what) {
65             case CARRIER_EVENT_VOICE_REGISTRATION:
66             case CARRIER_EVENT_DATA_REGISTRATION:
67                 mIsPhoneRegistered = true;
68                 handleConfigChanges();
69                 break;
70             case CARRIER_EVENT_VOICE_DEREGISTRATION:
71             case CARRIER_EVENT_DATA_DEREGISTRATION:
72                 if (isGlobalModeOrRadioOffOrAirplaneMode()) {
73                     break;
74                 }
75                 mIsPhoneRegistered = false;
76                 handleConfigChanges();
77                 break;
78             case SHOW_NOTIFICATION:
79                 sendNotification();
80                 break;
81         }
82     }
83 
84     /**
85      * Returns true if the preferred network is set to 'Global' or the radio is off or in
86      * Airplane Mode else returns false.
87      */
isGlobalModeOrRadioOffOrAirplaneMode()88     private boolean isGlobalModeOrRadioOffOrAirplaneMode() {
89         Context context = mPhone.getContext();
90         int preferredNetworkSetting = -1;
91         int airplaneMode = -1;
92         int subId = mPhone.getSubId();
93         try {
94             preferredNetworkSetting =
95                     android.provider.Settings.Global.getInt(context.getContentResolver(),
96                             android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId,
97                             Phone.PREFERRED_NT_MODE);
98             airplaneMode = Settings.Global.getInt(context.getContentResolver(),
99                     Settings.Global.AIRPLANE_MODE_ON, 0);
100         } catch (Exception e) {
101             Rlog.e(LOG_TAG, "Unable to get PREFERRED_NETWORK_MODE.");
102             return true;
103         }
104         return ((preferredNetworkSetting == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA) ||
105                 !mSST.isRadioOn() || (airplaneMode != 0));
106     }
107 
108     /**
109      * Contains logic to decide when to create/cancel notifications.
110      */
handleConfigChanges()111     private void handleConfigChanges() {
112 
113         if (mDelay == UNINITIALIZED_DELAY_VALUE) {
114             cancelNotification();
115             return;
116         }
117         // send a notification if the device is registerd to a network.
118         if (mIsPhoneRegistered) {
119             cancelNotification();
120             Rlog.i(LOG_TAG, "canceling all notifications. ");
121         } else {
122             Message notificationMsg;
123             notificationMsg = obtainMessage(SHOW_NOTIFICATION, null);
124             Rlog.i(LOG_TAG, "starting timer for notifications. ");
125             sendMessageDelayed(notificationMsg, mDelay);
126         }
127     }
128 
129     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
130         @Override
131         public void onReceive(Context context, Intent intent) {
132             CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
133                     context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
134             PersistableBundle b = carrierConfigManager.getConfig();
135             mDelay = b.getInt(CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT);
136             Rlog.i(LOG_TAG, "reading time to delay notification: " + mDelay);
137             handleConfigChanges();
138         }
139     };
140 
141     /**
142      * Post a notification to the NotificationManager for changing network type.
143      */
sendNotification()144     private void sendNotification() {
145         Context context = mPhone.getContext();
146 
147         Rlog.i(LOG_TAG, "w/values: " + "," + mIsPhoneRegistered + "," + mDelay
148                 + "," + isGlobalModeOrRadioOffOrAirplaneMode() + "," + mSST.isRadioOn());
149 
150         // exit if the network preference is set to Global or if the phone is registered.
151         if (isGlobalModeOrRadioOffOrAirplaneMode() || mIsPhoneRegistered) {
152             return;
153         }
154 
155         NotificationManager notificationManager = (NotificationManager)
156                 context.getSystemService(Context.NOTIFICATION_SERVICE);
157 
158 
159         Intent notificationIntent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);
160         PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, notificationIntent,
161                 PendingIntent.FLAG_ONE_SHOT);
162 
163         CharSequence title =
164                 context.getText(com.android.internal.R.string.NetworkPreferenceSwitchTitle);
165         CharSequence details =
166                 context.getText(com.android.internal.R.string.NetworkPreferenceSwitchSummary);
167 
168 
169         Notification mNotification = new Notification.Builder(context)
170                 .setWhen(System.currentTimeMillis())
171                 .setAutoCancel(true)
172                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
173                 .setContentTitle(title)
174                 .setColor(context.getResources().getColor(
175                         com.android.internal.R.color.system_notification_accent_color))
176                 .setStyle(new Notification.BigTextStyle().bigText(details))
177                 .setContentText(details)
178                 .setContentIntent(settingsIntent)
179                 .setChannel(NotificationChannelController.CHANNEL_ID_ALERT)
180                 .build();
181 
182         notificationManager.notify(NOTIFICATION_ID, mNotification);
183     }
184 
185     /**
186      * Cancel notifications if a registration is pending or has been sent.
187      */
cancelNotification()188     private void cancelNotification() {
189         Context context = mPhone.getContext();
190         mIsPhoneRegistered = true;
191         NotificationManager notificationManager = (NotificationManager)
192                 context.getSystemService(Context.NOTIFICATION_SERVICE);
193         notificationManager.cancel(NOTIFICATION_ID);
194     }
195 }