Merge "Move Keepalive out of IpSecTransform.Builder"
diff --git a/api/current.txt b/api/current.txt
index 7954bf5..33d3bb9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -39995,6 +39995,8 @@
method public void notifyConfigChangedForSubId(int);
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
+ field public static final java.lang.String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
+ field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
diff --git a/api/system-current.txt b/api/system-current.txt
index 67aa62b..2e39bb7f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4124,6 +4124,7 @@
method public int getSimApplicationState();
method public int getSimCardState();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
+ method public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
method public android.os.Bundle getVisualVoicemailSettings();
method public boolean handlePinMmi(java.lang.String);
method public boolean handlePinMmiForSubscriber(int, java.lang.String);
@@ -4145,6 +4146,7 @@
method public int[] supplyPinReportResult(java.lang.String);
method public boolean supplyPuk(java.lang.String, java.lang.String);
method public int[] supplyPukReportResult(java.lang.String, java.lang.String);
+ method public boolean switchSlots(int[]);
method public void toggleRadioOnOff();
method public void updateServiceLocation();
field public static final java.lang.String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
@@ -4161,6 +4163,25 @@
field public static final int SIM_STATE_PRESENT = 11; // 0xb
}
+ public class UiccSlotInfo implements android.os.Parcelable {
+ ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int);
+ method public int describeContents();
+ method public java.lang.String getCardId();
+ method public int getCardStateInfo();
+ method public boolean getIsActive();
+ method public boolean getIsEuicc();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1
+ field public static final int CARD_STATE_INFO_ERROR = 3; // 0x3
+ field public static final int CARD_STATE_INFO_PRESENT = 2; // 0x2
+ field public static final int CARD_STATE_INFO_RESTRICTED = 4; // 0x4
+ field public static final android.os.Parcelable.Creator<android.telephony.UiccSlotInfo> CREATOR;
+ field public final java.lang.String cardId;
+ field public final int cardStateInfo;
+ field public final boolean isActive;
+ field public final boolean isEuicc;
+ }
+
public abstract class VisualVoicemailService extends android.app.Service {
method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 31516fd..e81ed9a 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -892,7 +892,7 @@
*
* @hide
*/
- private Set<UidRange> mUids = null;
+ private ArraySet<UidRange> mUids = null;
/**
* Convenience method to set the UIDs this network applies to to a single UID.
@@ -1180,7 +1180,7 @@
dest.writeInt(mLinkDownBandwidthKbps);
dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
dest.writeInt(mSignalStrength);
- dest.writeArraySet(new ArraySet<>(mUids));
+ dest.writeArraySet(mUids);
}
public static final Creator<NetworkCapabilities> CREATOR =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ed68276..7ad4373 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8646,13 +8646,52 @@
public static final String RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS =
"recommended_network_evaluator_cache_expiry_ms";
- /**
+ /**
* Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
* connectivity.
* @hide
*/
- public static final String BLE_SCAN_ALWAYS_AVAILABLE =
- "ble_scan_always_enabled";
+ public static final String BLE_SCAN_ALWAYS_AVAILABLE = "ble_scan_always_enabled";
+
+ /**
+ * The length in milliseconds of a BLE scan window in a low-power scan mode.
+ * @hide
+ */
+ public static final String BLE_SCAN_LOW_POWER_WINDOW_MS = "ble_scan_low_power_window_ms";
+
+ /**
+ * The length in milliseconds of a BLE scan window in a balanced scan mode.
+ * @hide
+ */
+ public static final String BLE_SCAN_BALANCED_WINDOW_MS = "ble_scan_balanced_window_ms";
+
+ /**
+ * The length in milliseconds of a BLE scan window in a low-latency scan mode.
+ * @hide
+ */
+ public static final String BLE_SCAN_LOW_LATENCY_WINDOW_MS =
+ "ble_scan_low_latency_window_ms";
+
+ /**
+ * The length in milliseconds of a BLE scan interval in a low-power scan mode.
+ * @hide
+ */
+ public static final String BLE_SCAN_LOW_POWER_INTERVAL_MS =
+ "ble_scan_low_power_interval_ms";
+
+ /**
+ * The length in milliseconds of a BLE scan interval in a balanced scan mode.
+ * @hide
+ */
+ public static final String BLE_SCAN_BALANCED_INTERVAL_MS =
+ "ble_scan_balanced_interval_ms";
+
+ /**
+ * The length in milliseconds of a BLE scan interval in a low-latency scan mode.
+ * @hide
+ */
+ public static final String BLE_SCAN_LOW_LATENCY_INTERVAL_MS =
+ "ble_scan_low_latency_interval_ms";
/**
* Used to save the Wifi_ON state prior to tethering.
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 9167076..d0f5ba7 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -55,6 +55,8 @@
public static final int DISABLE_VERIFIER = 1 << 9;
/** Only use oat files located in /system. Otherwise use dex/jar/apk . */
public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10;
+ /** Do not enfore hidden API access restrictions. */
+ public static final int DISABLE_HIDDEN_API_CHECKS = 1 << 11;
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = 0;
@@ -158,6 +160,9 @@
*/
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
+ // SystemServer is always allowed to use hidden APIs.
+ runtimeFlags |= DISABLE_HIDDEN_API_CHECKS;
+
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 19808ca..ee276ef11 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -111,6 +111,12 @@
Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
+ Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS,
+ Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS,
+ Settings.Global.BLE_SCAN_BALANCED_WINDOW_MS,
+ Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS,
+ Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
+ Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index e3740e3..7ad062a 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -163,7 +163,7 @@
/**
* Create a drawable by opening a given file path and decoding the bitmap.
*/
- @SuppressWarnings("unused")
+ @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, String filepath) {
this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
mBitmapState.mTargetDensity = mTargetDensity;
@@ -188,7 +188,7 @@
/**
* Create a drawable by decoding a bitmap from the given input stream.
*/
- @SuppressWarnings("unused")
+ @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, java.io.InputStream is) {
this(new BitmapState(BitmapFactory.decodeStream(is)), null);
mBitmapState.mTargetDensity = mTargetDensity;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 002381a..d3fb087 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3877,6 +3877,12 @@
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
+ if (app.info.isAllowedToUseHiddenApi()) {
+ // This app is allowed to use undocumented and private APIs. Set
+ // up its runtime with the appropriate flag.
+ runtimeFlags |= Zygote.DISABLE_HIDDEN_API_CHECKS;
+ }
+
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 7b171b3..69dec2d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -495,6 +495,7 @@
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final long ident = Binder.clearCallingIdentity();
try {
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index f59871b..94ed218 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -39,13 +39,29 @@
private final static String TAG = "CarrierConfigManager";
/**
+ * Extra included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate the slot index that the
+ * broadcast is for.
+ */
+ public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
+
+ /**
+ * Optional extra included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate the
+ * subscription index that the broadcast is for, if a valid one is available.
+ */
+ public static final String EXTRA_SUBSCRIPTION_INDEX =
+ SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX;
+
+ /**
* @hide
*/
public CarrierConfigManager() {
}
/**
- * This intent is broadcast by the system when carrier config changes.
+ * This intent is broadcast by the system when carrier config changes. An int is specified in
+ * {@link #EXTRA_SLOT_INDEX} to indicate the slot index that this is for. An optional int extra
+ * {@link #EXTRA_SUBSCRIPTION_INDEX} is included to indicate the subscription index if a valid
+ * one is available for the slot index.
*/
public static final String
ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 04cbbd8..ada697f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -22,14 +22,13 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
-import android.annotation.SuppressLint;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.app.PendingIntent;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
@@ -43,7 +42,6 @@
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.service.carrier.CarrierIdentifier;
import android.telecom.PhoneAccount;
@@ -62,7 +60,6 @@
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.ITelephonyRegistry;
-import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyProperties;
@@ -2561,6 +2558,53 @@
}
}
+ /**
+ * Gets all the UICC slots.
+ *
+ * @return UiccSlotInfo array.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public UiccSlotInfo[] getUiccSlotsInfo() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ return null;
+ }
+ return telephony.getUiccSlotsInfo();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive. For
+ * example, passing the physicalSlots array [1, 0] means mapping the first item 1, which is
+ * physical slot index 1, to the logical slot 0; and mapping the second item 0, which is
+ * physical slot index 0, to the logical slot 1. The index of the array means the index of the
+ * logical slots.
+ *
+ * @param physicalSlots Index i in the array representing physical slot for phone i. The array
+ * size should be same as {@link #getPhoneCount()}.
+ * @return boolean Return true if the switch succeeds, false if the switch fails.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean switchSlots(int[] physicalSlots) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ return false;
+ }
+ return telephony.switchSlots(physicalSlots);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
//
//
// Subscriber Info
diff --git a/telephony/java/android/telephony/UiccSlotInfo.aidl b/telephony/java/android/telephony/UiccSlotInfo.aidl
new file mode 100644
index 0000000..5571a6c
--- /dev/null
+++ b/telephony/java/android/telephony/UiccSlotInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 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 android.telephony;
+
+parcelable UiccSlotInfo;
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
new file mode 100644
index 0000000..0b3cbad
--- /dev/null
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 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 android.telephony;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+import android.annotation.IntDef;
+
+/**
+ * Class for the information of a UICC slot.
+ * @hide
+ */
+@SystemApi
+public class UiccSlotInfo implements Parcelable {
+ /**
+ * Card state.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "CARD_STATE_INFO_" }, value = {
+ CARD_STATE_INFO_ABSENT,
+ CARD_STATE_INFO_PRESENT,
+ CARD_STATE_INFO_ERROR,
+ CARD_STATE_INFO_RESTRICTED
+ })
+ public @interface CardStateInfo {}
+
+ /** Card state absent. */
+ public static final int CARD_STATE_INFO_ABSENT = 1;
+
+ /** Card state present. */
+ public static final int CARD_STATE_INFO_PRESENT = 2;
+
+ /** Card state error. */
+ public static final int CARD_STATE_INFO_ERROR = 3;
+
+ /** Card state restricted. */
+ public static final int CARD_STATE_INFO_RESTRICTED = 4;
+
+ public final boolean isActive;
+ public final boolean isEuicc;
+ public final String cardId;
+ public final @CardStateInfo int cardStateInfo;
+
+ public static final Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() {
+ @Override
+ public UiccSlotInfo createFromParcel(Parcel in) {
+ return new UiccSlotInfo(in);
+ }
+
+ @Override
+ public UiccSlotInfo[] newArray(int size) {
+ return new UiccSlotInfo[size];
+ }
+ };
+
+ private UiccSlotInfo(Parcel in) {
+ isActive = in.readByte() != 0;
+ isEuicc = in.readByte() != 0;
+ cardId = in.readString();
+ cardStateInfo = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByte((byte) (isActive ? 1 : 0));
+ dest.writeByte((byte) (isEuicc ? 1 : 0));
+ dest.writeString(cardId);
+ dest.writeInt(cardStateInfo);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId,
+ @CardStateInfo int cardStateInfo) {
+ this.isActive = isActive;
+ this.isEuicc = isEuicc;
+ this.cardId = cardId;
+ this.cardStateInfo = cardStateInfo;
+ }
+
+ public boolean getIsActive() {
+ return isActive;
+ }
+
+ public boolean getIsEuicc() {
+ return isEuicc;
+ }
+
+ public String getCardId() {
+ return cardId;
+ }
+
+ @CardStateInfo
+ public int getCardStateInfo() {
+ return cardStateInfo;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+
+ UiccSlotInfo that = (UiccSlotInfo) obj;
+ return (isActive == that.isActive)
+ && (isEuicc == that.isEuicc)
+ && (cardId == that.cardId)
+ && (cardStateInfo == that.cardStateInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result = 31 * result + (isActive ? 1 : 0);
+ result = 31 * result + (isEuicc ? 1 : 0);
+ result = 31 * result + Objects.hashCode(cardId);
+ result = 31 * result + cardStateInfo;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "UiccSlotInfo (isActive="
+ + isActive
+ + ", isEuicc="
+ + isEuicc
+ + ", cardId="
+ + cardId
+ + ", cardState="
+ + cardStateInfo
+ + ")";
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index fba82ee..dfb3c34 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -47,6 +47,7 @@
import java.util.List;
+import android.telephony.UiccSlotInfo;
/**
* Interface used to interact with the phone. Mostly this is used by the
@@ -1444,4 +1445,19 @@
* @hide
*/
SignalStrength getSignalStrength(int subId);
+
+ /**
+ * Get slot info for all the UICC slots.
+ * @return UiccSlotInfo array.
+ * @hide
+ */
+ UiccSlotInfo[] getUiccSlotsInfo();
+
+ /**
+ * Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive.
+ * @param physicalSlots Index i in the array representing physical slot for phone i. The array
+ * size should be same as getPhoneCount().
+ * @return boolean Return true if the switch succeeds, false if the switch fails.
+ */
+ boolean switchSlots(in int[] physicalSlots);
}
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 9f8b3a8..c095438 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -837,6 +837,13 @@
}
/**
+ * Strip all the trailing 'F' characters of a string, e.g., an ICCID.
+ */
+ public static String stripTrailingFs(String s) {
+ return s == null ? null : s.replaceAll("(?i)f*$", "");
+ }
+
+ /**
* Converts a character of [0-9a-aA-F] to its hex value in a byte. If the character is not a
* hex number, 0 will be returned.
*/