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