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.ActivityNotFoundException;
     19 import android.content.ComponentName;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.pm.PackageManager;
     23 import android.os.PersistableBundle;
     24 import android.telephony.CarrierConfigManager;
     25 import android.telephony.Rlog;
     26 
     27 import com.android.internal.util.ArrayUtils;
     28 
     29 import java.util.HashMap;
     30 import java.util.Map;
     31 
     32 /**
     33  * This class act as an CarrierSignalling Agent.
     34  * it load registered carrier signalling receivers from Carrier Config and cache the result to avoid
     35  * repeated polling and send the intent to the interested receivers.
     36  * each CarrierSignalAgent is associated with a phone object.
     37  */
     38 public class CarrierSignalAgent {
     39 
     40     private static final String LOG_TAG = "CarrierSignalAgent";
     41     private static final boolean DBG = true;
     42 
     43     /** Member variables */
     44     private final Phone mPhone;
     45     /**
     46      * This is a map of intent action -> string array of carrier signal receiver names which are
     47      * interested in this intent action
     48      */
     49     private final HashMap<String, String[]> mCachedCarrierSignalReceiverNames =
     50             new HashMap<>();
     51     /**
     52      * This is a map of intent action -> carrier config key of signal receiver names which are
     53      * interested in this intent action
     54      */
     55     private final Map<String, String> mIntentToCarrierConfigKeyMap =
     56             new HashMap<String, String>() {{
     57                 put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED,
     58                         CarrierConfigManager.KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY);
     59                 put(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE,
     60                         CarrierConfigManager.KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY);
     61                 put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
     62                         CarrierConfigManager.KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY);
     63             }};
     64 
     65     /** Constructor */
     66     public CarrierSignalAgent(Phone phone) {
     67         mPhone = phone;
     68     }
     69 
     70     /**
     71      * Read carrier signalling receiver name from CarrierConfig based on the intent type
     72      * @return array of receiver Name: the package (a String) name / the class (a String) name
     73      */
     74     private String[] getCarrierSignalReceiverName(String intentAction) {
     75         String receiverType = mIntentToCarrierConfigKeyMap.get(intentAction);
     76         if(receiverType == null) {
     77             return null;
     78         }
     79         String[] receiverNames = mCachedCarrierSignalReceiverNames.get(intentAction);
     80         // In case of cache miss, we need to look up/load from carrier config.
     81         if (!mCachedCarrierSignalReceiverNames.containsKey(intentAction)) {
     82             CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
     83                     .getSystemService(Context.CARRIER_CONFIG_SERVICE);
     84             PersistableBundle b = null;
     85             if (configManager != null) {
     86                 b = configManager.getConfig();
     87             }
     88             if (b != null) {
     89                 receiverNames = b.getStringArray(receiverType);
     90                 if(receiverNames!=null) {
     91                     for(String name: receiverNames) {
     92                         Rlog.d("loadCarrierSignalReceiverNames: ", name);
     93                     }
     94                 }
     95             }
     96             mCachedCarrierSignalReceiverNames.put(intentAction, receiverNames);
     97         }
     98         return receiverNames;
     99     }
    100 
    101     /**
    102      * Check if there are registered carrier broadcast receivers to handle any registered intents.
    103      */
    104     public boolean hasRegisteredCarrierSignalReceivers() {
    105         for(String intent : mIntentToCarrierConfigKeyMap.keySet()) {
    106             if(!ArrayUtils.isEmpty(getCarrierSignalReceiverName(intent))) {
    107                 return true;
    108             }
    109         }
    110         return false;
    111     }
    112 
    113     public boolean notifyCarrierSignalReceivers(Intent intent) {
    114         // Read a list of broadcast receivers from carrier config manager
    115         // which are interested on certain intent type
    116         String[] receiverName = getCarrierSignalReceiverName(intent.getAction());
    117         if (receiverName == null) {
    118             loge("Carrier receiver name is null");
    119             return false;
    120         }
    121         final PackageManager packageManager = mPhone.getContext().getPackageManager();
    122         boolean ret = false;
    123 
    124         for(String name : receiverName) {
    125             ComponentName componentName = ComponentName.unflattenFromString(name);
    126             if (componentName == null) {
    127                 loge("Carrier receiver name could not be parsed");
    128                 return false;
    129             }
    130             intent.setComponent(componentName);
    131             // Check if broadcast receiver is available
    132             if (packageManager.queryBroadcastReceivers(intent,
    133                     PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
    134                 loge("Carrier signal receiver is configured, but not available: " + name);
    135                 break;
    136             }
    137 
    138             intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mPhone.getSubId());
    139             intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    140 
    141             try {
    142                 mPhone.getContext().sendBroadcast(intent);
    143                 if (DBG) log("send Intent to carrier signal receiver with action: " +
    144                         intent.getAction());
    145                 ret = true;
    146             } catch (ActivityNotFoundException e) {
    147                 loge("sendBroadcast failed: " + e);
    148             }
    149         }
    150 
    151         return ret;
    152     }
    153 
    154     /* Clear cached receiver names */
    155     public void reset() {
    156         mCachedCarrierSignalReceiverNames.clear();
    157     }
    158 
    159     private void log(String s) {
    160         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
    161     }
    162 
    163     private void loge(String s) {
    164         Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
    165     }
    166 }
    167