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.util.LocalLog; 31 import android.util.Log; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 import com.android.internal.util.IndentingPrintWriter; 35 import java.io.FileDescriptor; 36 import java.io.PrintWriter; 37 38 /** 39 * Carrier Action Agent(CAA) paired with 40 * {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent}, 41 * serves as an agent to dispatch carrier actions from carrier apps to different telephony modules, 42 * {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean) 43 * carrierActionSetRadioEnabled} for example. 44 * 45 * CAA supports dynamic registration where different telephony modules could listen for a specific 46 * carrier action event and implement their own handler. CCA will dispatch the event to all 47 * interested parties and maintain the received action states internally for future inspection. 48 * Each CarrierActionAgent is associated with a phone object. 49 */ 50 public class CarrierActionAgent extends Handler { 51 private static final String LOG_TAG = "CarrierActionAgent"; 52 private static final boolean DBG = true; 53 private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); 54 55 /** A list of carrier actions */ 56 public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED = 0; 57 public static final int CARRIER_ACTION_SET_RADIO_ENABLED = 1; 58 public static final int CARRIER_ACTION_RESET = 2; 59 60 /** Member variables */ 61 private final Phone mPhone; 62 /** registrant list per carrier action */ 63 private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList(); 64 private RegistrantList mRadioEnableRegistrants = new RegistrantList(); 65 /** local log for carrier actions */ 66 private LocalLog mMeteredApnEnabledLog = new LocalLog(10); 67 private LocalLog mRadioEnabledLog = new LocalLog(10); 68 /** carrier actions, true by default */ 69 private Boolean mCarrierActionOnMeteredApnEnabled = true; 70 private Boolean mCarrierActionOnRadioEnabled = true; 71 /** content observer for APM change */ 72 private final SettingsObserver mSettingsObserver; 73 74 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 75 @Override 76 public void onReceive(Context context, Intent intent) { 77 final String action = intent.getAction(); 78 final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 79 if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ 80 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) { 81 // ignore rebroadcast since carrier apps are direct boot aware. 82 return; 83 } 84 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState) || 85 IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) { 86 sendEmptyMessage(CARRIER_ACTION_RESET); 87 } 88 } 89 } 90 }; 91 92 private class SettingsObserver extends ContentObserver { SettingsObserver()93 SettingsObserver() { 94 super(null); 95 } 96 97 @Override onChange(boolean selfChange)98 public void onChange(boolean selfChange) { 99 if (Settings.Global.getInt(mPhone.getContext().getContentResolver(), 100 Settings.Global.AIRPLANE_MODE_ON, 0) != 0) { 101 sendEmptyMessage(CARRIER_ACTION_RESET); 102 } 103 } 104 } 105 106 /** Constructor */ CarrierActionAgent(Phone phone)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(); 112 mPhone.getContext().getContentResolver().registerContentObserver( 113 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), 114 false, mSettingsObserver); 115 if (DBG) log("Creating CarrierActionAgent"); 116 } 117 118 @Override handleMessage(Message msg)119 public void handleMessage(Message msg) { 120 switch (msg.what) { 121 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 122 mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj; 123 log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled); 124 mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: " 125 + mCarrierActionOnMeteredApnEnabled); 126 mMeteredApnEnableRegistrants.notifyRegistrants( 127 new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null)); 128 break; 129 case CARRIER_ACTION_SET_RADIO_ENABLED: 130 mCarrierActionOnRadioEnabled = (boolean) msg.obj; 131 log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 132 mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled); 133 mRadioEnableRegistrants.notifyRegistrants( 134 new AsyncResult(null, mCarrierActionOnRadioEnabled, null)); 135 break; 136 case CARRIER_ACTION_RESET: 137 log("CARRIER_ACTION_RESET"); 138 carrierActionSetMeteredApnsEnabled(true); 139 carrierActionSetRadioEnabled(true); 140 // notify configured carrier apps for reset 141 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers( 142 new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET)); 143 break; 144 default: 145 loge("Unknown carrier action: " + msg.what); 146 } 147 } 148 149 /** 150 * Return current carrier action values 151 */ getCarrierActionValue(int action)152 public Object getCarrierActionValue(int action) { 153 Object val = getCarrierAction(action); 154 if (val == null) { 155 throw new IllegalArgumentException("invalid carrier action: " + action); 156 } 157 return val; 158 } 159 160 /** 161 * Action set from carrier app to enable/disable radio 162 */ carrierActionSetRadioEnabled(boolean enabled)163 public void carrierActionSetRadioEnabled(boolean enabled) { 164 sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled)); 165 } 166 167 /** 168 * Action set from carrier app to enable/disable metered APNs 169 */ carrierActionSetMeteredApnsEnabled(boolean enabled)170 public void carrierActionSetMeteredApnsEnabled(boolean enabled) { 171 sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled)); 172 } 173 getRegistrantsFromAction(int action)174 private RegistrantList getRegistrantsFromAction(int action) { 175 switch (action) { 176 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 177 return mMeteredApnEnableRegistrants; 178 case CARRIER_ACTION_SET_RADIO_ENABLED: 179 return mRadioEnableRegistrants; 180 default: 181 loge("Unsupported action: " + action); 182 return null; 183 } 184 } 185 getCarrierAction(int action)186 private Object getCarrierAction(int action) { 187 switch (action) { 188 case CARRIER_ACTION_SET_METERED_APNS_ENABLED: 189 return mCarrierActionOnMeteredApnEnabled; 190 case CARRIER_ACTION_SET_RADIO_ENABLED: 191 return mCarrierActionOnRadioEnabled; 192 default: 193 loge("Unsupported action: " + action); 194 return null; 195 } 196 } 197 198 /** 199 * Register with CAA for a specific event. 200 * @param action which carrier action registrant is interested in 201 * @param notifyNow if carrier action has once set, notify registrant right after 202 * registering, so that registrants will get the latest carrier action. 203 */ registerForCarrierAction(int action, Handler h, int what, Object obj, boolean notifyNow)204 public void registerForCarrierAction(int action, Handler h, int what, Object obj, 205 boolean notifyNow) { 206 Object carrierAction = getCarrierAction(action); 207 if (carrierAction == null) { 208 throw new IllegalArgumentException("invalid carrier action: " + action); 209 } 210 RegistrantList list = getRegistrantsFromAction(action); 211 Registrant r = new Registrant(h, what, obj); 212 list.add(r); 213 if (notifyNow) { 214 r.notifyRegistrant(new AsyncResult(null, carrierAction, null)); 215 } 216 } 217 218 /** 219 * Unregister with CAA for a specific event. Callers will no longer be notified upon such event. 220 * @param action which carrier action caller is no longer interested in 221 */ unregisterForCarrierAction(Handler h, int action)222 public void unregisterForCarrierAction(Handler h, int action) { 223 RegistrantList list = getRegistrantsFromAction(action); 224 if (list == null) { 225 throw new IllegalArgumentException("invalid carrier action: " + action); 226 } 227 list.remove(h); 228 } 229 230 @VisibleForTesting getContentObserver()231 public ContentObserver getContentObserver() { 232 return mSettingsObserver; 233 } 234 log(String s)235 private void log(String s) { 236 Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 237 } 238 loge(String s)239 private void loge(String s) { 240 Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 241 } 242 logv(String s)243 private void logv(String s) { 244 Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); 245 } 246 dump(FileDescriptor fd, PrintWriter pw, String[] args)247 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 248 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 249 pw.println(" mCarrierActionOnMeteredApnsEnabled Log:"); 250 ipw.increaseIndent(); 251 mMeteredApnEnabledLog.dump(fd, ipw, args); 252 ipw.decreaseIndent(); 253 254 pw.println(" mCarrierActionOnRadioEnabled Log:"); 255 ipw.increaseIndent(); 256 mRadioEnabledLog.dump(fd, ipw, args); 257 ipw.decreaseIndent(); 258 } 259 } 260