| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.internal.telephony; |
| |
| import android.content.ActivityNotFoundException; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.PackageManager; |
| import android.os.PersistableBundle; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.Rlog; |
| |
| import com.android.internal.util.ArrayUtils; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| /** |
| * This class act as an CarrierSignalling Agent. |
| * it load registered carrier signalling receivers from Carrier Config and cache the result to avoid |
| * repeated polling and send the intent to the interested receivers. |
| * each CarrierSignalAgent is associated with a phone object. |
| */ |
| public class CarrierSignalAgent { |
| |
| private static final String LOG_TAG = "CarrierSignalAgent"; |
| private static final boolean DBG = true; |
| |
| /** Member variables */ |
| private final Phone mPhone; |
| /** |
| * This is a map of intent action -> string array of carrier signal receiver names which are |
| * interested in this intent action |
| */ |
| private final HashMap<String, String[]> mCachedCarrierSignalReceiverNames = |
| new HashMap<>(); |
| /** |
| * This is a map of intent action -> carrier config key of signal receiver names which are |
| * interested in this intent action |
| */ |
| private final Map<String, String> mIntentToCarrierConfigKeyMap = |
| new HashMap<String, String>() {{ |
| put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED, |
| CarrierConfigManager.KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY); |
| put(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE, |
| CarrierConfigManager.KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY); |
| put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED, |
| CarrierConfigManager.KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY); |
| }}; |
| |
| /** Constructor */ |
| public CarrierSignalAgent(Phone phone) { |
| mPhone = phone; |
| } |
| |
| /** |
| * Read carrier signalling receiver name from CarrierConfig based on the intent type |
| * @return array of receiver Name: the package (a String) name / the class (a String) name |
| */ |
| private String[] getCarrierSignalReceiverName(String intentAction) { |
| String receiverType = mIntentToCarrierConfigKeyMap.get(intentAction); |
| if(receiverType == null) { |
| return null; |
| } |
| String[] receiverNames = mCachedCarrierSignalReceiverNames.get(intentAction); |
| // In case of cache miss, we need to look up/load from carrier config. |
| if (!mCachedCarrierSignalReceiverNames.containsKey(intentAction)) { |
| CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() |
| .getSystemService(Context.CARRIER_CONFIG_SERVICE); |
| PersistableBundle b = null; |
| if (configManager != null) { |
| b = configManager.getConfig(); |
| } |
| if (b != null) { |
| receiverNames = b.getStringArray(receiverType); |
| if(receiverNames!=null) { |
| for(String name: receiverNames) { |
| Rlog.d("loadCarrierSignalReceiverNames: ", name); |
| } |
| } |
| } |
| mCachedCarrierSignalReceiverNames.put(intentAction, receiverNames); |
| } |
| return receiverNames; |
| } |
| |
| /** |
| * Check if there are registered carrier broadcast receivers to handle any registered intents. |
| */ |
| public boolean hasRegisteredCarrierSignalReceivers() { |
| for(String intent : mIntentToCarrierConfigKeyMap.keySet()) { |
| if(!ArrayUtils.isEmpty(getCarrierSignalReceiverName(intent))) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean notifyCarrierSignalReceivers(Intent intent) { |
| // Read a list of broadcast receivers from carrier config manager |
| // which are interested on certain intent type |
| String[] receiverName = getCarrierSignalReceiverName(intent.getAction()); |
| if (receiverName == null) { |
| loge("Carrier receiver name is null"); |
| return false; |
| } |
| final PackageManager packageManager = mPhone.getContext().getPackageManager(); |
| boolean ret = false; |
| |
| for(String name : receiverName) { |
| ComponentName componentName = ComponentName.unflattenFromString(name); |
| if (componentName == null) { |
| loge("Carrier receiver name could not be parsed"); |
| return false; |
| } |
| intent.setComponent(componentName); |
| // Check if broadcast receiver is available |
| if (packageManager.queryBroadcastReceivers(intent, |
| PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) { |
| loge("Carrier signal receiver is configured, but not available: " + name); |
| break; |
| } |
| |
| intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mPhone.getSubId()); |
| intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); |
| |
| try { |
| mPhone.getContext().sendBroadcast(intent); |
| if (DBG) log("send Intent to carrier signal receiver with action: " + |
| intent.getAction()); |
| ret = true; |
| } catch (ActivityNotFoundException e) { |
| loge("sendBroadcast failed: " + e); |
| } |
| } |
| |
| return ret; |
| } |
| |
| /* Clear cached receiver names */ |
| public void reset() { |
| mCachedCarrierSignalReceiverNames.clear(); |
| } |
| |
| private void log(String s) { |
| Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); |
| } |
| |
| private void loge(String s) { |
| Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); |
| } |
| } |