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 }