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 package com.android.internal.telephony; 17 18 import android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.IntentFilter; 22 import android.database.ContentObserver; 23 import android.os.AsyncResult; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.os.Registrant; 27 import android.os.RegistrantList; 28 import android.provider.Settings; 29 import android.provider.Telephony; 30 import android.telephony.Rlog; 31 import android.telephony.TelephonyManager; 32 import android.util.LocalLog; 33 import android.util.Log; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.util.IndentingPrintWriter; 37 38 import java.io.FileDescriptor; 39 import java.io.PrintWriter; 40 41 /** 42 * Carrier Action Agent(CAA) paired with 43 * {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent}, 44 * serves as an agent to dispatch carrier actions from carrier apps to different telephony modules, 45 * {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean) 46 * carrierActionSetRadioEnabled} for example. 47 * 48 * CAA supports dynamic registration where different telephony modules could listen for a specific 49 * carrier action event and implement their own handler. CCA will dispatch the event to all 50 * interested parties and maintain the received action states internally for future inspection. 51 * Each CarrierActionAgent is associated with a phone object. 52 */ 53 public class CarrierActionAgent extends Handler { 54 private static final String LOG_TAG = "CarrierActionAgent"; 55 private static final boolean DBG = true; 56 private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); 57 58 /** A list of carrier actions */ 59 public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED = 0; 60 public static final int CARRIER_ACTION_SET_RADIO_ENABLED = 1; 61 public static final int CARRIER_ACTION_RESET = 2; 62 public static final int CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS = 3; 63 public static final int EVENT_APM_SETTINGS_CHANGED = 4; 64 public static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 5; 65 public static final int EVENT_DATA_ROAMING_OFF = 6; 66 public static final int EVENT_SIM_STATE_CHANGED = 7; 67 public static final int EVENT_APN_SETTINGS_CHANGED = 8; 68 69 /** Member variables */ 70 private final Phone mPhone; 71 /** registrant list per carrier action */ 72 private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList(); 73 private RegistrantList mRadioEnableRegistrants = new RegistrantList(); 74 private RegistrantList mDefaultNetworkReportRegistrants = new RegistrantList(); 75 /** local log for carrier actions */ 76 private LocalLog mMeteredApnEnabledLog = new LocalLog(10); 77 private LocalLog mRadioEnabledLog = new LocalLog(10); 78 private LocalLog mReportDefaultNetworkStatusLog = new LocalLog(10); 79 /** carrier actions */ 80 private Boolean mCarrierActionOnMeteredApnEnabled = true; 81 private Boolean mCarrierActionOnRadioEnabled = true; 82 private Boolean mCarrierActionReportDefaultNetworkStatus = false; 83 /** content observer for APM change */ 84 private final SettingsObserver mSettingsObserver; 85 86 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 87 @Override 88 public void onReceive(Context context, Intent intent) { 89 final String action = intent.getAction(); 90 final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 91 if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ 92 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) { 93 // ignore rebroadcast since carrier apps are direct boot aware. 94 return; 95 } 96 sendMessage(obtainMessage(EVENT_SIM_STATE_CHANGED, iccState)); 97 } 98 } 99 }; 100 101 /** Constructor */ CarrierActionAgent(Phone phone)102 public CarrierActionAgent(Phone phone) { 103 mPhone = phone; 104 mPhone.getContext().registerReceiver(mReceiver, 105 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); 106 mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); 107 if (DBG) log("Creating CarrierActionAgent"); 108 } 109 110 @Override handleMessage(Message msg)111 public void handleMessage(Message msg) { 112 // skip notification if the input carrier action is same as the current one. 113 Boolean enabled = getCarrierActionEnabled(msg.what); 114 if (enabled != null && enabled == (boolean) msg.obj) return; 115 switch (msg.what) { 116 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 117 mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj; 118 log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled); 119 mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: " 120 + mCarrierActionOnMeteredApnEnabled); 121 mMeteredApnEnableRegistrants.notifyRegistrants( 122 new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null)); 123 break; 124 case CARRIER_ACTION_SET_RADIO_ENABLED: 125 mCarrierActionOnRadioEnabled = (boolean) msg.obj; 126 log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 127 mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 128 mRadioEnableRegistrants.notifyRegistrants( 129 new AsyncResult(null, mCarrierActionOnRadioEnabled, null)); 130 break; 131 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 132 mCarrierActionReportDefaultNetworkStatus = (boolean) msg.obj; 133 log("CARRIER_ACTION_REPORT_AT_DEFAULT_NETWORK_STATUS: " 134 + mCarrierActionReportDefaultNetworkStatus); 135 mReportDefaultNetworkStatusLog.log("REGISTER_DEFAULT_NETWORK_STATUS: " 136 + mCarrierActionReportDefaultNetworkStatus); 137 mDefaultNetworkReportRegistrants.notifyRegistrants( 138 new AsyncResult(null, mCarrierActionReportDefaultNetworkStatus, null)); 139 break; 140 case CARRIER_ACTION_RESET: 141 log("CARRIER_ACTION_RESET"); 142 carrierActionReset(); 143 break; 144 case EVENT_APM_SETTINGS_CHANGED: 145 log("EVENT_APM_SETTINGS_CHANGED"); 146 if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(), 147 Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) { 148 carrierActionReset(); 149 } 150 break; 151 case EVENT_MOBILE_DATA_SETTINGS_CHANGED: 152 log("EVENT_MOBILE_DATA_SETTINGS_CHANGED"); 153 if (!mPhone.isUserDataEnabled()) carrierActionReset(); 154 break; 155 case EVENT_DATA_ROAMING_OFF: 156 log("EVENT_DATA_ROAMING_OFF"); 157 // reset carrier actions when exit roaming state. 158 carrierActionReset(); 159 break; 160 case EVENT_SIM_STATE_CHANGED: 161 String iccState = (String) msg.obj; 162 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) { 163 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 164 carrierActionReset(); 165 String mobileData = Settings.Global.MOBILE_DATA; 166 if (TelephonyManager.getDefault().getSimCount() != 1) { 167 mobileData = mobileData + mPhone.getSubId(); 168 } 169 mSettingsObserver.observe(Settings.Global.getUriFor(mobileData), 170 EVENT_MOBILE_DATA_SETTINGS_CHANGED); 171 mSettingsObserver.observe( 172 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), 173 EVENT_APM_SETTINGS_CHANGED); 174 mSettingsObserver.observe( 175 Telephony.Carriers.CONTENT_URI, EVENT_APN_SETTINGS_CHANGED); 176 if (mPhone.getServiceStateTracker() != null) { 177 mPhone.getServiceStateTracker().registerForDataRoamingOff( 178 this, EVENT_DATA_ROAMING_OFF, null, false); 179 } 180 } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) { 181 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 182 carrierActionReset(); 183 mSettingsObserver.unobserve(); 184 if (mPhone.getServiceStateTracker() != null) { 185 mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); 186 } 187 } 188 break; 189 case EVENT_APN_SETTINGS_CHANGED: 190 log("EVENT_APN_SETTINGS_CHANGED"); 191 // Reset carrier actions when APN change. 192 carrierActionReset(); 193 break; 194 default: 195 loge("Unknown carrier action: " + msg.what); 196 } 197 } 198 199 /** 200 * Action set from carrier app to enable/disable radio 201 */ carrierActionSetRadioEnabled(boolean enabled)202 public void carrierActionSetRadioEnabled(boolean enabled) { 203 sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled)); 204 } 205 206 /** 207 * Action set from carrier app to enable/disable metered APNs 208 */ carrierActionSetMeteredApnsEnabled(boolean enabled)209 public void carrierActionSetMeteredApnsEnabled(boolean enabled) { 210 sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled)); 211 } 212 213 /** 214 * Action set from carrier app to start/stop reporting default network status. 215 */ carrierActionReportDefaultNetworkStatus(boolean report)216 public void carrierActionReportDefaultNetworkStatus(boolean report) { 217 sendMessage(obtainMessage(CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, report)); 218 } 219 carrierActionReset()220 private void carrierActionReset() { 221 carrierActionReportDefaultNetworkStatus(false); 222 carrierActionSetMeteredApnsEnabled(true); 223 carrierActionSetRadioEnabled(true); 224 // notify configured carrier apps for reset 225 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers( 226 new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET)); 227 } 228 getRegistrantsFromAction(int action)229 private RegistrantList getRegistrantsFromAction(int action) { 230 switch (action) { 231 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 232 return mMeteredApnEnableRegistrants; 233 case CARRIER_ACTION_SET_RADIO_ENABLED: 234 return mRadioEnableRegistrants; 235 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 236 return mDefaultNetworkReportRegistrants; 237 default: 238 loge("Unsupported action: " + action); 239 return null; 240 } 241 } 242 getCarrierActionEnabled(int action)243 private Boolean getCarrierActionEnabled(int action) { 244 switch (action) { 245 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 246 return mCarrierActionOnMeteredApnEnabled; 247 case CARRIER_ACTION_SET_RADIO_ENABLED: 248 return mCarrierActionOnRadioEnabled; 249 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 250 return mCarrierActionReportDefaultNetworkStatus; 251 default: 252 loge("Unsupported action: " + action); 253 return null; 254 } 255 } 256 257 /** 258 * Register with CAA for a specific event. 259 * @param action which carrier action registrant is interested in 260 * @param notifyNow if carrier action has once set, notify registrant right after 261 * registering, so that registrants will get the latest carrier action. 262 */ registerForCarrierAction(int action, Handler h, int what, Object obj, boolean notifyNow)263 public void registerForCarrierAction(int action, Handler h, int what, Object obj, 264 boolean notifyNow) { 265 Boolean carrierAction = getCarrierActionEnabled(action); 266 if (carrierAction == null) { 267 throw new IllegalArgumentException("invalid carrier action: " + action); 268 } 269 RegistrantList list = getRegistrantsFromAction(action); 270 Registrant r = new Registrant(h, what, obj); 271 list.add(r); 272 if (notifyNow) { 273 r.notifyRegistrant(new AsyncResult(null, carrierAction, null)); 274 } 275 } 276 277 /** 278 * Unregister with CAA for a specific event. Callers will no longer be notified upon such event. 279 * @param action which carrier action caller is no longer interested in 280 */ unregisterForCarrierAction(Handler h, int action)281 public void unregisterForCarrierAction(Handler h, int action) { 282 RegistrantList list = getRegistrantsFromAction(action); 283 if (list == null) { 284 throw new IllegalArgumentException("invalid carrier action: " + action); 285 } 286 list.remove(h); 287 } 288 289 @VisibleForTesting getContentObserver()290 public ContentObserver getContentObserver() { 291 return mSettingsObserver; 292 } 293 log(String s)294 private void log(String s) { 295 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 296 } 297 loge(String s)298 private void loge(String s) { 299 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 300 } 301 logv(String s)302 private void logv(String s) { 303 Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 304 } 305 dump(FileDescriptor fd, PrintWriter pw, String[] args)306 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 307 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 308 pw.println(" mCarrierActionOnMeteredApnsEnabled Log:"); 309 ipw.increaseIndent(); 310 mMeteredApnEnabledLog.dump(fd, ipw, args); 311 ipw.decreaseIndent(); 312 313 pw.println(" mCarrierActionOnRadioEnabled Log:"); 314 ipw.increaseIndent(); 315 mRadioEnabledLog.dump(fd, ipw, args); 316 ipw.decreaseIndent(); 317 318 pw.println(" mCarrierActionReportDefaultNetworkStatus Log:"); 319 ipw.increaseIndent(); 320 mReportDefaultNetworkStatusLog.dump(fd, ipw, args); 321 ipw.decreaseIndent(); 322 } 323 } 324