• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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