CarrierActionAgent.java revision 5ddb6ec362673fab1ece512d4c9f1068e1642697
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 */ 16package com.android.internal.telephony; 17 18import android.content.BroadcastReceiver; 19import android.content.Context; 20import android.content.Intent; 21import android.content.IntentFilter; 22import android.database.ContentObserver; 23import android.os.AsyncResult; 24import android.os.Handler; 25import android.os.Message; 26import android.os.Registrant; 27import android.os.RegistrantList; 28import android.provider.Settings; 29import android.telephony.Rlog; 30import android.telephony.TelephonyManager; 31import android.util.LocalLog; 32import android.util.Log; 33 34import com.android.internal.annotations.VisibleForTesting; 35import com.android.internal.util.IndentingPrintWriter; 36import java.io.FileDescriptor; 37import 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 */ 51public 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 EVENT_APM_SETTINGS_CHANGED = 3; 61 public static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 4; 62 public static final int EVENT_DATA_ROAMING_OFF = 5; 63 public static final int EVENT_SIM_STATE_CHANGED = 6; 64 65 /** Member variables */ 66 private final Phone mPhone; 67 /** registrant list per carrier action */ 68 private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList(); 69 private RegistrantList mRadioEnableRegistrants = new RegistrantList(); 70 /** local log for carrier actions */ 71 private LocalLog mMeteredApnEnabledLog = new LocalLog(10); 72 private LocalLog mRadioEnabledLog = new LocalLog(10); 73 /** carrier actions, true by default */ 74 private Boolean mCarrierActionOnMeteredApnEnabled = true; 75 private Boolean mCarrierActionOnRadioEnabled = true; 76 /** content observer for APM change */ 77 private final SettingsObserver mSettingsObserver; 78 79 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 80 @Override 81 public void onReceive(Context context, Intent intent) { 82 final String action = intent.getAction(); 83 final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 84 if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ 85 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) { 86 // ignore rebroadcast since carrier apps are direct boot aware. 87 return; 88 } 89 sendMessage(obtainMessage(EVENT_SIM_STATE_CHANGED, iccState)); 90 } 91 } 92 }; 93 94 /** Constructor */ 95 public CarrierActionAgent(Phone phone) { 96 mPhone = phone; 97 mPhone.getContext().registerReceiver(mReceiver, 98 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); 99 mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); 100 if (DBG) log("Creating CarrierActionAgent"); 101 } 102 103 @Override 104 public void handleMessage(Message msg) { 105 switch (msg.what) { 106 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 107 mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj; 108 log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled); 109 mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: " 110 + mCarrierActionOnMeteredApnEnabled); 111 mMeteredApnEnableRegistrants.notifyRegistrants( 112 new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null)); 113 break; 114 case CARRIER_ACTION_SET_RADIO_ENABLED: 115 mCarrierActionOnRadioEnabled = (boolean) msg.obj; 116 log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 117 mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 118 mRadioEnableRegistrants.notifyRegistrants( 119 new AsyncResult(null, mCarrierActionOnRadioEnabled, null)); 120 break; 121 case CARRIER_ACTION_RESET: 122 log("CARRIER_ACTION_RESET"); 123 carrierActionReset(); 124 break; 125 case EVENT_APM_SETTINGS_CHANGED: 126 log("EVENT_APM_SETTINGS_CHANGED"); 127 if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(), 128 Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) { 129 carrierActionReset(); 130 } 131 break; 132 case EVENT_MOBILE_DATA_SETTINGS_CHANGED: 133 log("EVENT_MOBILE_DATA_SETTINGS_CHANGED"); 134 if (!mPhone.getDataEnabled()) carrierActionReset(); 135 break; 136 case EVENT_DATA_ROAMING_OFF: 137 log("EVENT_DATA_ROAMING_OFF"); 138 // reset carrier actions when exit roaming state. 139 carrierActionReset(); 140 break; 141 case EVENT_SIM_STATE_CHANGED: 142 String iccState = (String) msg.obj; 143 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) { 144 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 145 carrierActionReset(); 146 String mobileData = Settings.Global.MOBILE_DATA; 147 if (TelephonyManager.getDefault().getSimCount() != 1) { 148 mobileData = mobileData + mPhone.getSubId(); 149 } 150 mSettingsObserver.observe(Settings.Global.getUriFor(mobileData), 151 EVENT_MOBILE_DATA_SETTINGS_CHANGED); 152 mSettingsObserver.observe( 153 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), 154 EVENT_APM_SETTINGS_CHANGED); 155 if (mPhone.getServiceStateTracker() != null) { 156 mPhone.getServiceStateTracker().registerForDataRoamingOff( 157 this, EVENT_DATA_ROAMING_OFF, null, false); 158 } 159 } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) { 160 log("EVENT_SIM_STATE_CHANGED status: " + iccState); 161 carrierActionReset(); 162 mSettingsObserver.unobserve(); 163 if (mPhone.getServiceStateTracker() != null) { 164 mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); 165 } 166 } 167 break; 168 default: 169 loge("Unknown carrier action: " + msg.what); 170 } 171 } 172 173 /** 174 * Return current carrier action values 175 */ 176 public Object getCarrierActionValue(int action) { 177 Object val = getCarrierAction(action); 178 if (val == null) { 179 throw new IllegalArgumentException("invalid carrier action: " + action); 180 } 181 return val; 182 } 183 184 /** 185 * Action set from carrier app to enable/disable radio 186 */ 187 public void carrierActionSetRadioEnabled(boolean enabled) { 188 sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled)); 189 } 190 191 /** 192 * Action set from carrier app to enable/disable metered APNs 193 */ 194 public void carrierActionSetMeteredApnsEnabled(boolean enabled) { 195 sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled)); 196 } 197 198 private void carrierActionReset() { 199 carrierActionSetMeteredApnsEnabled(true); 200 carrierActionSetRadioEnabled(true); 201 // notify configured carrier apps for reset 202 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers( 203 new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET)); 204 } 205 206 private RegistrantList getRegistrantsFromAction(int action) { 207 switch (action) { 208 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 209 return mMeteredApnEnableRegistrants; 210 case CARRIER_ACTION_SET_RADIO_ENABLED: 211 return mRadioEnableRegistrants; 212 default: 213 loge("Unsupported action: " + action); 214 return null; 215 } 216 } 217 218 private Object getCarrierAction(int action) { 219 switch (action) { 220 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 221 return mCarrierActionOnMeteredApnEnabled; 222 case CARRIER_ACTION_SET_RADIO_ENABLED: 223 return mCarrierActionOnRadioEnabled; 224 default: 225 loge("Unsupported action: " + action); 226 return null; 227 } 228 } 229 230 /** 231 * Register with CAA for a specific event. 232 * @param action which carrier action registrant is interested in 233 * @param notifyNow if carrier action has once set, notify registrant right after 234 * registering, so that registrants will get the latest carrier action. 235 */ 236 public void registerForCarrierAction(int action, Handler h, int what, Object obj, 237 boolean notifyNow) { 238 Object carrierAction = getCarrierAction(action); 239 if (carrierAction == null) { 240 throw new IllegalArgumentException("invalid carrier action: " + action); 241 } 242 RegistrantList list = getRegistrantsFromAction(action); 243 Registrant r = new Registrant(h, what, obj); 244 list.add(r); 245 if (notifyNow) { 246 r.notifyRegistrant(new AsyncResult(null, carrierAction, null)); 247 } 248 } 249 250 /** 251 * Unregister with CAA for a specific event. Callers will no longer be notified upon such event. 252 * @param action which carrier action caller is no longer interested in 253 */ 254 public void unregisterForCarrierAction(Handler h, int action) { 255 RegistrantList list = getRegistrantsFromAction(action); 256 if (list == null) { 257 throw new IllegalArgumentException("invalid carrier action: " + action); 258 } 259 list.remove(h); 260 } 261 262 @VisibleForTesting 263 public ContentObserver getContentObserver() { 264 return mSettingsObserver; 265 } 266 267 private void log(String s) { 268 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 269 } 270 271 private void loge(String s) { 272 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 273 } 274 275 private void logv(String s) { 276 Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 277 } 278 279 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 280 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 281 pw.println(" mCarrierActionOnMeteredApnsEnabled Log:"); 282 ipw.increaseIndent(); 283 mMeteredApnEnabledLog.dump(fd, ipw, args); 284 ipw.decreaseIndent(); 285 286 pw.println(" mCarrierActionOnRadioEnabled Log:"); 287 ipw.increaseIndent(); 288 mRadioEnabledLog.dump(fd, ipw, args); 289 ipw.decreaseIndent(); 290 } 291} 292