CarrierActionAgent.java revision afffe1b3e671ba002a5bf79a2f59ec8e6c8bd6a3
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.util.LocalLog;
31import android.util.Log;
32
33import com.android.internal.annotations.VisibleForTesting;
34import com.android.internal.util.IndentingPrintWriter;
35import java.io.FileDescriptor;
36import 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 */
50public 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 (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState) ||
81                        IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
82                    sendEmptyMessage(CARRIER_ACTION_RESET);
83                }
84            }
85        }
86    };
87
88    private class SettingsObserver extends ContentObserver {
89        SettingsObserver() {
90            super(null);
91        }
92
93        @Override
94        public void onChange(boolean selfChange) {
95            if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
96                    Settings.Global.AIRPLANE_MODE_ON, 0) != 0) {
97                sendEmptyMessage(CARRIER_ACTION_RESET);
98            }
99        }
100    }
101
102    /** Constructor */
103    public CarrierActionAgent(Phone phone) {
104        mPhone = phone;
105        mPhone.getContext().registerReceiver(mReceiver,
106                new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
107        mSettingsObserver = new SettingsObserver();
108        mPhone.getContext().getContentResolver().registerContentObserver(
109                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
110                false, mSettingsObserver);
111        if (DBG) log("Creating CarrierActionAgent");
112    }
113
114    @Override
115    public void handleMessage(Message msg) {
116        switch (msg.what) {
117            case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
118                mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj;
119                log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
120                mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
121                        + mCarrierActionOnMeteredApnEnabled);
122                mMeteredApnEnableRegistrants.notifyRegistrants(
123                        new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
124                break;
125            case CARRIER_ACTION_SET_RADIO_ENABLED:
126                mCarrierActionOnRadioEnabled = (boolean) msg.obj;
127                log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
128                mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
129                mRadioEnableRegistrants.notifyRegistrants(
130                        new AsyncResult(null, mCarrierActionOnRadioEnabled, null));
131                break;
132            case CARRIER_ACTION_RESET:
133                log("CARRIER_ACTION_RESET");
134                carrierActionSetMeteredApnsEnabled(true);
135                carrierActionSetRadioEnabled(true);
136                // notify configured carrier apps for reset
137                mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
138                        new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
139                break;
140            default:
141                loge("Unknown carrier action: " + msg.what);
142        }
143    }
144
145    /**
146     * Return current carrier action values
147     */
148    public Object getCarrierActionValue(int action) {
149        Object val = getCarrierAction(action);
150        if (val == null) {
151            throw new IllegalArgumentException("invalid carrier action: " + action);
152        }
153        return val;
154    }
155
156    /**
157     * Action set from carrier app to enable/disable radio
158     */
159    public void carrierActionSetRadioEnabled(boolean enabled) {
160        sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled));
161    }
162
163    /**
164     * Action set from carrier app to enable/disable metered APNs
165     */
166    public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
167        sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled));
168    }
169
170    private RegistrantList getRegistrantsFromAction(int action) {
171        switch (action) {
172            case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
173                return mMeteredApnEnableRegistrants;
174            case CARRIER_ACTION_SET_RADIO_ENABLED:
175                return mRadioEnableRegistrants;
176            default:
177                loge("Unsupported action: " + action);
178                return null;
179        }
180    }
181
182    private Object getCarrierAction(int action) {
183        switch (action) {
184            case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
185                return mCarrierActionOnMeteredApnEnabled;
186            case CARRIER_ACTION_SET_RADIO_ENABLED:
187                return mCarrierActionOnRadioEnabled;
188            default:
189                loge("Unsupported action: " + action);
190                return null;
191        }
192    }
193
194    /**
195     * Register with CAA for a specific event.
196     * @param action which carrier action registrant is interested in
197     * @param notifyNow if carrier action has once set, notify registrant right after
198     *                  registering, so that registrants will get the latest carrier action.
199     */
200    public void registerForCarrierAction(int action, Handler h, int what, Object obj,
201                                         boolean notifyNow) {
202        Object carrierAction = getCarrierAction(action);
203        if (carrierAction == null) {
204            throw new IllegalArgumentException("invalid carrier action: " + action);
205        }
206        RegistrantList list = getRegistrantsFromAction(action);
207        Registrant r = new Registrant(h, what, obj);
208        list.add(r);
209        if (notifyNow) {
210            r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
211        }
212    }
213
214    /**
215     * Unregister with CAA for a specific event. Callers will no longer be notified upon such event.
216     * @param action which carrier action caller is no longer interested in
217     */
218    public void unregisterForCarrierAction(Handler h, int action) {
219        RegistrantList list = getRegistrantsFromAction(action);
220        if (list == null) {
221            throw new IllegalArgumentException("invalid carrier action: " + action);
222        }
223        list.remove(h);
224    }
225
226    @VisibleForTesting
227    public ContentObserver getContentObserver() {
228        return mSettingsObserver;
229    }
230
231    private void log(String s) {
232        Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
233    }
234
235    private void loge(String s) {
236        Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
237    }
238
239    private void logv(String s) {
240        Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
241    }
242
243    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
244        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
245        pw.println(" mCarrierActionOnMeteredApnsEnabled Log:");
246        ipw.increaseIndent();
247        mMeteredApnEnabledLog.dump(fd, ipw, args);
248        ipw.decreaseIndent();
249
250        pw.println(" mCarrierActionOnRadioEnabled Log:");
251        ipw.increaseIndent();
252        mRadioEnabledLog.dump(fd, ipw, args);
253        ipw.decreaseIndent();
254    }
255}
256