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