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.TelephonyManager; 31 import android.util.LocalLog; 32 import android.util.Log; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.internal.util.IndentingPrintWriter; 36 import com.android.telephony.Rlog; 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(Intent.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 int otaspState = (mCarrierActionOnMeteredApnEnabled) 122 ? mPhone.getServiceStateTracker().getOtasp() 123 : TelephonyManager.OTASP_SIM_UNPROVISIONED; 124 mPhone.notifyOtaspChanged(otaspState); 125 mMeteredApnEnableRegistrants.notifyRegistrants( 126 new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null)); 127 break; 128 case CARRIER_ACTION_SET_RADIO_ENABLED: 129 mCarrierActionOnRadioEnabled = (boolean) msg.obj; 130 log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 131 mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 132 mRadioEnableRegistrants.notifyRegistrants( 133 new AsyncResult(null, mCarrierActionOnRadioEnabled, null)); 134 break; 135 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 136 mCarrierActionReportDefaultNetworkStatus = (boolean) msg.obj; 137 log("CARRIER_ACTION_REPORT_AT_DEFAULT_NETWORK_STATUS: " 138 + mCarrierActionReportDefaultNetworkStatus); 139 mReportDefaultNetworkStatusLog.log("REGISTER_DEFAULT_NETWORK_STATUS: " 140 + mCarrierActionReportDefaultNetworkStatus); 141 mDefaultNetworkReportRegistrants.notifyRegistrants( 142 new AsyncResult(null, mCarrierActionReportDefaultNetworkStatus, null)); 143 break; 144 case CARRIER_ACTION_RESET: 145 log("CARRIER_ACTION_RESET"); 146 carrierActionReset(); 147 break; 148 case EVENT_APM_SETTINGS_CHANGED: 149 log("EVENT_APM_SETTINGS_CHANGED"); 150 if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(), 151 Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) { 152 carrierActionReset(); 153 } 154 break; 155 case EVENT_MOBILE_DATA_SETTINGS_CHANGED: 156 log("EVENT_MOBILE_DATA_SETTINGS_CHANGED"); 157 if (!mPhone.isUserDataEnabled()) carrierActionReset(); 158 break; 159 case EVENT_DATA_ROAMING_OFF: 160 log("EVENT_DATA_ROAMING_OFF"); 161 // reset carrier actions when exit roaming state. 162 carrierActionReset(); 163 break; 164 case EVENT_SIM_STATE_CHANGED: 165 String iccState = (String) msg.obj; 166 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) { 167 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 168 carrierActionReset(); 169 String mobileData = Settings.Global.MOBILE_DATA; 170 if (TelephonyManager.getDefault().getSimCount() != 1) { 171 mobileData = mobileData + mPhone.getSubId(); 172 } 173 mSettingsObserver.observe(Settings.Global.getUriFor(mobileData), 174 EVENT_MOBILE_DATA_SETTINGS_CHANGED); 175 mSettingsObserver.observe( 176 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), 177 EVENT_APM_SETTINGS_CHANGED); 178 mSettingsObserver.observe( 179 Telephony.Carriers.CONTENT_URI, EVENT_APN_SETTINGS_CHANGED); 180 if (mPhone.getServiceStateTracker() != null) { 181 mPhone.getServiceStateTracker().registerForDataRoamingOff( 182 this, EVENT_DATA_ROAMING_OFF, null, false); 183 } 184 } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) { 185 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 186 carrierActionReset(); 187 mSettingsObserver.unobserve(); 188 if (mPhone.getServiceStateTracker() != null) { 189 mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); 190 } 191 } 192 break; 193 case EVENT_APN_SETTINGS_CHANGED: 194 log("EVENT_APN_SETTINGS_CHANGED"); 195 // Reset carrier actions when APN change. 196 carrierActionReset(); 197 break; 198 default: 199 loge("Unknown carrier action: " + msg.what); 200 } 201 } 202 203 /** 204 * Action set from carrier app to enable/disable radio 205 */ carrierActionSetRadioEnabled(boolean enabled)206 public void carrierActionSetRadioEnabled(boolean enabled) { 207 sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled)); 208 } 209 210 /** 211 * Action set from carrier app to enable/disable metered APNs 212 */ carrierActionSetMeteredApnsEnabled(boolean enabled)213 public void carrierActionSetMeteredApnsEnabled(boolean enabled) { 214 sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled)); 215 } 216 217 /** 218 * Action set from carrier app to start/stop reporting default network status. 219 */ carrierActionReportDefaultNetworkStatus(boolean report)220 public void carrierActionReportDefaultNetworkStatus(boolean report) { 221 sendMessage(obtainMessage(CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, report)); 222 } 223 carrierActionReset()224 public void carrierActionReset() { 225 carrierActionReportDefaultNetworkStatus(false); 226 carrierActionSetMeteredApnsEnabled(true); 227 carrierActionSetRadioEnabled(true); 228 // notify configured carrier apps for reset 229 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers( 230 new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_RESET)); 231 } 232 getRegistrantsFromAction(int action)233 private RegistrantList getRegistrantsFromAction(int action) { 234 switch (action) { 235 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 236 return mMeteredApnEnableRegistrants; 237 case CARRIER_ACTION_SET_RADIO_ENABLED: 238 return mRadioEnableRegistrants; 239 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 240 return mDefaultNetworkReportRegistrants; 241 default: 242 loge("Unsupported action: " + action); 243 return null; 244 } 245 } 246 getCarrierActionEnabled(int action)247 private Boolean getCarrierActionEnabled(int action) { 248 switch (action) { 249 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 250 return mCarrierActionOnMeteredApnEnabled; 251 case CARRIER_ACTION_SET_RADIO_ENABLED: 252 return mCarrierActionOnRadioEnabled; 253 case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS: 254 return mCarrierActionReportDefaultNetworkStatus; 255 default: 256 loge("Unsupported action: " + action); 257 return null; 258 } 259 } 260 261 /** 262 * Register with CAA for a specific event. 263 * @param action which carrier action registrant is interested in 264 * @param notifyNow if carrier action has once set, notify registrant right after 265 * registering, so that registrants will get the latest carrier action. 266 */ registerForCarrierAction(int action, Handler h, int what, Object obj, boolean notifyNow)267 public void registerForCarrierAction(int action, Handler h, int what, Object obj, 268 boolean notifyNow) { 269 Boolean carrierAction = getCarrierActionEnabled(action); 270 if (carrierAction == null) { 271 throw new IllegalArgumentException("invalid carrier action: " + action); 272 } 273 RegistrantList list = getRegistrantsFromAction(action); 274 Registrant r = new Registrant(h, what, obj); 275 list.add(r); 276 if (notifyNow) { 277 r.notifyRegistrant(new AsyncResult(null, carrierAction, null)); 278 } 279 } 280 281 /** 282 * Unregister with CAA for a specific event. Callers will no longer be notified upon such event. 283 * @param action which carrier action caller is no longer interested in 284 */ unregisterForCarrierAction(Handler h, int action)285 public void unregisterForCarrierAction(Handler h, int action) { 286 RegistrantList list = getRegistrantsFromAction(action); 287 if (list == null) { 288 throw new IllegalArgumentException("invalid carrier action: " + action); 289 } 290 list.remove(h); 291 } 292 293 @VisibleForTesting getContentObserver()294 public ContentObserver getContentObserver() { 295 return mSettingsObserver; 296 } 297 log(String s)298 private void log(String s) { 299 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 300 } 301 loge(String s)302 private void loge(String s) { 303 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 304 } 305 logv(String s)306 private void logv(String s) { 307 Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 308 } 309 dump(FileDescriptor fd, PrintWriter pw, String[] args)310 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 311 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 312 pw.println(" mCarrierActionOnMeteredApnsEnabled Log:"); 313 ipw.increaseIndent(); 314 mMeteredApnEnabledLog.dump(fd, ipw, args); 315 ipw.decreaseIndent(); 316 317 pw.println(" mCarrierActionOnRadioEnabled Log:"); 318 ipw.increaseIndent(); 319 mRadioEnabledLog.dump(fd, ipw, args); 320 ipw.decreaseIndent(); 321 322 pw.println(" mCarrierActionReportDefaultNetworkStatus Log:"); 323 ipw.increaseIndent(); 324 mReportDefaultNetworkStatusLog.dump(fd, ipw, args); 325 ipw.decreaseIndent(); 326 } 327 } 328