Home | History | Annotate | Download | only in telephony
      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.provider.Telephony;
     30 import android.telephony.Rlog;
     31 import android.telephony.TelephonyManager;
     32 import android.util.LocalLog;
     33 import android.util.Log;
     34 
     35 import com.android.internal.annotations.VisibleForTesting;
     36 import com.android.internal.util.IndentingPrintWriter;
     37 
     38 import java.io.FileDescriptor;
     39 import java.io.PrintWriter;
     40 
     41 /**
     42  * Carrier Action Agent(CAA) paired with
     43  * {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent},
     44  * serves as an agent to dispatch carrier actions from carrier apps to different telephony modules,
     45  * {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean)
     46  * carrierActionSetRadioEnabled} for example.
     47  *
     48  * CAA supports dynamic registration where different telephony modules could listen for a specific
     49  * carrier action event and implement their own handler. CCA will dispatch the event to all
     50  * interested parties and maintain the received action states internally for future inspection.
     51  * Each CarrierActionAgent is associated with a phone object.
     52  */
     53 public class CarrierActionAgent extends Handler {
     54     private static final String LOG_TAG = "CarrierActionAgent";
     55     private static final boolean DBG = true;
     56     private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
     57 
     58     /** A list of carrier actions */
     59     public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED        = 0;
     60     public static final int CARRIER_ACTION_SET_RADIO_ENABLED               = 1;
     61     public static final int CARRIER_ACTION_RESET                           = 2;
     62     public static final int CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS   = 3;
     63     public static final int EVENT_APM_SETTINGS_CHANGED                     = 4;
     64     public static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED             = 5;
     65     public static final int EVENT_DATA_ROAMING_OFF                         = 6;
     66     public static final int EVENT_SIM_STATE_CHANGED                        = 7;
     67     public static final int EVENT_APN_SETTINGS_CHANGED                     = 8;
     68 
     69     /** Member variables */
     70     private final Phone mPhone;
     71     /** registrant list per carrier action */
     72     private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList();
     73     private RegistrantList mRadioEnableRegistrants = new RegistrantList();
     74     private RegistrantList mDefaultNetworkReportRegistrants = new RegistrantList();
     75     /** local log for carrier actions */
     76     private LocalLog mMeteredApnEnabledLog = new LocalLog(10);
     77     private LocalLog mRadioEnabledLog = new LocalLog(10);
     78     private LocalLog mReportDefaultNetworkStatusLog = new LocalLog(10);
     79     /** carrier actions */
     80     private Boolean mCarrierActionOnMeteredApnEnabled = true;
     81     private Boolean mCarrierActionOnRadioEnabled = true;
     82     private Boolean mCarrierActionReportDefaultNetworkStatus = false;
     83     /** content observer for APM change */
     84     private final SettingsObserver mSettingsObserver;
     85 
     86     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
     87         @Override
     88         public void onReceive(Context context, Intent intent) {
     89             final String action = intent.getAction();
     90             final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
     91             if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
     92                 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
     93                     // ignore rebroadcast since carrier apps are direct boot aware.
     94                     return;
     95                 }
     96                 sendMessage(obtainMessage(EVENT_SIM_STATE_CHANGED, iccState));
     97             }
     98         }
     99     };
    100 
    101     /** Constructor */
    102     public CarrierActionAgent(Phone phone) {
    103         mPhone = phone;
    104         mPhone.getContext().registerReceiver(mReceiver,
    105                 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
    106         mSettingsObserver = new SettingsObserver(mPhone.getContext(), this);
    107         if (DBG) log("Creating CarrierActionAgent");
    108     }
    109 
    110     @Override
    111     public void handleMessage(Message msg) {
    112         // skip notification if the input carrier action is same as the current one.
    113         Boolean enabled = getCarrierActionEnabled(msg.what);
    114         if (enabled != null && enabled == (boolean) msg.obj) return;
    115         switch (msg.what) {
    116             case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
    117                 mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj;
    118                 log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
    119                 mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
    120                         + mCarrierActionOnMeteredApnEnabled);
    121                 mMeteredApnEnableRegistrants.notifyRegistrants(
    122                         new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
    123                 break;
    124             case CARRIER_ACTION_SET_RADIO_ENABLED:
    125                 mCarrierActionOnRadioEnabled = (boolean) msg.obj;
    126                 log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
    127                 mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
    128                 mRadioEnableRegistrants.notifyRegistrants(
    129                         new AsyncResult(null, mCarrierActionOnRadioEnabled, null));
    130                 break;
    131             case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
    132                 mCarrierActionReportDefaultNetworkStatus = (boolean) msg.obj;
    133                 log("CARRIER_ACTION_REPORT_AT_DEFAULT_NETWORK_STATUS: "
    134                         + mCarrierActionReportDefaultNetworkStatus);
    135                 mReportDefaultNetworkStatusLog.log("REGISTER_DEFAULT_NETWORK_STATUS: "
    136                         + mCarrierActionReportDefaultNetworkStatus);
    137                 mDefaultNetworkReportRegistrants.notifyRegistrants(
    138                         new AsyncResult(null, mCarrierActionReportDefaultNetworkStatus, null));
    139                 break;
    140             case CARRIER_ACTION_RESET:
    141                 log("CARRIER_ACTION_RESET");
    142                 carrierActionReset();
    143                 break;
    144             case EVENT_APM_SETTINGS_CHANGED:
    145                 log("EVENT_APM_SETTINGS_CHANGED");
    146                 if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(),
    147                         Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) {
    148                     carrierActionReset();
    149                 }
    150                 break;
    151             case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
    152                 log("EVENT_MOBILE_DATA_SETTINGS_CHANGED");
    153                 if (!mPhone.isUserDataEnabled()) carrierActionReset();
    154                 break;
    155             case EVENT_DATA_ROAMING_OFF:
    156                 log("EVENT_DATA_ROAMING_OFF");
    157                 // reset carrier actions when exit roaming state.
    158                 carrierActionReset();
    159                 break;
    160             case EVENT_SIM_STATE_CHANGED:
    161                 String iccState = (String) msg.obj;
    162                 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) {
    163                     log("EVENT_SIM_STATE_CHANGED status: " + iccState);
    164                     carrierActionReset();
    165                     String mobileData = Settings.Global.MOBILE_DATA;
    166                     if (TelephonyManager.getDefault().getSimCount() != 1) {
    167                         mobileData = mobileData + mPhone.getSubId();
    168                     }
    169                     mSettingsObserver.observe(Settings.Global.getUriFor(mobileData),
    170                             EVENT_MOBILE_DATA_SETTINGS_CHANGED);
    171                     mSettingsObserver.observe(
    172                             Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
    173                             EVENT_APM_SETTINGS_CHANGED);
    174                     mSettingsObserver.observe(
    175                             Telephony.Carriers.CONTENT_URI, EVENT_APN_SETTINGS_CHANGED);
    176                     if (mPhone.getServiceStateTracker() != null) {
    177                         mPhone.getServiceStateTracker().registerForDataRoamingOff(
    178                                 this, EVENT_DATA_ROAMING_OFF, null, false);
    179                     }
    180                 } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
    181                     log("EVENT_SIM_STATE_CHANGED status: " + iccState);
    182                     carrierActionReset();
    183                     mSettingsObserver.unobserve();
    184                     if (mPhone.getServiceStateTracker() != null) {
    185                         mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
    186                     }
    187                 }
    188                 break;
    189             case EVENT_APN_SETTINGS_CHANGED:
    190                 log("EVENT_APN_SETTINGS_CHANGED");
    191                 // Reset carrier actions when APN change.
    192                 carrierActionReset();
    193                 break;
    194             default:
    195                 loge("Unknown carrier action: " + msg.what);
    196         }
    197     }
    198 
    199     /**
    200      * Action set from carrier app to enable/disable radio
    201      */
    202     public void carrierActionSetRadioEnabled(boolean enabled) {
    203         sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled));
    204     }
    205 
    206     /**
    207      * Action set from carrier app to enable/disable metered APNs
    208      */
    209     public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
    210         sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled));
    211     }
    212 
    213     /**
    214      * Action set from carrier app to start/stop reporting default network status.
    215      */
    216     public void carrierActionReportDefaultNetworkStatus(boolean report) {
    217         sendMessage(obtainMessage(CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, report));
    218     }
    219 
    220     private void carrierActionReset() {
    221         carrierActionReportDefaultNetworkStatus(false);
    222         carrierActionSetMeteredApnsEnabled(true);
    223         carrierActionSetRadioEnabled(true);
    224         // notify configured carrier apps for reset
    225         mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
    226                 new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
    227     }
    228 
    229     private RegistrantList getRegistrantsFromAction(int action) {
    230         switch (action) {
    231             case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
    232                 return mMeteredApnEnableRegistrants;
    233             case CARRIER_ACTION_SET_RADIO_ENABLED:
    234                 return mRadioEnableRegistrants;
    235             case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
    236                 return mDefaultNetworkReportRegistrants;
    237             default:
    238                 loge("Unsupported action: " + action);
    239                 return null;
    240         }
    241     }
    242 
    243     private Boolean getCarrierActionEnabled(int action) {
    244         switch (action) {
    245             case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
    246                 return mCarrierActionOnMeteredApnEnabled;
    247             case CARRIER_ACTION_SET_RADIO_ENABLED:
    248                 return mCarrierActionOnRadioEnabled;
    249             case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
    250                 return mCarrierActionReportDefaultNetworkStatus;
    251             default:
    252                 loge("Unsupported action: " + action);
    253                 return null;
    254         }
    255     }
    256 
    257     /**
    258      * Register with CAA for a specific event.
    259      * @param action which carrier action registrant is interested in
    260      * @param notifyNow if carrier action has once set, notify registrant right after
    261      *                  registering, so that registrants will get the latest carrier action.
    262      */
    263     public void registerForCarrierAction(int action, Handler h, int what, Object obj,
    264                                          boolean notifyNow) {
    265         Boolean carrierAction = getCarrierActionEnabled(action);
    266         if (carrierAction == null) {
    267             throw new IllegalArgumentException("invalid carrier action: " + action);
    268         }
    269         RegistrantList list = getRegistrantsFromAction(action);
    270         Registrant r = new Registrant(h, what, obj);
    271         list.add(r);
    272         if (notifyNow) {
    273             r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
    274         }
    275     }
    276 
    277     /**
    278      * Unregister with CAA for a specific event. Callers will no longer be notified upon such event.
    279      * @param action which carrier action caller is no longer interested in
    280      */
    281     public void unregisterForCarrierAction(Handler h, int action) {
    282         RegistrantList list = getRegistrantsFromAction(action);
    283         if (list == null) {
    284             throw new IllegalArgumentException("invalid carrier action: " + action);
    285         }
    286         list.remove(h);
    287     }
    288 
    289     @VisibleForTesting
    290     public ContentObserver getContentObserver() {
    291         return mSettingsObserver;
    292     }
    293 
    294     private void log(String s) {
    295         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
    296     }
    297 
    298     private void loge(String s) {
    299         Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
    300     }
    301 
    302     private void logv(String s) {
    303         Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
    304     }
    305 
    306     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    307         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
    308         pw.println(" mCarrierActionOnMeteredApnsEnabled Log:");
    309         ipw.increaseIndent();
    310         mMeteredApnEnabledLog.dump(fd, ipw, args);
    311         ipw.decreaseIndent();
    312 
    313         pw.println(" mCarrierActionOnRadioEnabled Log:");
    314         ipw.increaseIndent();
    315         mRadioEnabledLog.dump(fd, ipw, args);
    316         ipw.decreaseIndent();
    317 
    318         pw.println(" mCarrierActionReportDefaultNetworkStatus Log:");
    319         ipw.increaseIndent();
    320         mReportDefaultNetworkStatusLog.dump(fd, ipw, args);
    321         ipw.decreaseIndent();
    322     }
    323 }
    324