cold sim clean up
- add new api to control provisioning notification visibility through
network agent
- rework on the interaction between carrier app and framework
- code cleanup
- unit test support
- hook pco value into datacallcomplete, enabling test by set sysprop for
pco values
Bug: 28567303
Change-Id: Id6b9b2aff4c4f128103593aab0bcef1c3a365141
diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
new file mode 100644
index 0000000..3d0bc6e
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
@@ -0,0 +1,169 @@
+/*
+ * 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 static 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 static 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);
+ }
+ }
+ } else {
+ // Return static default defined in CarrierConfigManager.
+ receiverNames = CarrierConfigManager.getDefaultConfig().getStringArray(receiverType);
+ }
+ 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);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 79a054b..e4b62c9 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -225,6 +225,8 @@
private int mCallRingContinueToken;
private int mCallRingDelay;
private boolean mIsVoiceCapable = true;
+ /* Used for communicate between configured CarrierSignalling receivers */
+ private CarrierSignalAgent mCarrierSignalAgent;
// Variable to cache the video capability. When RAT changes, we lose this info and are unable
// to recover from the state. We cache it and notify listeners when they register.
@@ -424,6 +426,7 @@
mContext = context;
mLooper = Looper.myLooper();
mCi = ci;
+ mCarrierSignalAgent = new CarrierSignalAgent(this);
mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
@@ -1718,6 +1721,10 @@
return (callForwardingIndicator == IccRecords.CALL_FORWARDING_STATUS_ENABLED);
}
+ public CarrierSignalAgent getCarrierSignalAgent() {
+ return mCarrierSignalAgent;
+ }
+
/**
* Query the CDMA roaming preference setting
*
@@ -2616,6 +2623,25 @@
(mDcTracker.isDataPossible(apnType)));
}
+
+ /**
+ * Action set from carrier signalling broadcast receivers to enable/disable metered apns.
+ */
+ public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
+ if(mDcTracker != null) {
+ mDcTracker.carrierActionSetMeteredApnsEnabled(enabled);
+ }
+ }
+
+ /**
+ * Action set from carrier signalling broadcast receivers to enable/disable radio
+ */
+ public void carrierActionSetRadioEnabled(boolean enabled) {
+ if(mDcTracker != null) {
+ mDcTracker.carrierActionSetRadioEnabled(enabled);
+ }
+ }
+
/**
* Notify registrants of a new ringing Connection.
* Subclasses of Phone probably want to replace this with a
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index cff562a..ebe8827 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -114,6 +114,8 @@
static final String REASON_SIM_NOT_READY = "simNotReady";
static final String REASON_IWLAN_AVAILABLE = "iwlanAvailable";
static final String REASON_CARRIER_CHANGE = "carrierChange";
+ static final String REASON_CARRIER_ACTION_DISABLE_METERED_APN =
+ "carrierActionDisableMeteredApn";
// Used for band mode selection methods
static final int BM_UNSPECIFIED = RILConstants.BAND_MODE_UNSPECIFIED; // automatic
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 8af290e..1122b36 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -252,6 +252,8 @@
private boolean mImsRegistrationOnOff = false;
private boolean mAlarmSwitch = false;
+ /** Radio is disabled by carrier. Radio power will not be override if this field is set */
+ private boolean mRadioDisabledByCarrier = false;
private PendingIntent mRadioOffIntent = null;
private static final String ACTION_RADIO_OFF = "android.intent.action.ACTION_RADIO_OFF";
private boolean mPowerOffDelayNeed = true;
@@ -796,6 +798,16 @@
}
/**
+ * Radio power set from carrier action. if set to false means carrier desire to turn radio off
+ * and radio wont be re-enabled unless carrier explicitly turn it back on.
+ * @param enable indicate if radio power is enabled or disabled from carrier action.
+ */
+ public void setRadioPowerFromCarrier(boolean enable) {
+ mRadioDisabledByCarrier = !enable;
+ setRadioPower(enable);
+ }
+
+ /**
* These two flags manage the behavior of the cell lock -- the
* lock should be held if either flag is true. The intention is
* to allow temporary acquisition of the lock to get a single
@@ -2266,7 +2278,8 @@
", mDesiredPowerState=" + mDesiredPowerState +
", getRadioState=" + mCi.getRadioState() +
", mPowerOffDelayNeed=" + mPowerOffDelayNeed +
- ", mAlarmSwitch=" + mAlarmSwitch);
+ ", mAlarmSwitch=" + mAlarmSwitch +
+ ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier);
}
if (mPhone.isPhoneTypeGsm() && mAlarmSwitch) {
@@ -2279,7 +2292,8 @@
// If we want it on and it's off, turn it on
if (mDesiredPowerState
- && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
+ && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF &&
+ !mRadioDisabledByCarrier) {
mCi.setRadioPower(true, null);
} else if (!mDesiredPowerState && mCi.getRadioState().isOn()) {
// If it's on and available and we want it off gracefully
@@ -4566,6 +4580,7 @@
pw.println(" mImsRegistered=" + mImsRegistered);
pw.println(" mImsRegistrationOnOff=" + mImsRegistrationOnOff);
pw.println(" mAlarmSwitch=" + mAlarmSwitch);
+ pw.println(" mRadioDisabledByCarrier" + mRadioDisabledByCarrier);
pw.println(" mPowerOffDelayNeed=" + mPowerOffDelayNeed);
pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown);
pw.println(" mSpnUpdatePending=" + mSpnUpdatePending);
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 568c348..38b054b 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -290,16 +290,12 @@
// FIXME: consider stick this into database too
String countryIso = getSubscriptionCountryIso(id);
- int simProvisioningStatus = cursor.getInt(cursor.getColumnIndexOrThrow(
- SubscriptionManager.SIM_PROVISIONING_STATUS));
-
if (VDBG) {
String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId);
logd("[getSubInfoRecord] id:" + id + " iccid:" + iccIdToPrint + " simSlotIndex:"
+ simSlotIndex + " displayName:" + displayName + " nameSource:" + nameSource
+ " iconTint:" + iconTint + " dataRoaming:" + dataRoaming
- + " mcc:" + mcc + " mnc:" + mnc + " countIso:" + countryIso
- + " simProvisioningStatus:" + simProvisioningStatus);
+ + " mcc:" + mcc + " mnc:" + mnc + " countIso:" + countryIso);
}
// If line1number has been set to a different number, use it instead.
@@ -308,8 +304,7 @@
number = line1Number;
}
return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
- nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
- simProvisioningStatus);
+ nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso);
}
/**
@@ -1099,47 +1094,6 @@
return result;
}
- /**
- * Set SimProvisioning Status by subscription ID
- * @param provisioningStatus with the subscription:
- * {@See SubscriptionManager#SIM_PROVISIONED}
- * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
- * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
- * @param subId the unique SubInfoRecord index in database
- * @return the number of records updated
- */
- @Override
- public int setSimProvisioningStatus(int provisioningStatus, int subId) {
-
- if (DBG) {
- logd("[setSimProvisioningStatus]+ provisioningStatus:" + provisioningStatus + " subId:"
- + subId);
- }
-
- enforceModifyPhoneState("setSimProvisioningStatus");
- // Now that all security checks passes, perform the operation as ourselves.
- final long identity = Binder.clearCallingIdentity();
- try {
- validateSubId(subId);
- if (provisioningStatus < 0 || provisioningStatus >
- SubscriptionManager.MAX_SIM_PROVISIONING_STATUS) {
- logd("[setSimProvisioningStatus]- fail with wrong provisioningStatus");
- return -1;
- }
- ContentValues value = new ContentValues(1);
- value.put(SubscriptionManager.SIM_PROVISIONING_STATUS, provisioningStatus);
-
- int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI,
- value, SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" +
- Long.toString(subId), null);
- notifySubscriptionInfoChanged();
-
- return result;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
@Override
public int getSlotId(int subId) {
if (VDBG) printStackTrace("[getSlotId] subId=" + subId);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 22a5c7c..c5064e1 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.dataconnection;
import com.android.internal.telephony.CallTracker;
+import com.android.internal.telephony.CarrierSignalAgent;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.DctConstants;
import com.android.internal.telephony.Phone;
@@ -1513,6 +1514,11 @@
updateTcpBufferSizes(mRilRat);
final NetworkMisc misc = new NetworkMisc();
+ final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent();
+ if(carrierSignalAgent.hasRegisteredCarrierSignalReceivers()) {
+ // carrierSignal Receivers will place the carrier-specific provisioning notification
+ misc.provisioningNotificationDisabled = true;
+ }
misc.subscriberId = mPhone.getSubscriberId();
if (createNetworkAgent) {
@@ -1811,7 +1817,6 @@
and let DcTracker to make the decision */
Message msg = mDct.obtainMessage(DctConstants.EVENT_REDIRECTION_DETECTED,
redirectUrl);
- AsyncResult.forMessage(msg, mApnContexts, null);
msg.sendToTarget();
}
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 9862e9c..7280f3a 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -27,7 +27,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
@@ -48,7 +47,6 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
-import android.os.PersistableBundle;
import android.os.RegistrantList;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -57,13 +55,12 @@
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.provider.Telephony;
-import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
-import android.telephony.SubscriptionInfo;
-import android.telephony.TelephonyManager;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
@@ -72,24 +69,22 @@
import android.util.Pair;
import android.util.SparseArray;
import android.view.WindowManager;
-import android.telephony.Rlog;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.GsmCdmaPhone;
-import com.android.internal.telephony.Phone;
import com.android.internal.telephony.DctConstants;
import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.GsmCdmaPhone;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.SubscriptionController;
+import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.UiccController;
-import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
-import com.android.internal.util.AsyncChannel;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.AsyncChannel;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -108,9 +103,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import java.lang.StringBuilder;
-
-import com.android.internal.telephony.ServiceStateTracker;
/**
* {@hide}
*/
@@ -174,10 +166,6 @@
private static final String INTENT_DATA_STALL_ALARM =
"com.android.internal.telephony.data-stall";
- private static final String REDIRECTION_URL_KEY = "redirectionUrl";
- private static final String ERROR_CODE_KEY = "errorCode";
- private static final String APN_TYPE_KEY = "apnType";
-
@VisibleForTesting
public static class DataAllowFailReason {
private HashSet<DataAllowFailReasonType> mDataAllowFailReasonSet = new HashSet<>();
@@ -372,8 +360,6 @@
int subId = mPhone.getSubId();
if (SubscriptionManager.isValidSubscriptionId(subId)) {
registerSettingsObserver();
- /* check if sim is un-provisioned */
- applyUnProvisionedSimDetected();
}
if (mPreviousSubId.getAndSet(subId) != subId &&
SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -627,21 +613,10 @@
private int mDisconnectPendingCount = 0;
- /** mRedirectUrl is set when we got the validation failure with the redirection URL
- * based on which we start the Carrier App to check the sim state */
- private String mRedirectUrl = null;
-
- /** mColdSimDetected is set to true when we received SubInfoChanged &&
- * SubscriptionInfo.simProvisioningStatus equals to SIM_UNPROVISIONED_COLD */
- private boolean mColdSimDetected = false;
-
- /** mmOutOfCreditSimDetected is set to true when we received SubInfoChanged &&
- * SubscriptionInfo.simProvisioningStatus equals to SIM_UNPROVISIONED_OUT_OF_CREDIT */
- private boolean mOutOfCreditSimDetected = false;
-
- /** HashSet of ApnContext associated with redirected data-connection.
- * those apn contexts tear down upon redirection and re-establish upon non-cold sim detection */
- private HashSet<ApnContext> redirectApnContextSet = new HashSet<>();
+ /** Indicate if metered APNs are disabled.
+ * set to block all the metered APNs from continuously sending requests, which causes
+ * undesired network load */
+ private boolean mMeteredApnDisabled = false;
/**
* Handles changes to the APN db.
@@ -975,44 +950,6 @@
return true;
}
- /**
- * Called when there is any change to any SubscriptionInfo Typically
- * this method invokes {@link SubscriptionManager#getActiveSubscriptionInfoList}
- */
- private boolean isColdSimDetected() {
- int subId = mPhone.getSubId();
- if(SubscriptionManager.isValidSubscriptionId(subId)) {
- final SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
- if (subInfo != null) {
- final int simProvisioningStatus = subInfo.getSimProvisioningStatus();
- if (simProvisioningStatus == SubscriptionManager.SIM_UNPROVISIONED_COLD) {
- log("Cold Sim Detected on SubId: " + subId);
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Called when there is any change to any SubscriptionInfo Typically
- * this method invokes {@link SubscriptionManager#getActiveSubscriptionInfoList}
- */
- private boolean isOutOfCreditSimDetected() {
- int subId = mPhone.getSubId();
- if(SubscriptionManager.isValidSubscriptionId(subId)) {
- final SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
- if (subInfo != null) {
- final int simProvisioningStatus = subInfo.getSimProvisioningStatus();
- if (simProvisioningStatus == SubscriptionManager.SIM_UNPROVISIONED_OUT_OF_CREDIT) {
- log("Out Of Credit Sim Detected on SubId: " + subId);
- return true;
- }
- }
- }
- return false;
- }
-
public int getApnPriority(String name) {
ApnContext apnContext = mApnContexts.get(name);
if (apnContext == null) {
@@ -1340,7 +1277,8 @@
private boolean isDataEnabled(boolean checkUserDataEnabled) {
synchronized (mDataEnabledLock) {
if (!(mInternalDataEnabled && (!checkUserDataEnabled || mUserDataEnabled)
- && (!checkUserDataEnabled || sPolicyDataEnabled)))
+ && (!checkUserDataEnabled || sPolicyDataEnabled)
+ && (!checkUserDataEnabled || !mMeteredApnDisabled)))
return false;
}
return true;
@@ -1590,7 +1528,7 @@
if (apnContext.isConnectable() && (isEmergencyApn ||
(isDataAllowed && isDataAllowedForApn(apnContext) &&
- isDataEnabled(checkUserDataEnabled) && !isEmergency())) && !mColdSimDetected ) {
+ isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
if (apnContext.getState() == DctConstants.State.FAILED) {
String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
if (DBG) log(str);
@@ -1651,14 +1589,12 @@
if (!isDataEnabled(checkUserDataEnabled)) {
str.append("isDataEnabled(" + checkUserDataEnabled + ") = false. " +
"mInternalDataEnabled = " + mInternalDataEnabled + " , mUserDataEnabled = "
- + mUserDataEnabled + ", sPolicyDataEnabled = " + sPolicyDataEnabled + " ");
+ + mUserDataEnabled + ", sPolicyDataEnabled = " + sPolicyDataEnabled +
+ ", mMeteredApnDisabled = " + mMeteredApnDisabled);
}
if (isEmergency()) {
str.append("emergency = true");
}
- if(mColdSimDetected) {
- str.append("coldSimDetected = true");
- }
if (DBG) log(str.toString());
apnContext.requestLog(str.toString());
@@ -1704,17 +1640,18 @@
private boolean cleanUpAllConnections(boolean tearDown, String reason) {
if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
boolean didDisconnect = false;
- boolean specificDisable = false;
+ boolean disableMeteredOnly = false;
- // Either user disable mobile data or under roaming service and user disabled roaming
+ // reasons that only metered apn will be torn down
if (!TextUtils.isEmpty(reason)) {
- specificDisable = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) ||
- reason.equals(Phone.REASON_ROAMING_ON);
+ disableMeteredOnly = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) ||
+ reason.equals(Phone.REASON_ROAMING_ON) ||
+ reason.equals(Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
}
for (ApnContext apnContext : mApnContexts.values()) {
if (apnContext.isDisconnected() == false) didDisconnect = true;
- if (specificDisable) {
+ if (disableMeteredOnly) {
// Use ApnSetting to decide metered or non-metered.
// Tear down all metered data connections.
ApnSetting apnSetting = apnContext.getApnSetting();
@@ -2403,35 +2340,38 @@
setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
}
- private void applyUnProvisionedSimDetected() {
- if(isColdSimDetected()) {
- if(!mColdSimDetected) {
- if(DBG) {
- log("onColdSimDetected: cleanUpAllDataConnections");
- }
- cleanUpAllConnections(null);
- //send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
+ /**
+ * Action set from carrier signalling broadcast receivers to enable/disable metered apns.
+ */
+ public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
+ if (enabled == mMeteredApnDisabled) {
+ if (DBG) {
+ log("carrier Action: set metered apns enabled: " + enabled);
+ }
+ // Disable/enable all metered apns
+ mMeteredApnDisabled = !enabled;
+ if (!enabled) {
+ // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
mPhone.notifyOtaspChanged(ServiceStateTracker.OTASP_SIM_UNPROVISIONED);
- mColdSimDetected = true;
+ // Tear down all metered apns
+ cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
+ } else {
+ setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
}
- } else if (isOutOfCreditSimDetected()) {
- if(!mOutOfCreditSimDetected) {
- if(DBG) {
- log("onOutOfCreditSimDetected on subId: re-establish data connection");
- }
- for (ApnContext context : redirectApnContextSet) {
- onTrySetupData(context);
- redirectApnContextSet.remove(context);
- }
- mOutOfCreditSimDetected = true;
- }
- } else {
- if (DBG) log("Provisioned Sim Detected on subId: " + mPhone.getSubId() );
- mColdSimDetected = false;
- mOutOfCreditSimDetected = false;
}
}
+ /**
+ * Action set from carrier signalling broadcast receivers to enable/disable radio
+ */
+ public void carrierActionSetRadioEnabled(boolean enabled) {
+ if (DBG) {
+ log("carrier Action: set radio enabled: " + enabled);
+ }
+ final ServiceStateTracker sst = mPhone.getServiceStateTracker();
+ sst.setRadioPowerFromCarrier(enabled);
+ }
+
private void onSimNotReady() {
if (DBG) log("onSimNotReady");
@@ -2984,6 +2924,16 @@
log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()
+ ", reason:" + apnContext.getReason());
}
+ if (Build.IS_DEBUGGABLE) {
+ // adb shell setprop persist.radio.test.pco [pco_val]
+ String radioTestProperty = "persist.radio.test.pco";
+ int pcoVal = SystemProperties.getInt(radioTestProperty, 0);
+ log("PCO testing: read pco value from persist.radio.test.pco " + pcoVal);
+ Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE);
+ intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnContext.getApnType());
+ intent.putExtra(TelephonyIntents.EXTRA_PCO_KEY, pcoVal);
+ mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
+ }
}
} else {
cause = (DcFailCause) (ar.result);
@@ -3002,11 +2952,12 @@
mPhone.notifyPreciseDataConnectionFailed(apnContext.getReason(),
apnContext.getApnType(), apn != null ? apn.apn : "unknown", cause.toString());
- //compose broadcast intent send to the specific carrier apps
- Intent intent = new Intent(TelephonyIntents.ACTION_REQUEST_NETWORK_FAILED);
- intent.putExtra(ERROR_CODE_KEY, cause.getErrorCode());
- intent.putExtra(APN_TYPE_KEY, apnContext.getApnType());
- notifyCarrierAppWithIntent(intent);
+ // Compose broadcast intent send to the specific carrier signaling receivers
+ Intent intent = new Intent(TelephonyIntents
+ .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED);
+ intent.putExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY, cause.getErrorCode());
+ intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnContext.getApnType());
+ mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
if (cause.isRestartRadioFail() || apnContext.restartOnError(cause.getErrorCode())) {
if (DBG) log("Modem restarted.");
@@ -3092,48 +3043,14 @@
}
/**
- * Read Carrier App name from CarrierConfig
- * @return String[0] Package name, String[1] Activity name
- */
- private String[] getActivationAppName() {
- CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle b = null;
- String[] activationApp;
-
- if (configManager != null) {
- b = configManager.getConfig();
- }
- if (b != null) {
- activationApp = b.getStringArray(CarrierConfigManager
- .KEY_SIM_PROVISIONING_STATUS_DETECTION_CARRIER_APP_STRING_ARRAY);
- } else {
- // Return static default defined in CarrierConfigManager.
- activationApp = CarrierConfigManager.getDefaultConfig().getStringArray
- (CarrierConfigManager
- .KEY_SIM_PROVISIONING_STATUS_DETECTION_CARRIER_APP_STRING_ARRAY);
- }
- return activationApp;
- }
-
- /**
* Called when EVENT_REDIRECTION_DETECTED is received.
*/
- private void onDataConnectionRedirected(String redirectUrl,
- HashMap<ApnContext, ConnectionParams> apnContextMap) {
+ private void onDataConnectionRedirected(String redirectUrl) {
if (!TextUtils.isEmpty(redirectUrl)) {
- mRedirectUrl = redirectUrl;
- Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_REDIRECTED);
- intent.putExtra(REDIRECTION_URL_KEY, redirectUrl);
- if(!isColdSimDetected() && !isOutOfCreditSimDetected()
- && checkCarrierAppAvailable(intent)) {
- log("Starting Activation Carrier app with redirectUrl : " + redirectUrl);
-
- // Tear down data connections for all apn types
- for(ApnContext context : apnContextMap.keySet()) {
- cleanUpConnection(true, context);
- redirectApnContextSet.add(context);
- }
+ Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
+ intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, redirectUrl);
+ if(mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent)) {
+ log("Notify carrier signal receivers with redirectUrl: " + redirectUrl);
}
}
}
@@ -3168,8 +3085,6 @@
if (mDisconnectPendingCount == 0) {
notifyDataDisconnectComplete();
notifyAllDataDisconnected();
- // Notify carrier app with redirection when there is no pending disconnect req
- notifyCarrierAppForRedirection();
}
return;
}
@@ -3217,8 +3132,6 @@
mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed());
notifyDataDisconnectComplete();
notifyAllDataDisconnected();
- // Notify carrier app with redirection when there is no pending disconnect req
- notifyCarrierAppForRedirection();
}
}
@@ -3835,10 +3748,9 @@
break;
case DctConstants.EVENT_REDIRECTION_DETECTED:
- AsyncResult ar = (AsyncResult) msg.obj;
- String url = (String) ar.userObj;
+ String url = (String) msg.obj;
log("dataConnectionTracker.handleMessage: EVENT_REDIRECTION_DETECTED=" + url);
- onDataConnectionRedirected(url, (HashMap<ApnContext, ConnectionParams>) ar.result);
+ onDataConnectionRedirected(url);
case DctConstants.EVENT_RADIO_AVAILABLE:
onRadioAvailable();
@@ -4090,8 +4002,11 @@
mIccRecords.set(newIccRecords);
newIccRecords.registerForRecordsLoaded(
this, DctConstants.EVENT_RECORDS_LOADED, null);
- SubscriptionController.getInstance().setSimProvisioningStatus(
- SubscriptionManager.SIM_PROVISIONED, mPhone.getSubId());
+ // reset carrier actions on sim loaded
+ final ServiceStateTracker sst = mPhone.getServiceStateTracker();
+ sst.setRadioPowerFromCarrier(true);
+ mMeteredApnDisabled = false;
+ mPhone.getCarrierSignalAgent().reset();
}
} else {
onSimNotReady();
@@ -4129,60 +4044,6 @@
sendMessage(msg);
}
- private boolean checkCarrierAppAvailable(Intent intent) {
- // Read from carrier config manager
- String[] activationApp = getActivationAppName();
- if(activationApp == null || activationApp.length != 2) {
- return false;
- }
-
- intent.setClassName(activationApp[0], activationApp[1]);
- // Check if activation app is available
- final PackageManager packageManager = mPhone.getContext().getPackageManager();
- if (packageManager.queryBroadcastReceivers(intent,
- PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
- loge("Activation Carrier app is configured, but not available: "
- + activationApp[0] + "." + activationApp[1]);
- return false;
- }
- return true;
- }
-
- private boolean notifyCarrierAppWithIntent(Intent intent) {
- // RIL has limitation to process new request while there is pending deactivation requests
- // Make sure there is no pending disconnect before launching carrier app
- if (mDisconnectPendingCount != 0) {
- loge("Wait for pending disconnect requests done");
- return false;
- }
- if (!checkCarrierAppAvailable(intent)) {
- loge("Carrier app is unavailable");
- return false;
- }
-
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mPhone.getSubId());
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-
- try {
- mPhone.getContext().sendBroadcast(intent);
- } catch (ActivityNotFoundException e) {
- loge("sendBroadcast failed: " + e);
- return false;
- }
-
- if (DBG) log("send Intent to Carrier app with action: " + intent.getAction());
- return true;
- }
-
- private void notifyCarrierAppForRedirection() {
- // Notify carrier app with redirectionUrl
- if (!isColdSimDetected() && !isOutOfCreditSimDetected() && mRedirectUrl != null) {
- Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_REDIRECTED);
- intent.putExtra(REDIRECTION_URL_KEY, mRedirectUrl);
- if (notifyCarrierAppWithIntent(intent)) mRedirectUrl = null;
- }
- }
-
private void notifyDataDisconnectComplete() {
log("notifyDataDisconnectComplete");
for (Message m: mDisconnectAllCompleteMsgList) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index f8f9ac9..3993e7b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -488,6 +488,8 @@
}).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());
doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
+ //doReturn(mBundle).when(mCarrierConfigManager).getConfig(anyInt());
+ doReturn(mBundle).when(mCarrierConfigManager).getConfig();
mConfiguration.locale = Locale.US;
doReturn(mConfiguration).when(mResources).getConfiguration();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
index 50e557f..ac97937 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java
@@ -35,8 +35,7 @@
@Before
public void setUp() throws Exception {
mSubscriptionInfoUT = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, "T-mobile",
- "T-mobile", 0, 255, "12345", 0, null, 310, 260, "156",
- SubscriptionManager.SIM_PROVISIONED);
+ "T-mobile", 0, 255, "12345", 0, null, 310, 260, "156");
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 2452069..976f418 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -44,6 +44,7 @@
import android.provider.BlockedNumberContract;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.util.Log;
@@ -169,8 +170,12 @@
protected EriManager mEriManager;
@Mock
protected IBinder mConnMetLoggerBinder;
+ @Mock
+ protected CarrierSignalAgent mCarrierSignalAgent;
protected TelephonyManager mTelephonyManager;
+ protected SubscriptionManager mSubscriptionManager;
+ protected PackageManager mPackageManager;
protected SimulatedCommands mSimulatedCommands;
protected ContextFixture mContextFixture;
protected Context mContext;
@@ -299,6 +304,9 @@
mPhone.mCi = mSimulatedCommands;
mCT.mCi = mSimulatedCommands;
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ mSubscriptionManager = (SubscriptionManager) mContext.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ mPackageManager = mContext.getPackageManager();
replaceInstance(TelephonyManager.class, "sInstance", null,
mContext.getSystemService(Context.TELEPHONY_SERVICE));
@@ -344,6 +352,7 @@
doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mPhone).getPhoneType();
doReturn(mCT).when(mPhone).getCallTracker();
doReturn(mSST).when(mPhone).getServiceStateTracker();
+ doReturn(mCarrierSignalAgent).when(mPhone).getCarrierSignalAgent();
mPhone.mEriManager = mEriManager;
//mUiccController
@@ -443,8 +452,7 @@
}
protected void setupMockPackagePermissionChecks() throws Exception {
- PackageManager mockPackageManager = mContext.getPackageManager();
- doReturn(new String[]{TAG}).when(mockPackageManager).getPackagesForUid(anyInt());
- doReturn(mPackageInfo).when(mockPackageManager).getPackageInfo(eq(TAG), anyInt());
+ doReturn(new String[]{TAG}).when(mPackageManager).getPackagesForUid(anyInt());
+ doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(eq(TAG), anyInt());
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index a014980..772905b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -35,6 +35,8 @@
import android.provider.Telephony;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.MediumTest;
@@ -53,6 +55,8 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -72,6 +76,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -103,6 +108,8 @@
IBinder mBinder;
@Mock
NetworkRequest mNetworkRequest;
+ @Mock
+ SubscriptionInfo mSubscriptionInfo;
private DcTracker mDct;
@@ -110,6 +117,8 @@
private PersistableBundle mBundle;
+ private SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
+
private final ApnSettingContentProvider mApnSettingContentProvider =
new ApnSettingContentProvider();
@@ -299,6 +308,18 @@
doReturn(true).when(mSimRecords).getRecordsLoaded();
doReturn(PhoneConstants.State.IDLE).when(mCT).getState();
doReturn(true).when(mSST).getDesiredPowerState();
+ doAnswer(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ mOnSubscriptionsChangedListener =
+ (SubscriptionManager.OnSubscriptionsChangedListener)
+ invocation.getArguments()[0];
+ return null;
+ }
+ }
+ ).when(mSubscriptionManager).addOnSubscriptionsChangedListener(any());
+ doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
doReturn(1).when(mIsub).getDefaultDataSubId();
doReturn(mIsub).when(mBinder).queryLocalInterface(anyString());
@@ -739,4 +760,51 @@
allowed = isDataAllowed(failureReason);
assertFalse(failureReason.getDataAllowFailReason(), allowed);
}
+
+ // Test for API carrierActionSetMeteredApnsEnabled.
+ @Test
+ @MediumTest
+ public void testCarrierActionSetMeteredApnsEnabled() throws Exception {
+ //step 1: setup two DataCalls one for Internet and IMS
+ //step 2: set data is enabled
+ //step 3: cold sim is detected
+ //step 4: all data connection is torn down
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+
+ boolean dataEnabled = mDct.getDataEnabled();
+ mDct.setDataEnabled(true);
+
+ mDct.setEnabled(5, true);
+ mDct.setEnabled(0, true);
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+ eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), eq(2), eq(FAKE_APN3),
+ eq(""), eq(""), eq(3), eq("IP"), any(Message.class));
+ verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+ eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), eq(0), eq(FAKE_APN1),
+ eq(""), eq(""), eq(0), eq("IP"), any(Message.class));
+ assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
+
+ mDct.carrierActionSetMeteredApnsEnabled(false);
+ waitForMs(100);
+
+ // Validate all metered data connections have been torn down
+ verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(anyInt(), anyInt(),
+ any(Message.class));
+ assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
+ assertEquals(DctConstants.State.IDLE, mDct.getState(PhoneConstants.APN_TYPE_DEFAULT));
+
+ // Reset settings at the end of test
+ mDct.setDataEnabled(dataEnabled);
+ waitForMs(200);
+ }
}