Merge "Remodel Network Selection" into mm-wireless-dev
diff --git a/api/current.txt b/api/current.txt
index 19e58ae..e29d5ec 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19218,6 +19218,7 @@
method public java.lang.String getAltSubjectMatch();
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
+ method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
@@ -19230,6 +19231,7 @@
method public void setAltSubjectMatch(java.lang.String);
method public void setAnonymousIdentity(java.lang.String);
method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
@@ -30673,6 +30675,8 @@
public final class CellIdentityGsm implements android.os.Parcelable {
method public int describeContents();
+ method public int getArfcn();
+ method public int getBsic();
method public int getCid();
method public int getLac();
method public int getMcc();
@@ -30685,6 +30689,7 @@
public final class CellIdentityLte implements android.os.Parcelable {
method public int describeContents();
method public int getCi();
+ method public int getEarfcn();
method public int getMcc();
method public int getMnc();
method public int getPci();
@@ -30700,6 +30705,7 @@
method public int getMcc();
method public int getMnc();
method public int getPsc();
+ method public int getUarfcn();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 20c0560..47aeee3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -20994,6 +20994,7 @@
method public java.lang.String getAltSubjectMatch();
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
+ method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
@@ -21006,6 +21007,7 @@
method public void setAltSubjectMatch(java.lang.String);
method public void setAnonymousIdentity(java.lang.String);
method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
@@ -32920,6 +32922,8 @@
public final class CellIdentityGsm implements android.os.Parcelable {
method public int describeContents();
+ method public int getArfcn();
+ method public int getBsic();
method public int getCid();
method public int getLac();
method public int getMcc();
@@ -32932,6 +32936,7 @@
public final class CellIdentityLte implements android.os.Parcelable {
method public int describeContents();
method public int getCi();
+ method public int getEarfcn();
method public int getMcc();
method public int getMnc();
method public int getPci();
@@ -32947,6 +32952,7 @@
method public int getMcc();
method public int getMnc();
method public int getPsc();
+ method public int getUarfcn();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR;
}
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 90d2aa0..74f1171 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -38,6 +38,10 @@
private final int mLac;
// 16-bit GSM Cell Identity described in TS 27.007, 0..65535
private final int mCid;
+ // 16-bit GSM Absolute RF Channel Number
+ private final int mArfcn;
+ // 6-bit Base Station Identity Code
+ private final int mBsic;
/**
* @hide
@@ -47,6 +51,8 @@
mMnc = Integer.MAX_VALUE;
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
+ mArfcn = Integer.MAX_VALUE;
+ mBsic = Integer.MAX_VALUE;
}
/**
* public constructor
@@ -58,10 +64,27 @@
* @hide
*/
public CellIdentityGsm (int mcc, int mnc, int lac, int cid) {
+ this(mcc, mnc, lac, cid, Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * public constructor
+ * @param mcc 3-digit Mobile Country Code, 0..999
+ * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+ * @param lac 16-bit Location Area Code, 0..65535
+ * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
+ * @param arfcn 16-bit GSM Absolute RF Channel Number
+ * @param bsic 6-bit Base Station Identity Code
+ *
+ * @hide
+ */
+ public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int arfcn, int bsic) {
mMcc = mcc;
mMnc = mnc;
mLac = lac;
mCid = cid;
+ mArfcn = arfcn;
+ mBsic = bsic;
}
private CellIdentityGsm(CellIdentityGsm cid) {
@@ -69,6 +92,8 @@
mMnc = cid.mMnc;
mLac = cid.mLac;
mCid = cid.mCid;
+ mArfcn = cid.mArfcn;
+ mBsic = cid.mBsic;
}
CellIdentityGsm copy() {
@@ -106,6 +131,21 @@
}
/**
+ * @return 16-bit GSM Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+ */
+ public int getArfcn() {
+ return mArfcn;
+ }
+
+ /**
+ * @return 6-bit Base Station Identity Code, Integer.MAX_VALUE if unknown
+ */
+ public int getBsic() {
+ return mBsic;
+ }
+
+
+ /**
* @return Integer.MAX_VALUE, undefined for GSM
*/
@Deprecated
@@ -132,7 +172,9 @@
return mMcc == o.mMcc &&
mMnc == o.mMnc &&
mLac == o.mLac &&
- mCid == o.mCid;
+ mCid == o.mCid &&
+ mArfcn == o.mArfcn &&
+ mBsic == o.mBsic;
}
@Override
@@ -142,6 +184,8 @@
sb.append(" mMnc=").append(mMnc);
sb.append(" mLac=").append(mLac);
sb.append(" mCid=").append(mCid);
+ sb.append(" mArfcn=").append(mArfcn);
+ sb.append(" mBsic=").append("0x").append(Integer.toHexString(mBsic));
sb.append("}");
return sb.toString();
@@ -161,6 +205,8 @@
dest.writeInt(mMnc);
dest.writeInt(mLac);
dest.writeInt(mCid);
+ dest.writeInt(mArfcn);
+ dest.writeInt(mBsic);
}
/** Construct from Parcel, type has already been processed */
@@ -169,6 +215,8 @@
mMnc = in.readInt();
mLac = in.readInt();
mCid = in.readInt();
+ mArfcn = in.readInt();
+ mBsic = in.readInt();
if (DBG) log("CellIdentityGsm(Parcel): " + toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 1e7ac08..ce74383 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -40,6 +40,8 @@
private final int mPci;
// 16-bit tracking area code
private final int mTac;
+ // 18-bit Absolute RF Channel Number
+ private final int mEarfcn;
/**
* @hide
@@ -50,6 +52,7 @@
mCi = Integer.MAX_VALUE;
mPci = Integer.MAX_VALUE;
mTac = Integer.MAX_VALUE;
+ mEarfcn = Integer.MAX_VALUE;
}
/**
@@ -63,11 +66,27 @@
* @hide
*/
public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac) {
+ this(mcc, mnc, ci, pci, tac, Integer.MAX_VALUE);
+ }
+
+ /**
+ *
+ * @param mcc 3-digit Mobile Country Code, 0..999
+ * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+ * @param ci 28-bit Cell Identity
+ * @param pci Physical Cell Id 0..503
+ * @param tac 16-bit Tracking Area Code
+ * @param earfcn 18-bit LTE Absolute RF Channel Number
+ *
+ * @hide
+ */
+ public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac, int earfcn) {
mMcc = mcc;
mMnc = mnc;
mCi = ci;
mPci = pci;
mTac = tac;
+ mEarfcn = earfcn;
}
private CellIdentityLte(CellIdentityLte cid) {
@@ -76,6 +95,7 @@
mCi = cid.mCi;
mPci = cid.mPci;
mTac = cid.mTac;
+ mEarfcn = cid.mEarfcn;
}
CellIdentityLte copy() {
@@ -117,6 +137,13 @@
return mTac;
}
+ /**
+ * @return 18-bit Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+ */
+ public int getEarfcn() {
+ return mEarfcn;
+ }
+
@Override
public int hashCode() {
return Objects.hash(mMcc, mMnc, mCi, mPci, mTac);
@@ -137,7 +164,8 @@
mMnc == o.mMnc &&
mCi == o.mCi &&
mPci == o.mPci &&
- mTac == o.mTac;
+ mTac == o.mTac &&
+ mEarfcn == o.mEarfcn;
}
@Override
@@ -148,6 +176,7 @@
sb.append(" mCi="); sb.append(mCi);
sb.append(" mPci="); sb.append(mPci);
sb.append(" mTac="); sb.append(mTac);
+ sb.append(" mEarfcn="); sb.append(mEarfcn);
sb.append("}");
return sb.toString();
@@ -168,6 +197,7 @@
dest.writeInt(mCi);
dest.writeInt(mPci);
dest.writeInt(mTac);
+ dest.writeInt(mEarfcn);
}
/** Construct from Parcel, type has already been processed */
@@ -177,6 +207,7 @@
mCi = in.readInt();
mPci = in.readInt();
mTac = in.readInt();
+ mEarfcn = in.readInt();
if (DBG) log("CellIdentityLte(Parcel): " + toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 56ee8c9..0d13efd 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -40,6 +40,8 @@
private final int mCid;
// 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
private final int mPsc;
+ // 16-bit UMTS Absolute RF Channel Number
+ private final int mUarfcn;
/**
* @hide
@@ -50,6 +52,7 @@
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
mPsc = Integer.MAX_VALUE;
+ mUarfcn = Integer.MAX_VALUE;
}
/**
* public constructor
@@ -62,11 +65,27 @@
* @hide
*/
public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
+ this(mcc, mnc, lac, cid, psc, Integer.MAX_VALUE);
+ }
+
+ /**
+ * public constructor
+ * @param mcc 3-digit Mobile Country Code, 0..999
+ * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+ * @param lac 16-bit Location Area Code, 0..65535
+ * @param cid 28-bit UMTS Cell Identity
+ * @param psc 9-bit UMTS Primary Scrambling Code
+ * @param uarfcn 16-bit UMTS Absolute RF Channel Number
+ *
+ * @hide
+ */
+ public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc, int uarfcn) {
mMcc = mcc;
mMnc = mnc;
mLac = lac;
mCid = cid;
mPsc = psc;
+ mUarfcn = uarfcn;
}
private CellIdentityWcdma(CellIdentityWcdma cid) {
@@ -75,6 +94,7 @@
mLac = cid.mLac;
mCid = cid.mCid;
mPsc = cid.mPsc;
+ mUarfcn = cid.mUarfcn;
}
CellIdentityWcdma copy() {
@@ -123,6 +143,13 @@
return Objects.hash(mMcc, mMnc, mLac, mCid, mPsc);
}
+ /**
+ * @return 16-bit UMTS Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+ */
+ public int getUarfcn() {
+ return mUarfcn;
+ }
+
@Override
public boolean equals(Object other) {
if (this == other) {
@@ -138,7 +165,8 @@
mMnc == o.mMnc &&
mLac == o.mLac &&
mCid == o.mCid &&
- mPsc == o.mPsc;
+ mPsc == o.mPsc &&
+ mUarfcn == o.mUarfcn;
}
@Override
@@ -149,6 +177,7 @@
sb.append(" mLac=").append(mLac);
sb.append(" mCid=").append(mCid);
sb.append(" mPsc=").append(mPsc);
+ sb.append(" mUarfcn=").append(mUarfcn);
sb.append("}");
return sb.toString();
@@ -169,6 +198,7 @@
dest.writeInt(mLac);
dest.writeInt(mCid);
dest.writeInt(mPsc);
+ dest.writeInt(mUarfcn);
}
/** Construct from Parcel, type has already been processed */
@@ -178,6 +208,7 @@
mLac = in.readInt();
mCid = in.readInt();
mPsc = in.readInt();
+ mUarfcn = in.readInt();
if (DBG) log("CellIdentityWcdma(Parcel): " + toString());
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index d27fcec..addf7ef 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -34,6 +34,7 @@
private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+ private int mTimingAdvance;
/**
* Empty constructor
@@ -75,6 +76,22 @@
public void initialize(int ss, int ber) {
mSignalStrength = ss;
mBitErrorRate = ber;
+ mTimingAdvance = Integer.MAX_VALUE;
+ }
+
+ /**
+ * Initialize all the values
+ *
+ * @param ss SignalStrength as ASU value
+ * @param ber is Bit Error Rate
+ * @param ta timing advance
+ *
+ * @hide
+ */
+ public void initialize(int ss, int ber, int ta) {
+ mSignalStrength = ss;
+ mBitErrorRate = ber;
+ mTimingAdvance = ta;
}
/**
@@ -83,6 +100,7 @@
protected void copyFrom(CellSignalStrengthGsm s) {
mSignalStrength = s.mSignalStrength;
mBitErrorRate = s.mBitErrorRate;
+ mTimingAdvance = s.mTimingAdvance;
}
/**
@@ -98,6 +116,7 @@
public void setDefaultValues() {
mSignalStrength = Integer.MAX_VALUE;
mBitErrorRate = Integer.MAX_VALUE;
+ mTimingAdvance = Integer.MAX_VALUE;
}
/**
@@ -174,7 +193,8 @@
return false;
}
- return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate;
+ return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate &&
+ s.mTimingAdvance == mTimingAdvance;
}
/**
@@ -184,7 +204,8 @@
public String toString() {
return "CellSignalStrengthGsm:"
+ " ss=" + mSignalStrength
- + " ber=" + mBitErrorRate;
+ + " ber=" + mBitErrorRate
+ + " mTa=" + mTimingAdvance;
}
/** Implement the Parcelable interface */
@@ -193,6 +214,7 @@
if (DBG) log("writeToParcel(Parcel, int): " + toString());
dest.writeInt(mSignalStrength);
dest.writeInt(mBitErrorRate);
+ dest.writeInt(mTimingAdvance);
}
/**
@@ -202,6 +224,7 @@
private CellSignalStrengthGsm(Parcel in) {
mSignalStrength = in.readInt();
mBitErrorRate = in.readInt();
+ mTimingAdvance = in.readInt();
if (DBG) log("CellSignalStrengthGsm(Parcel): " + toString());
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index b089387..962a600 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1857,9 +1857,6 @@
// to the list.
number = extractNetworkPortionAlt(number);
- Rlog.d(LOG_TAG, "subId:" + subId + ", defaultCountryIso:" +
- ((defaultCountryIso == null) ? "NULL" : defaultCountryIso));
-
String emergencyNumbers = "";
int slotId = SubscriptionManager.getSlotId(subId);
@@ -1869,7 +1866,8 @@
emergencyNumbers = SystemProperties.get(ecclist, "");
- Rlog.d(LOG_TAG, "slotId:" + slotId + ", emergencyNumbers: " + emergencyNumbers);
+ Rlog.d(LOG_TAG, "slotId:" + slotId + " subId:" + subId + " country:"
+ + defaultCountryIso + " emergencyNumbers: " + emergencyNumbers);
if (TextUtils.isEmpty(emergencyNumbers)) {
// then read-only ecclist property since old RIL only uses this
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index c680999..ad007c6 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -37,6 +37,7 @@
static final String LOG_TAG = "PHONE";
static final boolean DBG = true;
+ static final boolean VDBG = false; // STOPSHIP if true
/**
* Normal operation condition, the phone is registered
@@ -829,7 +830,7 @@
/** @hide */
public void setDataRegState(int state) {
mDataRegState = state;
- if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
+ if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
}
public void setRoaming(boolean roaming) {
@@ -1017,7 +1018,8 @@
/** @hide */
public void setRilDataRadioTechnology(int rt) {
this.mRilDataRadioTechnology = rt;
- if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRadioTechnology=" + mRilDataRadioTechnology);
+ if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" +
+ mRilDataRadioTechnology);
}
/** @hide */
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3c4c04b..7d5645e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -336,6 +336,8 @@
int RIL_REQUEST_PULL_LCEDATA = 134;
int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
+ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
+
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 59b22bd..53efe6c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -15,12 +15,14 @@
*/
package android.net.wifi;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.security.Credentials;
import android.text.TextUtils;
import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -72,6 +74,13 @@
public static final String KEYSTORE_URI = "keystore://";
/**
+ * String representing the keystore URI used for wpa_supplicant,
+ * Unlike #KEYSTORE_URI, this supports a list of space-delimited aliases
+ * @hide
+ */
+ public static final String KEYSTORES_URI = "keystores://";
+
+ /**
* String to set the engine value to when it should be enabled.
* @hide
*/
@@ -103,6 +112,8 @@
public static final String PLMN_KEY = "plmn";
/** @hide */
public static final String PHASE1_KEY = "phase1";
+ /** @hide */
+ public static final String CA_CERT_ALIAS_DELIMITER = " ";
/** {@hide} */
public static final String ENABLE_TLS_1_2 = "\"tls_disable_tlsv1_2=0\"";
@@ -113,7 +124,7 @@
//By default, we enable TLS1.2. However, due to a known bug on some radius, we may disable it to
// fall back to TLS 1.1.
private boolean mTls12Enable = true;
- private X509Certificate mCaCert;
+ private X509Certificate[] mCaCerts;
private PrivateKey mClientPrivateKey;
private X509Certificate mClientCertificate;
@@ -145,7 +156,7 @@
dest.writeString(entry.getValue());
}
- writeCertificate(dest, mCaCert);
+ writeCertificates(dest, mCaCerts);
if (mClientPrivateKey != null) {
String algorithm = mClientPrivateKey.getAlgorithm();
@@ -161,6 +172,17 @@
dest.writeInt(mTls12Enable ? 1: 0);
}
+ private void writeCertificates(Parcel dest, X509Certificate[] cert) {
+ if (cert != null && cert.length != 0) {
+ dest.writeInt(cert.length);
+ for (int i = 0; i < cert.length; i++) {
+ writeCertificate(dest, cert[i]);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
private void writeCertificate(Parcel dest, X509Certificate cert) {
if (cert != null) {
try {
@@ -186,7 +208,7 @@
enterpriseConfig.mFields.put(key, value);
}
- enterpriseConfig.mCaCert = readCertificate(in);
+ enterpriseConfig.mCaCerts = readCertificates(in);
PrivateKey userKey = null;
int len = in.readInt();
@@ -210,6 +232,18 @@
return enterpriseConfig;
}
+ private X509Certificate[] readCertificates(Parcel in) {
+ X509Certificate[] certs = null;
+ int len = in.readInt();
+ if (len > 0) {
+ certs = new X509Certificate[len];
+ for (int i = 0; i < len; i++) {
+ certs[i] = readCertificate(in);
+ }
+ }
+ return certs;
+ }
+
private X509Certificate readCertificate(Parcel in) {
X509Certificate cert = null;
int len = in.readInt();
@@ -430,6 +464,36 @@
}
/**
+ * Encode a CA certificate alias so it does not contain illegal character.
+ * @hide
+ */
+ public static String encodeCaCertificateAlias(String alias) {
+ byte[] bytes = alias.getBytes(StandardCharsets.UTF_8);
+ StringBuilder sb = new StringBuilder(bytes.length * 2);
+ for (byte o : bytes) {
+ sb.append(String.format("%02x", o & 0xFF));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Decode a previously-encoded CA certificate alias.
+ * @hide
+ */
+ public static String decodeCaCertificateAlias(String alias) {
+ byte[] data = new byte[alias.length() >> 1];
+ for (int n = 0, position = 0; n < alias.length(); n += 2, position++) {
+ data[position] = (byte) Integer.parseInt(alias.substring(n, n + 2), 16);
+ }
+ try {
+ return new String(data, StandardCharsets.UTF_8);
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ return alias;
+ }
+ }
+
+ /**
* Set CA certificate alias.
*
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
@@ -443,6 +507,35 @@
}
/**
+ * Set CA certificate aliases. When creating installing the corresponding certificate to
+ * the keystore, please use alias encoded by {@link #encodeCaCertificateAlias(String)}.
+ *
+ * <p> See the {@link android.security.KeyChain} for details on installing or choosing
+ * a certificate.
+ * </p>
+ * @param aliases identifies the certificate
+ * @hide
+ */
+ public void setCaCertificateAliases(@Nullable String[] aliases) {
+ if (aliases == null) {
+ setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX);
+ } else if (aliases.length == 1) {
+ // Backwards compatibility: use the original cert prefix if setting only one alias.
+ setCaCertificateAlias(aliases[0]);
+ } else {
+ // Use KEYSTORES_URI which supports multiple aliases.
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < aliases.length; i++) {
+ if (i > 0) {
+ sb.append(CA_CERT_ALIAS_DELIMITER);
+ }
+ sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i]));
+ }
+ setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI);
+ }
+ }
+
+ /**
* Get CA certificate alias
* @return alias to the CA certificate
* @hide
@@ -452,6 +545,32 @@
}
/**
+ * Get CA certificate aliases
+ * @return alias to the CA certificate
+ * @hide
+ */
+ @Nullable public String[] getCaCertificateAliases() {
+ String value = getFieldValue(CA_CERT_KEY, "");
+ if (value.startsWith(CA_CERT_PREFIX)) {
+ // Backwards compatibility: parse the original alias prefix.
+ return new String[] {getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX)};
+ } else if (value.startsWith(KEYSTORES_URI)) {
+ String values = value.substring(KEYSTORES_URI.length());
+
+ String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER);
+ for (int i = 0; i < aliases.length; i++) {
+ aliases[i] = decodeCaCertificateAlias(aliases[i]);
+ if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) {
+ aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length());
+ }
+ }
+ return aliases.length != 0 ? aliases : null;
+ } else {
+ return TextUtils.isEmpty(value) ? null : new String[] {value};
+ }
+ }
+
+ /**
* Specify a X.509 certificate that identifies the server.
*
* <p>A default name is automatically assigned to the certificate and used
@@ -462,31 +581,76 @@
* @param cert X.509 CA certificate
* @throws IllegalArgumentException if not a CA certificate
*/
- public void setCaCertificate(X509Certificate cert) {
+ public void setCaCertificate(@Nullable X509Certificate cert) {
if (cert != null) {
if (cert.getBasicConstraints() >= 0) {
- mCaCert = cert;
+ mCaCerts = new X509Certificate[] {cert};
} else {
throw new IllegalArgumentException("Not a CA certificate");
}
} else {
- mCaCert = null;
+ mCaCerts = null;
}
}
/**
- * Get CA certificate
+ * Get CA certificate. If multiple CA certificates are configured previously,
+ * return the first one.
* @return X.509 CA certificate
*/
- public X509Certificate getCaCertificate() {
- return mCaCert;
+ @Nullable public X509Certificate getCaCertificate() {
+ if (mCaCerts != null && mCaCerts.length > 0) {
+ return mCaCerts[0];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Specify a list of X.509 certificates that identifies the server. The validation
+ * passes if the CA of server certificate matches one of the given certificates.
+
+ * <p>Default names are automatically assigned to the certificates and used
+ * with this configuration. The framework takes care of installing the
+ * certificates when the config is saved and removing the certificates when
+ * the config is removed.
+ *
+ * @param certs X.509 CA certificates
+ * @throws IllegalArgumentException if any of the provided certificates is
+ * not a CA certificate
+ */
+ public void setCaCertificates(@Nullable X509Certificate[] certs) {
+ if (certs != null) {
+ X509Certificate[] newCerts = new X509Certificate[certs.length];
+ for (int i = 0; i < certs.length; i++) {
+ if (certs[i].getBasicConstraints() >= 0) {
+ newCerts[i] = certs[i];
+ } else {
+ throw new IllegalArgumentException("Not a CA certificate");
+ }
+ }
+ mCaCerts = newCerts;
+ } else {
+ mCaCerts = null;
+ }
+ }
+
+ /**
+ * Get CA certificates.
+ */
+ @Nullable public X509Certificate[] getCaCertificates() {
+ if (mCaCerts != null || mCaCerts.length > 0) {
+ return mCaCerts;
+ } else {
+ return null;
+ }
}
/**
* @hide
*/
public void resetCaCertificate() {
- mCaCert = null;
+ mCaCerts = null;
}
/** Set Client certificate alias.