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