Merge changes I9de0ffe9,Idc804896
* changes:
Use sdkparcelables to generate framework.aidl
Initial sdkparcelables
diff --git a/Android.bp b/Android.bp
index 2c1fce3..eb5240e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -464,6 +464,7 @@
"telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl",
"telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl",
"telephony/java/android/telephony/ims/internal/aidl/IImsServiceControllerListener.aidl",
+ "telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl",
"telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl",
@@ -484,13 +485,11 @@
"telephony/java/com/android/ims/internal/IImsService.aidl",
"telephony/java/com/android/ims/internal/IImsServiceController.aidl",
"telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl",
- "telephony/java/com/android/ims/internal/IImsSmsFeature.aidl",
"telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl",
"telephony/java/com/android/ims/internal/IImsUt.aidl",
"telephony/java/com/android/ims/internal/IImsUtListener.aidl",
"telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl",
"telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl",
- "telephony/java/com/android/ims/internal/ISmsListener.aidl",
"telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl",
"telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl",
"telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl",
diff --git a/Android.mk b/Android.mk
index 5438bfa..5f07965 100644
--- a/Android.mk
+++ b/Android.mk
@@ -40,6 +40,10 @@
frameworks/base/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl \
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
frameworks/base/telephony/java/android/telephony/SubscriptionInfo.aidl \
+ frameworks/base/telephony/java/android/telephony/CellIdentityCdma.aidl \
+ frameworks/base/telephony/java/android/telephony/CellIdentityGsm.aidl \
+ frameworks/base/telephony/java/android/telephony/CellIdentityLte.aidl \
+ frameworks/base/telephony/java/android/telephony/CellIdentityWcdma.aidl \
frameworks/base/telephony/java/android/telephony/CellInfo.aidl \
frameworks/base/telephony/java/android/telephony/SignalStrength.aidl \
frameworks/base/telephony/java/android/telephony/IccOpenLogicalChannelResponse.aidl \
diff --git a/api/current.txt b/api/current.txt
index a07e1fd..e8d0ee2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7909,6 +7909,94 @@
method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
}
+ public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
+ method public boolean connect(android.bluetooth.BluetoothDevice);
+ method public boolean disconnect(android.bluetooth.BluetoothDevice);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceCallback);
+ method public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
+ method public boolean reportError(android.bluetooth.BluetoothDevice, byte);
+ method public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
+ method public boolean unregisterApp();
+ field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
+ field public static final byte ERROR_RSP_INVALID_PARAM = 4; // 0x4
+ field public static final byte ERROR_RSP_INVALID_RPT_ID = 2; // 0x2
+ field public static final byte ERROR_RSP_NOT_READY = 1; // 0x1
+ field public static final byte ERROR_RSP_SUCCESS = 0; // 0x0
+ field public static final byte ERROR_RSP_UNKNOWN = 14; // 0xe
+ field public static final byte ERROR_RSP_UNSUPPORTED_REQ = 3; // 0x3
+ field public static final byte PROTOCOL_BOOT_MODE = 0; // 0x0
+ field public static final byte PROTOCOL_REPORT_MODE = 1; // 0x1
+ field public static final byte REPORT_TYPE_FEATURE = 3; // 0x3
+ field public static final byte REPORT_TYPE_INPUT = 1; // 0x1
+ field public static final byte REPORT_TYPE_OUTPUT = 2; // 0x2
+ field public static final byte SUBCLASS1_COMBO = -64; // 0xffffffc0
+ field public static final byte SUBCLASS1_KEYBOARD = 64; // 0x40
+ field public static final byte SUBCLASS1_MOUSE = -128; // 0xffffff80
+ field public static final byte SUBCLASS1_NONE = 0; // 0x0
+ field public static final byte SUBCLASS2_CARD_READER = 6; // 0x6
+ field public static final byte SUBCLASS2_DIGITIZER_TABLET = 5; // 0x5
+ field public static final byte SUBCLASS2_GAMEPAD = 2; // 0x2
+ field public static final byte SUBCLASS2_JOYSTICK = 1; // 0x1
+ field public static final byte SUBCLASS2_REMOTE_CONTROL = 3; // 0x3
+ field public static final byte SUBCLASS2_SENSING_DEVICE = 4; // 0x4
+ field public static final byte SUBCLASS2_UNCATEGORIZED = 0; // 0x0
+ }
+
+ public final class BluetoothHidDeviceAppQosSettings implements android.os.Parcelable {
+ ctor public BluetoothHidDeviceAppQosSettings(int, int, int, int, int, int);
+ method public int describeContents();
+ method public int[] toArray();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppQosSettings> CREATOR;
+ field public static final int MAX = -1; // 0xffffffff
+ field public static final int SERVICE_BEST_EFFORT = 1; // 0x1
+ field public static final int SERVICE_GUARANTEED = 2; // 0x2
+ field public static final int SERVICE_NO_TRAFFIC = 0; // 0x0
+ field public final int delayVariation;
+ field public final int latency;
+ field public final int peakBandwidth;
+ field public final int serviceType;
+ field public final int tokenBucketSize;
+ field public final int tokenRate;
+ }
+
+ public static class BluetoothHidDeviceAppQosSettings.Builder {
+ ctor public BluetoothHidDeviceAppQosSettings.Builder();
+ method public android.bluetooth.BluetoothHidDeviceAppQosSettings build();
+ method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder delayVariation(int);
+ method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder latency(int);
+ method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder peakBandwidth(int);
+ method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder serviceType(int);
+ method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenBucketSize(int);
+ method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenRate(int);
+ }
+
+ public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable {
+ ctor public BluetoothHidDeviceAppSdpSettings(java.lang.String, java.lang.String, java.lang.String, byte, byte[]);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
+ field public final java.lang.String description;
+ field public final byte[] descriptors;
+ field public final java.lang.String name;
+ field public final java.lang.String provider;
+ field public final byte subclass;
+ }
+
+ public abstract class BluetoothHidDeviceCallback {
+ ctor public BluetoothHidDeviceCallback();
+ method public void onAppStatusChanged(android.bluetooth.BluetoothDevice, boolean);
+ method public void onConnectionStateChanged(android.bluetooth.BluetoothDevice, int);
+ method public void onGetReport(android.bluetooth.BluetoothDevice, byte, byte, int);
+ method public void onInterruptData(android.bluetooth.BluetoothDevice, byte, byte[]);
+ method public void onSetProtocol(android.bluetooth.BluetoothDevice, byte);
+ method public void onSetReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
+ method public void onVirtualCableUnplug(android.bluetooth.BluetoothDevice);
+ }
+
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
@@ -7928,6 +8016,7 @@
field public static final int GATT_SERVER = 8; // 0x8
field public static final int HEADSET = 1; // 0x1
field public static final int HEALTH = 3; // 0x3
+ field public static final int HID_DEVICE = 19; // 0x13
field public static final int SAP = 10; // 0xa
field public static final int STATE_CONNECTED = 2; // 0x2
field public static final int STATE_CONNECTING = 1; // 0x1
@@ -10757,6 +10846,7 @@
field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
+ field public static final java.lang.String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
field public static final java.lang.String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
@@ -16280,6 +16370,17 @@
field public static final int KNOTTED_HEH = 21; // 0x15
field public static final int LAM = 22; // 0x16
field public static final int LAMADH = 23; // 0x17
+ field public static final int MALAYALAM_BHA = 89; // 0x59
+ field public static final int MALAYALAM_JA = 90; // 0x5a
+ field public static final int MALAYALAM_LLA = 91; // 0x5b
+ field public static final int MALAYALAM_LLLA = 92; // 0x5c
+ field public static final int MALAYALAM_NGA = 93; // 0x5d
+ field public static final int MALAYALAM_NNA = 94; // 0x5e
+ field public static final int MALAYALAM_NNNA = 95; // 0x5f
+ field public static final int MALAYALAM_NYA = 96; // 0x60
+ field public static final int MALAYALAM_RA = 97; // 0x61
+ field public static final int MALAYALAM_SSA = 98; // 0x62
+ field public static final int MALAYALAM_TTA = 99; // 0x63
field public static final int MANICHAEAN_ALEPH = 58; // 0x3a
field public static final int MANICHAEAN_AYIN = 59; // 0x3b
field public static final int MANICHAEAN_BETH = 60; // 0x3c
@@ -16535,6 +16636,8 @@
field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D_ID = 209; // 0xd1
field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E;
field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E_ID = 256; // 0x100
+ field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F;
+ field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F_ID = 274; // 0x112
field public static final int CJK_UNIFIED_IDEOGRAPHS_ID = 71; // 0x47
field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS;
field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS_EXTENDED;
@@ -16680,6 +16783,8 @@
field public static final int JAVANESE_ID = 181; // 0xb5
field public static final android.icu.lang.UCharacter.UnicodeBlock KAITHI;
field public static final int KAITHI_ID = 193; // 0xc1
+ field public static final android.icu.lang.UCharacter.UnicodeBlock KANA_EXTENDED_A;
+ field public static final int KANA_EXTENDED_A_ID = 275; // 0x113
field public static final android.icu.lang.UCharacter.UnicodeBlock KANA_SUPPLEMENT;
field public static final int KANA_SUPPLEMENT_ID = 203; // 0xcb
field public static final android.icu.lang.UCharacter.UnicodeBlock KANBUN;
@@ -16752,6 +16857,8 @@
field public static final int MANICHAEAN_ID = 234; // 0xea
field public static final android.icu.lang.UCharacter.UnicodeBlock MARCHEN;
field public static final int MARCHEN_ID = 268; // 0x10c
+ field public static final android.icu.lang.UCharacter.UnicodeBlock MASARAM_GONDI;
+ field public static final int MASARAM_GONDI_ID = 276; // 0x114
field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS;
field public static final int MATHEMATICAL_ALPHANUMERIC_SYMBOLS_ID = 93; // 0x5d
field public static final android.icu.lang.UCharacter.UnicodeBlock MATHEMATICAL_OPERATORS;
@@ -16811,6 +16918,8 @@
field public static final android.icu.lang.UCharacter.UnicodeBlock NO_BLOCK;
field public static final android.icu.lang.UCharacter.UnicodeBlock NUMBER_FORMS;
field public static final int NUMBER_FORMS_ID = 45; // 0x2d
+ field public static final android.icu.lang.UCharacter.UnicodeBlock NUSHU;
+ field public static final int NUSHU_ID = 277; // 0x115
field public static final android.icu.lang.UCharacter.UnicodeBlock OGHAM;
field public static final int OGHAM_ID = 34; // 0x22
field public static final android.icu.lang.UCharacter.UnicodeBlock OLD_HUNGARIAN;
@@ -16889,6 +16998,8 @@
field public static final int SMALL_FORM_VARIANTS_ID = 84; // 0x54
field public static final android.icu.lang.UCharacter.UnicodeBlock SORA_SOMPENG;
field public static final int SORA_SOMPENG_ID = 218; // 0xda
+ field public static final android.icu.lang.UCharacter.UnicodeBlock SOYOMBO;
+ field public static final int SOYOMBO_ID = 278; // 0x116
field public static final android.icu.lang.UCharacter.UnicodeBlock SPACING_MODIFIER_LETTERS;
field public static final int SPACING_MODIFIER_LETTERS_ID = 6; // 0x6
field public static final android.icu.lang.UCharacter.UnicodeBlock SPECIALS;
@@ -16921,6 +17032,8 @@
field public static final int SYLOTI_NAGRI_ID = 143; // 0x8f
field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC;
field public static final int SYRIAC_ID = 13; // 0xd
+ field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC_SUPPLEMENT;
+ field public static final int SYRIAC_SUPPLEMENT_ID = 279; // 0x117
field public static final android.icu.lang.UCharacter.UnicodeBlock TAGALOG;
field public static final int TAGALOG_ID = 98; // 0x62
field public static final android.icu.lang.UCharacter.UnicodeBlock TAGBANWA;
@@ -16981,6 +17094,8 @@
field public static final int YI_RADICALS_ID = 73; // 0x49
field public static final android.icu.lang.UCharacter.UnicodeBlock YI_SYLLABLES;
field public static final int YI_SYLLABLES_ID = 72; // 0x48
+ field public static final android.icu.lang.UCharacter.UnicodeBlock ZANABAZAR_SQUARE;
+ field public static final int ZANABAZAR_SQUARE_ID = 280; // 0x118
}
public static abstract interface UCharacter.WordBreak {
@@ -17131,6 +17246,11 @@
field public static final int DIACRITIC = 7; // 0x7
field public static final int DOUBLE_START = 12288; // 0x3000
field public static final int EAST_ASIAN_WIDTH = 4100; // 0x1004
+ field public static final int EMOJI = 57; // 0x39
+ field public static final int EMOJI_COMPONENT = 61; // 0x3d
+ field public static final int EMOJI_MODIFIER = 59; // 0x3b
+ field public static final int EMOJI_MODIFIER_BASE = 60; // 0x3c
+ field public static final int EMOJI_PRESENTATION = 58; // 0x3a
field public static final int EXTENDER = 8; // 0x8
field public static final int FULL_COMPOSITION_EXCLUSION = 9; // 0x9
field public static final int GENERAL_CATEGORY = 4101; // 0x1005
@@ -17178,8 +17298,10 @@
field public static final int POSIX_GRAPH = 46; // 0x2e
field public static final int POSIX_PRINT = 47; // 0x2f
field public static final int POSIX_XDIGIT = 48; // 0x30
+ field public static final int PREPENDED_CONCATENATION_MARK = 63; // 0x3f
field public static final int QUOTATION_MARK = 25; // 0x19
field public static final int RADICAL = 26; // 0x1a
+ field public static final int REGIONAL_INDICATOR = 62; // 0x3e
field public static final int SCRIPT = 4106; // 0x100a
field public static final int SCRIPT_EXTENSIONS = 28672; // 0x7000
field public static final int SEGMENT_STARTER = 41; // 0x29
@@ -17321,6 +17443,7 @@
field public static final int MANDAIC = 84; // 0x54
field public static final int MANICHAEAN = 121; // 0x79
field public static final int MARCHEN = 169; // 0xa9
+ field public static final int MASARAM_GONDI = 175; // 0xaf
field public static final int MATHEMATICAL_NOTATION = 128; // 0x80
field public static final int MAYAN_HIEROGLYPHS = 85; // 0x55
field public static final int MEITEI_MAYEK = 115; // 0x73
@@ -17375,6 +17498,7 @@
field public static final int SINDHI = 145; // 0x91
field public static final int SINHALA = 33; // 0x21
field public static final int SORA_SOMPENG = 152; // 0x98
+ field public static final int SOYOMBO = 176; // 0xb0
field public static final int SUNDANESE = 113; // 0x71
field public static final int SYLOTI_NAGRI = 58; // 0x3a
field public static final int SYMBOLS = 129; // 0x81
@@ -17405,6 +17529,7 @@
field public static final int WESTERN_SYRIAC = 96; // 0x60
field public static final int WOLEAI = 155; // 0x9b
field public static final int YI = 41; // 0x29
+ field public static final int ZANABAZAR_SQUARE = 177; // 0xb1
}
public static final class UScript.ScriptUsage extends java.lang.Enum {
@@ -18199,11 +18324,14 @@
method public android.icu.util.Currency getCurrency();
method public java.lang.String getCurrencySymbol();
method public char getDecimalSeparator();
+ method public java.lang.String getDecimalSeparatorString();
method public char getDigit();
+ method public java.lang.String[] getDigitStrings();
method public char[] getDigits();
method public java.lang.String getExponentMultiplicationSign();
method public java.lang.String getExponentSeparator();
method public char getGroupingSeparator();
+ method public java.lang.String getGroupingSeparatorString();
method public java.lang.String getInfinity();
method public static android.icu.text.DecimalFormatSymbols getInstance();
method public static android.icu.text.DecimalFormatSymbols getInstance(java.util.Locale);
@@ -18211,37 +18339,52 @@
method public java.lang.String getInternationalCurrencySymbol();
method public java.util.Locale getLocale();
method public char getMinusSign();
+ method public java.lang.String getMinusSignString();
method public char getMonetaryDecimalSeparator();
+ method public java.lang.String getMonetaryDecimalSeparatorString();
method public char getMonetaryGroupingSeparator();
+ method public java.lang.String getMonetaryGroupingSeparatorString();
method public java.lang.String getNaN();
method public char getPadEscape();
method public java.lang.String getPatternForCurrencySpacing(int, boolean);
method public char getPatternSeparator();
method public char getPerMill();
+ method public java.lang.String getPerMillString();
method public char getPercent();
+ method public java.lang.String getPercentString();
method public char getPlusSign();
+ method public java.lang.String getPlusSignString();
method public char getSignificantDigit();
method public android.icu.util.ULocale getULocale();
method public char getZeroDigit();
method public void setCurrency(android.icu.util.Currency);
method public void setCurrencySymbol(java.lang.String);
method public void setDecimalSeparator(char);
+ method public void setDecimalSeparatorString(java.lang.String);
method public void setDigit(char);
+ method public void setDigitStrings(java.lang.String[]);
method public void setExponentMultiplicationSign(java.lang.String);
method public void setExponentSeparator(java.lang.String);
method public void setGroupingSeparator(char);
+ method public void setGroupingSeparatorString(java.lang.String);
method public void setInfinity(java.lang.String);
method public void setInternationalCurrencySymbol(java.lang.String);
method public void setMinusSign(char);
+ method public void setMinusSignString(java.lang.String);
method public void setMonetaryDecimalSeparator(char);
+ method public void setMonetaryDecimalSeparatorString(java.lang.String);
method public void setMonetaryGroupingSeparator(char);
+ method public void setMonetaryGroupingSeparatorString(java.lang.String);
method public void setNaN(java.lang.String);
method public void setPadEscape(char);
method public void setPatternForCurrencySpacing(int, boolean, java.lang.String);
method public void setPatternSeparator(char);
method public void setPerMill(char);
+ method public void setPerMillString(java.lang.String);
method public void setPercent(char);
+ method public void setPercentString(java.lang.String);
method public void setPlusSign(char);
+ method public void setPlusSignString(java.lang.String);
method public void setSignificantDigit(char);
method public void setZeroDigit(char);
field public static final int CURRENCY_SPC_CURRENCY_MATCH = 0; // 0x0
@@ -18262,7 +18405,9 @@
enum_constant public static final android.icu.text.DisplayContext DIALECT_NAMES;
enum_constant public static final android.icu.text.DisplayContext LENGTH_FULL;
enum_constant public static final android.icu.text.DisplayContext LENGTH_SHORT;
+ enum_constant public static final android.icu.text.DisplayContext NO_SUBSTITUTE;
enum_constant public static final android.icu.text.DisplayContext STANDARD_NAMES;
+ enum_constant public static final android.icu.text.DisplayContext SUBSTITUTE;
}
public static final class DisplayContext.Type extends java.lang.Enum {
@@ -18271,6 +18416,7 @@
enum_constant public static final android.icu.text.DisplayContext.Type CAPITALIZATION;
enum_constant public static final android.icu.text.DisplayContext.Type DIALECT_HANDLING;
enum_constant public static final android.icu.text.DisplayContext.Type DISPLAY_LENGTH;
+ enum_constant public static final android.icu.text.DisplayContext.Type SUBSTITUTE_HANDLING;
}
public abstract class IDNA {
@@ -18378,6 +18524,7 @@
method public static android.icu.text.MeasureFormat getInstance(java.util.Locale, android.icu.text.MeasureFormat.FormatWidth, android.icu.text.NumberFormat);
method public final android.icu.util.ULocale getLocale();
method public android.icu.text.NumberFormat getNumberFormat();
+ method public java.lang.String getUnitDisplayName(android.icu.util.MeasureUnit);
method public android.icu.text.MeasureFormat.FormatWidth getWidth();
method public final int hashCode();
method public android.icu.util.Measure parseObject(java.lang.String, java.text.ParsePosition);
@@ -19916,6 +20063,7 @@
field public static final android.icu.util.MeasureUnit MILLILITER;
field public static final android.icu.util.MeasureUnit MILLIMETER;
field public static final android.icu.util.MeasureUnit MILLIMETER_OF_MERCURY;
+ field public static final android.icu.util.MeasureUnit MILLIMOLE_PER_LITER;
field public static final android.icu.util.MeasureUnit MILLISECOND;
field public static final android.icu.util.MeasureUnit MILLIWATT;
field public static final android.icu.util.TimeUnit MINUTE;
@@ -19927,6 +20075,7 @@
field public static final android.icu.util.MeasureUnit OUNCE;
field public static final android.icu.util.MeasureUnit OUNCE_TROY;
field public static final android.icu.util.MeasureUnit PARSEC;
+ field public static final android.icu.util.MeasureUnit PART_PER_MILLION;
field public static final android.icu.util.MeasureUnit PICOMETER;
field public static final android.icu.util.MeasureUnit PINT;
field public static final android.icu.util.MeasureUnit PINT_METRIC;
@@ -20050,6 +20199,9 @@
public static final class TimeZone.SystemTimeZoneType extends java.lang.Enum {
method public static android.icu.util.TimeZone.SystemTimeZoneType valueOf(java.lang.String);
method public static final android.icu.util.TimeZone.SystemTimeZoneType[] values();
+ enum_constant public static final android.icu.util.TimeZone.SystemTimeZoneType ANY;
+ enum_constant public static final android.icu.util.TimeZone.SystemTimeZoneType CANONICAL;
+ enum_constant public static final android.icu.util.TimeZone.SystemTimeZoneType CANONICAL_LOCATION;
}
public final class ULocale implements java.lang.Comparable java.io.Serializable {
@@ -20251,6 +20403,7 @@
field public static final android.icu.util.VersionInfo ICU_VERSION;
field public static final android.icu.util.VersionInfo UCOL_BUILDER_VERSION;
field public static final android.icu.util.VersionInfo UCOL_RUNTIME_VERSION;
+ field public static final android.icu.util.VersionInfo UNICODE_10_0;
field public static final android.icu.util.VersionInfo UNICODE_1_0;
field public static final android.icu.util.VersionInfo UNICODE_1_0_1;
field public static final android.icu.util.VersionInfo UNICODE_1_1_0;
@@ -25749,6 +25902,23 @@
enum_constant public static final android.net.LocalSocketAddress.Namespace RESERVED;
}
+ public final class MacAddress implements android.os.Parcelable {
+ method public int addressType();
+ method public int describeContents();
+ method public static android.net.MacAddress fromBytes(byte[]);
+ method public static android.net.MacAddress fromString(java.lang.String);
+ method public boolean isLocallyAssigned();
+ method public byte[] toByteArray();
+ method public java.lang.String toOuiString();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.net.MacAddress BROADCAST_ADDRESS;
+ field public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
+ field public static final int TYPE_BROADCAST = 3; // 0x3
+ field public static final int TYPE_MULTICAST = 2; // 0x2
+ field public static final int TYPE_UNICAST = 1; // 0x1
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
+ }
+
public class MailTo {
method public java.lang.String getBody();
method public java.lang.String getCc();
@@ -25946,6 +26116,7 @@
public class TrafficStats {
ctor public TrafficStats();
method public static void clearThreadStatsTag();
+ method public static void clearThreadStatsUid();
method public static int getAndSetThreadStatsTag(int);
method public static long getMobileRxBytes();
method public static long getMobileRxPackets();
@@ -25971,9 +26142,12 @@
method public static void incrementOperationCount(int);
method public static void incrementOperationCount(int, int);
method public static void setThreadStatsTag(int);
+ method public static void setThreadStatsUidSelf();
method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method public static void tagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+ method public static void untagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
field public static final int UNSUPPORTED = -1; // 0xffffffff
}
@@ -33216,6 +33390,7 @@
field public static final java.lang.String FEATURES = "features";
field public static final int FEATURES_HD_CALL = 4; // 0x4
field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
+ field public static final int FEATURES_RTT = 16; // 0x10
field public static final int FEATURES_VIDEO = 1; // 0x1
field public static final int FEATURES_WIFI = 8; // 0x8
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
@@ -38926,6 +39101,7 @@
field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
+ field public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 5; // 0x5
}
public static class Call.Details {
@@ -39660,6 +39836,7 @@
public class CarrierConfigManager {
method public android.os.PersistableBundle getConfig();
method public android.os.PersistableBundle getConfigForSubId(int);
+ method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle);
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
@@ -39986,19 +40163,19 @@
}
public class MbmsDownloadSession implements java.lang.AutoCloseable {
- method public void cancelDownload(android.telephony.mbms.DownloadRequest);
+ method public int cancelDownload(android.telephony.mbms.DownloadRequest);
method public void close();
method public static android.telephony.MbmsDownloadSession create(android.content.Context, android.telephony.mbms.MbmsDownloadSessionCallback, android.os.Handler);
method public static android.telephony.MbmsDownloadSession create(android.content.Context, android.telephony.mbms.MbmsDownloadSessionCallback, int, android.os.Handler);
- method public void download(android.telephony.mbms.DownloadRequest);
+ method public int download(android.telephony.mbms.DownloadRequest);
method public int getDownloadStatus(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo);
method public java.io.File getTempFileRootDirectory();
method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads();
- method public void registerStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback, android.os.Handler);
+ method public int registerStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback, android.os.Handler);
method public void requestUpdateFileServices(java.util.List<java.lang.String>);
method public void resetDownloadKnowledge(android.telephony.mbms.DownloadRequest);
method public void setTempFileRootDirectory(java.io.File);
- method public void unregisterStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback);
+ method public int unregisterStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback);
field public static final java.lang.String DEFAULT_TOP_LEVEL_TEMP_DIRECTORY = "androidMbmsTempFileRoot";
field public static final java.lang.String EXTRA_MBMS_COMPLETED_FILE_URI = "android.telephony.extra.MBMS_COMPLETED_FILE_URI";
field public static final java.lang.String EXTRA_MBMS_DOWNLOAD_REQUEST = "android.telephony.extra.MBMS_DOWNLOAD_REQUEST";
@@ -40046,6 +40223,34 @@
field public static final int UNKNOWN_RSSI = 99; // 0x63
}
+ public class NetworkScan {
+ method public void stop() throws android.os.RemoteException;
+ field public static final int ERROR_INTERRUPTED = 10002; // 0x2712
+ field public static final int ERROR_INVALID_SCAN = 2; // 0x2
+ field public static final int ERROR_INVALID_SCANID = 10001; // 0x2711
+ field public static final int ERROR_MODEM_ERROR = 1; // 0x1
+ field public static final int ERROR_MODEM_UNAVAILABLE = 3; // 0x3
+ field public static final int ERROR_RADIO_INTERFACE_ERROR = 10000; // 0x2710
+ field public static final int ERROR_UNSUPPORTED = 4; // 0x4
+ field public static final int SUCCESS = 0; // 0x0
+ }
+
+ public final class NetworkScanRequest implements android.os.Parcelable {
+ ctor public NetworkScanRequest(int, android.telephony.RadioAccessSpecifier[], int, int, boolean, int, java.util.ArrayList<java.lang.String>);
+ method public int describeContents();
+ method public boolean getIncrementalResults();
+ method public int getIncrementalResultsPeriodicity();
+ method public int getMaxSearchTime();
+ method public java.util.ArrayList<java.lang.String> getPlmns();
+ method public int getScanType();
+ method public int getSearchPeriodicity();
+ method public android.telephony.RadioAccessSpecifier[] getSpecifiers();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.NetworkScanRequest> CREATOR;
+ field public static final int SCAN_TYPE_ONE_SHOT = 0; // 0x0
+ field public static final int SCAN_TYPE_PERIODIC = 1; // 0x1
+ }
+
public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
ctor public PhoneNumberFormattingTextWatcher();
ctor public PhoneNumberFormattingTextWatcher(java.lang.String);
@@ -40138,6 +40343,121 @@
field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
}
+ public final class RadioAccessSpecifier implements android.os.Parcelable {
+ ctor public RadioAccessSpecifier(int, int[], int[]);
+ method public int describeContents();
+ method public int[] getBands();
+ method public int[] getChannels();
+ method public int getRadioAccessNetwork();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.RadioAccessSpecifier> CREATOR;
+ }
+
+ public final class RadioNetworkConstants {
+ ctor public RadioNetworkConstants();
+ }
+
+ public static final class RadioNetworkConstants.EutranBands {
+ ctor public RadioNetworkConstants.EutranBands();
+ field public static final int BAND_1 = 1; // 0x1
+ field public static final int BAND_10 = 10; // 0xa
+ field public static final int BAND_11 = 11; // 0xb
+ field public static final int BAND_12 = 12; // 0xc
+ field public static final int BAND_13 = 13; // 0xd
+ field public static final int BAND_14 = 14; // 0xe
+ field public static final int BAND_17 = 17; // 0x11
+ field public static final int BAND_18 = 18; // 0x12
+ field public static final int BAND_19 = 19; // 0x13
+ field public static final int BAND_2 = 2; // 0x2
+ field public static final int BAND_20 = 20; // 0x14
+ field public static final int BAND_21 = 21; // 0x15
+ field public static final int BAND_22 = 22; // 0x16
+ field public static final int BAND_23 = 23; // 0x17
+ field public static final int BAND_24 = 24; // 0x18
+ field public static final int BAND_25 = 25; // 0x19
+ field public static final int BAND_26 = 26; // 0x1a
+ field public static final int BAND_27 = 27; // 0x1b
+ field public static final int BAND_28 = 28; // 0x1c
+ field public static final int BAND_3 = 3; // 0x3
+ field public static final int BAND_30 = 30; // 0x1e
+ field public static final int BAND_31 = 31; // 0x1f
+ field public static final int BAND_33 = 33; // 0x21
+ field public static final int BAND_34 = 34; // 0x22
+ field public static final int BAND_35 = 35; // 0x23
+ field public static final int BAND_36 = 36; // 0x24
+ field public static final int BAND_37 = 37; // 0x25
+ field public static final int BAND_38 = 38; // 0x26
+ field public static final int BAND_39 = 39; // 0x27
+ field public static final int BAND_4 = 4; // 0x4
+ field public static final int BAND_40 = 40; // 0x28
+ field public static final int BAND_41 = 41; // 0x29
+ field public static final int BAND_42 = 42; // 0x2a
+ field public static final int BAND_43 = 43; // 0x2b
+ field public static final int BAND_44 = 44; // 0x2c
+ field public static final int BAND_45 = 45; // 0x2d
+ field public static final int BAND_46 = 46; // 0x2e
+ field public static final int BAND_47 = 47; // 0x2f
+ field public static final int BAND_48 = 48; // 0x30
+ field public static final int BAND_5 = 5; // 0x5
+ field public static final int BAND_6 = 6; // 0x6
+ field public static final int BAND_65 = 65; // 0x41
+ field public static final int BAND_66 = 66; // 0x42
+ field public static final int BAND_68 = 68; // 0x44
+ field public static final int BAND_7 = 7; // 0x7
+ field public static final int BAND_70 = 70; // 0x46
+ field public static final int BAND_8 = 8; // 0x8
+ field public static final int BAND_9 = 9; // 0x9
+ }
+
+ public static final class RadioNetworkConstants.GeranBands {
+ ctor public RadioNetworkConstants.GeranBands();
+ field public static final int BAND_450 = 3; // 0x3
+ field public static final int BAND_480 = 4; // 0x4
+ field public static final int BAND_710 = 5; // 0x5
+ field public static final int BAND_750 = 6; // 0x6
+ field public static final int BAND_850 = 8; // 0x8
+ field public static final int BAND_DCS1800 = 12; // 0xc
+ field public static final int BAND_E900 = 10; // 0xa
+ field public static final int BAND_ER900 = 14; // 0xe
+ field public static final int BAND_P900 = 9; // 0x9
+ field public static final int BAND_PCS1900 = 13; // 0xd
+ field public static final int BAND_R900 = 11; // 0xb
+ field public static final int BAND_T380 = 1; // 0x1
+ field public static final int BAND_T410 = 2; // 0x2
+ field public static final int BAND_T810 = 7; // 0x7
+ }
+
+ public static final class RadioNetworkConstants.RadioAccessNetworks {
+ ctor public RadioNetworkConstants.RadioAccessNetworks();
+ field public static final int EUTRAN = 3; // 0x3
+ field public static final int GERAN = 1; // 0x1
+ field public static final int UTRAN = 2; // 0x2
+ }
+
+ public static final class RadioNetworkConstants.UtranBands {
+ ctor public RadioNetworkConstants.UtranBands();
+ field public static final int BAND_1 = 1; // 0x1
+ field public static final int BAND_10 = 10; // 0xa
+ field public static final int BAND_11 = 11; // 0xb
+ field public static final int BAND_12 = 12; // 0xc
+ field public static final int BAND_13 = 13; // 0xd
+ field public static final int BAND_14 = 14; // 0xe
+ field public static final int BAND_19 = 19; // 0x13
+ field public static final int BAND_2 = 2; // 0x2
+ field public static final int BAND_20 = 20; // 0x14
+ field public static final int BAND_21 = 21; // 0x15
+ field public static final int BAND_22 = 22; // 0x16
+ field public static final int BAND_25 = 25; // 0x19
+ field public static final int BAND_26 = 26; // 0x1a
+ field public static final int BAND_3 = 3; // 0x3
+ field public static final int BAND_4 = 4; // 0x4
+ field public static final int BAND_5 = 5; // 0x5
+ field public static final int BAND_6 = 6; // 0x6
+ field public static final int BAND_7 = 7; // 0x7
+ field public static final int BAND_8 = 8; // 0x8
+ field public static final int BAND_9 = 9; // 0x9
+ }
+
public class ServiceState implements android.os.Parcelable {
ctor public ServiceState();
ctor public ServiceState(android.telephony.ServiceState);
@@ -40415,12 +40735,15 @@
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
+ method public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
method public void sendDialerSpecialCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(java.lang.String, int, java.lang.String, android.app.PendingIntent);
method public void setDataEnabled(boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+ method public void setNetworkSelectionModeAutomatic();
+ method public boolean setNetworkSelectionModeManual(java.lang.String, boolean);
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
@@ -40508,6 +40831,17 @@
method public void onReceiveUssdResponseFailed(android.telephony.TelephonyManager, java.lang.String, int);
}
+ public final class TelephonyScanManager {
+ ctor public TelephonyScanManager();
+ }
+
+ public static abstract class TelephonyScanManager.NetworkScanCallback {
+ ctor public TelephonyScanManager.NetworkScanCallback();
+ method public void onComplete();
+ method public void onError(int);
+ method public void onResults(java.util.List<android.telephony.CellInfo>);
+ }
+
public abstract class VisualVoicemailService extends android.app.Service {
ctor public VisualVoicemailService();
method public android.os.IBinder onBind(android.content.Intent);
diff --git a/api/test-current.txt b/api/test-current.txt
index d4beaca..75ff437 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -253,6 +253,13 @@
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
+ public class TrafficStats {
+ method public static long getLoopbackRxBytes();
+ method public static long getLoopbackRxPackets();
+ method public static long getLoopbackTxBytes();
+ method public static long getLoopbackTxPackets();
+ }
+
}
package android.os {
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 9ec7f41..88e2356 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -166,7 +166,7 @@
if (item.icon == null) {
item.icon = mIconResizer.createIconThumbnail(item.resolveInfo.loadIcon(getPackageManager()));
}
- text.setCompoundDrawablesWithIntrinsicBounds(item.icon, null, null, null);
+ text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, null, null, null);
}
}
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 330a0bf..2fab305 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -35,8 +35,6 @@
*
* <p>BluetoothHidDevice is a proxy object for controlling the Bluetooth HID Device Service via IPC.
* Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
- *
- * <p>{@hide}
*/
public final class BluetoothHidDevice implements BluetoothProfile {
@@ -79,7 +77,7 @@
public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
- public static final byte SUBCLASS2_DIGITIZER_TABLED = (byte) 0x05;
+ public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05;
public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
/**
@@ -87,7 +85,7 @@
*
* @see BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)
* @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
- * @see BluetoothHidDeviceCallback#onIntrData(BluetoothDevice, byte, byte[])
+ * @see BluetoothHidDeviceCallback#onInterruptData(BluetoothDevice, byte, byte[])
*/
public static final byte REPORT_TYPE_INPUT = (byte) 1;
public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
@@ -157,8 +155,8 @@
}
@Override
- public void onIntrData(BluetoothDevice device, byte reportId, byte[] data) {
- mCallback.onIntrData(device, reportId, data);
+ public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
+ mCallback.onInterruptData(device, reportId, data);
}
@Override
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index 4609d52..c05df2d 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -26,8 +26,6 @@
* registration.
*
* <p>{@see BluetoothHidDevice}
- *
- * <p>{@hide}
*/
public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
@@ -46,10 +44,8 @@
/**
* Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS
- * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder. {@see <a
- * href="https://www.bluetooth.com/specifications/profiles-overview">
- * https://www.bluetooth.com/specifications/profiles-overview </a> Bluetooth HID Specfication
- * v1.1.1 Section 5.2 and Appendix D }
+ * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
+ * Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D for parameters.
*
* @param serviceType L2CAP service type
* @param tokenRate L2CAP token rate
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index 2da64e5..562c559 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -28,8 +28,6 @@
* Android device can be discovered as a Bluetooth HID Device.
*
* <p>{@see BluetoothHidDevice}
- *
- * <p>{@hide}
*/
public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
index 6ed1965..e71b00f 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -24,8 +24,6 @@
* registration.
*
* <p>{@see BluetoothHidDevice}
- *
- * <p>{@hide}
*/
public abstract class BluetoothHidDeviceCallback {
@@ -108,8 +106,8 @@
* @param reportId Report Id.
* @param data Report data.
*/
- public void onIntrData(BluetoothDevice device, byte reportId, byte[] data) {
- Log.d(TAG, "onIntrData: device=" + device + " reportId=" + reportId);
+ public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
+ Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId);
}
/**
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index ebbc710..df2028a 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -153,8 +153,6 @@
/**
* HID Device
- *
- * @hide
*/
public static final int HID_DEVICE = 19;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ef8f84b..89751da 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2085,6 +2085,13 @@
public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * supports cell-broadcast reception using the MBMS APIs.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports connecting to USB devices
* as the USB host.
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 9180112..95e7f60 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -67,4 +67,13 @@
/** Unregisters a callback on data usage. */
void unregisterUsageRequest(in DataUsageRequest request);
+ /** Get the uid stats information since boot */
+ long getUidStats(int uid, int type);
+
+ /** Get the iface stats information since boot */
+ long getIfaceStats(String iface, int type);
+
+ /** Get the total network stats information since boot */
+ long getTotalStats(int type);
+
}
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 5620a62..d6992aa 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -33,8 +33,6 @@
*
* This class only supports 48 bits long addresses and does not support 64 bits long addresses.
* Instances of this class are immutable.
- *
- * @hide
*/
public final class MacAddress implements Parcelable {
@@ -132,11 +130,12 @@
}
/**
- * @return a String representation of the OUI part of this MacAddres,
- * with the lower 3 bytes constituting the NIC part replaced with 0.
+ * @return a String representation of the OUI part of this MacAddress made of 3 hexadecimal
+ * numbers in [0,ff] joined by ':' characters.
*/
- public String toSafeString() {
- return stringAddrFromLongAddr(mAddr & OUI_MASK);
+ public String toOuiString() {
+ return String.format(
+ "%02x:%02x:%02x", (mAddr >> 40) & 0xff, (mAddr >> 32) & 0xff, (mAddr >> 24) & 0xff);
}
@Override
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index c339856..196a3bc 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -17,7 +17,9 @@
package android.net;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.DownloadManager;
import android.app.backup.BackupManager;
import android.app.usage.NetworkStatsManager;
@@ -30,6 +32,8 @@
import dalvik.system.SocketTagger;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Socket;
import java.net.SocketException;
@@ -151,6 +155,8 @@
private static Object sProfilingLock = new Object();
+ private static final String LOOPBACK_IFACE = "lo";
+
/**
* Set active tag to use when accounting {@link Socket} traffic originating
* from the current thread. Only one active tag per thread is supported.
@@ -264,14 +270,25 @@
}
/**
+ * Set specific UID to use when accounting {@link Socket} traffic
+ * originating from the current thread as the calling UID. Designed for use
+ * when another application is performing operations on your behalf.
+ * <p>
+ * Changes only take effect during subsequent calls to
+ * {@link #tagSocket(Socket)}.
+ */
+ public static void setThreadStatsUidSelf() {
+ setThreadStatsUid(android.os.Process.myUid());
+ }
+
+ /**
* Clear any active UID set to account {@link Socket} traffic originating
* from the current thread.
*
* @see #setThreadStatsUid(int)
- * @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+ @SuppressLint("Doclava125")
public static void clearThreadStatsUid() {
NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
@@ -316,6 +333,27 @@
}
/**
+ * Tag the given {@link FileDescriptor} socket with any statistics
+ * parameters active for the current thread. Subsequent calls always replace
+ * any existing parameters. When finished, call
+ * {@link #untagFileDescriptor(FileDescriptor)} to remove statistics
+ * parameters.
+ *
+ * @see #setThreadStatsTag(int)
+ */
+ public static void tagFileDescriptor(FileDescriptor fd) throws IOException {
+ SocketTagger.get().tag(fd);
+ }
+
+ /**
+ * Remove any statistics parameters from the given {@link FileDescriptor}
+ * socket.
+ */
+ public static void untagFileDescriptor(FileDescriptor fd) throws IOException {
+ SocketTagger.get().untag(fd);
+ }
+
+ /**
* Start profiling data usage for current UID. Only one profiling session
* can be active at a time.
*
@@ -467,7 +505,12 @@
public static long getMobileTcpRxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
- final long stat = nativeGetIfaceStat(iface, TYPE_TCP_RX_PACKETS);
+ long stat = UNSUPPORTED;
+ try {
+ stat = getStatsService().getIfaceStats(iface, TYPE_TCP_RX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
if (stat != UNSUPPORTED) {
total += stat;
}
@@ -479,7 +522,12 @@
public static long getMobileTcpTxPackets() {
long total = 0;
for (String iface : getMobileIfaces()) {
- final long stat = nativeGetIfaceStat(iface, TYPE_TCP_TX_PACKETS);
+ long stat = UNSUPPORTED;
+ try {
+ stat = getStatsService().getIfaceStats(iface, TYPE_TCP_TX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
if (stat != UNSUPPORTED) {
total += stat;
}
@@ -489,22 +537,78 @@
/** {@hide} */
public static long getTxPackets(String iface) {
- return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
+ try {
+ return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** {@hide} */
public static long getRxPackets(String iface) {
- return nativeGetIfaceStat(iface, TYPE_RX_PACKETS);
+ try {
+ return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** {@hide} */
public static long getTxBytes(String iface) {
- return nativeGetIfaceStat(iface, TYPE_TX_BYTES);
+ try {
+ return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** {@hide} */
public static long getRxBytes(String iface) {
- return nativeGetIfaceStat(iface, TYPE_RX_BYTES);
+ try {
+ return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@hide} */
+ @TestApi
+ public static long getLoopbackTxPackets() {
+ try {
+ return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@hide} */
+ @TestApi
+ public static long getLoopbackRxPackets() {
+ try {
+ return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@hide} */
+ @TestApi
+ public static long getLoopbackTxBytes() {
+ try {
+ return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@hide} */
+ @TestApi
+ public static long getLoopbackRxBytes() {
+ try {
+ return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -517,7 +621,11 @@
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalTxPackets() {
- return nativeGetTotalStat(TYPE_TX_PACKETS);
+ try {
+ return getStatsService().getTotalStats(TYPE_TX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -530,7 +638,11 @@
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalRxPackets() {
- return nativeGetTotalStat(TYPE_RX_PACKETS);
+ try {
+ return getStatsService().getTotalStats(TYPE_RX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -543,7 +655,11 @@
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalTxBytes() {
- return nativeGetTotalStat(TYPE_TX_BYTES);
+ try {
+ return getStatsService().getTotalStats(TYPE_TX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -556,7 +672,11 @@
* return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/
public static long getTotalRxBytes() {
- return nativeGetTotalStat(TYPE_RX_BYTES);
+ try {
+ return getStatsService().getTotalStats(TYPE_RX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -582,7 +702,11 @@
// unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
- return nativeGetUidStat(uid, TYPE_TX_BYTES);
+ try {
+ return getStatsService().getUidStats(uid, TYPE_TX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
} else {
return UNSUPPORTED;
}
@@ -611,7 +735,11 @@
// unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
- return nativeGetUidStat(uid, TYPE_RX_BYTES);
+ try {
+ return getStatsService().getUidStats(uid, TYPE_RX_BYTES);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
} else {
return UNSUPPORTED;
}
@@ -640,7 +768,11 @@
// unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
- return nativeGetUidStat(uid, TYPE_TX_PACKETS);
+ try {
+ return getStatsService().getUidStats(uid, TYPE_TX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
} else {
return UNSUPPORTED;
}
@@ -669,7 +801,11 @@
// unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
- return nativeGetUidStat(uid, TYPE_RX_PACKETS);
+ try {
+ return getStatsService().getUidStats(uid, TYPE_RX_PACKETS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
} else {
return UNSUPPORTED;
}
@@ -797,8 +933,4 @@
private static final int TYPE_TX_PACKETS = 3;
private static final int TYPE_TCP_RX_PACKETS = 4;
private static final int TYPE_TCP_TX_PACKETS = 5;
-
- private static native long nativeGetTotalStat(int type);
- private static native long nativeGetIfaceStat(String iface, int type);
- private static native long nativeGetUidStat(int uid, int type);
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 1b707bd..5c4a40e 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -35,6 +35,9 @@
import java.lang.ref.WeakReference;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
/**
* Base class for a remotable object, the core part of a lightweight
@@ -888,17 +891,62 @@
keyArray[size] = key;
}
if (size >= mWarnBucketSize) {
- final int total_size = size();
+ final int totalSize = size();
Log.v(Binder.TAG, "BinderProxy map growth! bucket size = " + size
- + " total = " + total_size);
+ + " total = " + totalSize);
mWarnBucketSize += WARN_INCREMENT;
- if (Build.IS_DEBUGGABLE && total_size > CRASH_AT_SIZE) {
- throw new AssertionError("Binder ProxyMap has too many entries. "
- + "BinderProxy leak?");
+ if (Build.IS_DEBUGGABLE && totalSize > CRASH_AT_SIZE) {
+ diagnosticCrash();
}
}
}
+ /**
+ * Dump a histogram to the logcat, then throw an assertion error. Used to diagnose
+ * abnormally large proxy maps.
+ */
+ private void diagnosticCrash() {
+ Map<String, Integer> counts = new HashMap<>();
+ for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
+ if (a != null) {
+ for (WeakReference<BinderProxy> weakRef : a) {
+ BinderProxy bp = weakRef.get();
+ String key;
+ if (bp == null) {
+ key = "<cleared weak-ref>";
+ } else {
+ try {
+ key = bp.getInterfaceDescriptor();
+ } catch (Throwable t) {
+ key = "<exception during getDescriptor>";
+ }
+ }
+ Integer i = counts.get(key);
+ if (i == null) {
+ counts.put(key, 1);
+ } else {
+ counts.put(key, i + 1);
+ }
+ }
+ }
+ }
+ Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
+ new Map.Entry[counts.size()]);
+ Arrays.sort(sorted, (Map.Entry<String, Integer> a, Map.Entry<String, Integer> b)
+ -> b.getValue().compareTo(a.getValue()));
+ Log.v(Binder.TAG, "BinderProxy descriptor histogram (top ten):");
+ int printLength = Math.min(10, sorted.length);
+ for (int i = 0; i < printLength; i++) {
+ Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i].getKey() + " x"
+ + sorted[i].getValue());
+ }
+
+ // Now throw an assertion.
+ final int totalSize = size();
+ throw new AssertionError("Binder ProxyMap has too many entries: " + totalSize
+ + ". BinderProxy leak?");
+ }
+
// Corresponding ArrayLists in the following two arrays always have the same size.
// They contain no empty entries. However WeakReferences in the values ArrayLists
// may have been cleared.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 8533c7e..18f3a14 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1083,12 +1083,14 @@
/** {@hide} */
public static Pair<String, Long> getPrimaryStoragePathAndSize() {
return Pair.create(null,
- FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()));
+ FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
+ + Environment.getRootDirectory().getTotalSpace()));
}
/** {@hide} */
public long getPrimaryStorageSize() {
- return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace());
+ return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
+ + Environment.getRootDirectory().getTotalSpace());
}
/** @removed */
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 766ad84..60df467 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -212,16 +212,19 @@
public static final String FEATURES = "features";
/** Call had video. */
- public static final int FEATURES_VIDEO = 0x1;
+ public static final int FEATURES_VIDEO = 1 << 0;
/** Call was pulled externally. */
- public static final int FEATURES_PULLED_EXTERNALLY = 0x2;
+ public static final int FEATURES_PULLED_EXTERNALLY = 1 << 1;
/** Call was HD. */
- public static final int FEATURES_HD_CALL = 0x4;
+ public static final int FEATURES_HD_CALL = 1 << 2;
/** Call was WIFI call. */
- public static final int FEATURES_WIFI = 0x8;
+ public static final int FEATURES_WIFI = 1 << 3;
+
+ /** Call was on RTT at some point */
+ public static final int FEATURES_RTT = 1 << 4;
/**
* Indicates the call underwent Assisted Dialing.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ca9544a..ed68276 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -65,6 +65,7 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.speech.tts.TextToSpeech;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
@@ -10077,8 +10078,12 @@
* <p>
* Type: int (0 for false, 1 for true)
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * instead.
*/
- public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ @Deprecated
+ public static final String ENHANCED_4G_MODE_ENABLED =
+ SubscriptionManager.ENHANCED_4G_MODE_ENABLED;
/**
* Whether VT (Video Telephony over IMS) is enabled
@@ -10086,8 +10091,10 @@
* Type: int (0 for false, 1 for true)
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#VT_IMS_ENABLED} instead.
*/
- public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ @Deprecated
+ public static final String VT_IMS_ENABLED = SubscriptionManager.VT_IMS_ENABLED;
/**
* Whether WFC is enabled
@@ -10095,8 +10102,10 @@
* Type: int (0 for false, 1 for true)
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ENABLED} instead.
*/
- public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ @Deprecated
+ public static final String WFC_IMS_ENABLED = SubscriptionManager.WFC_IMS_ENABLED;
/**
* WFC mode on home/non-roaming network.
@@ -10104,8 +10113,10 @@
* Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_MODE} instead.
*/
- public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ @Deprecated
+ public static final String WFC_IMS_MODE = SubscriptionManager.WFC_IMS_MODE;
/**
* WFC mode on roaming network.
@@ -10113,8 +10124,11 @@
* Type: int - see {@link #WFC_IMS_MODE} for values
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_MODE}
+ * instead.
*/
- public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+ @Deprecated
+ public static final String WFC_IMS_ROAMING_MODE = SubscriptionManager.WFC_IMS_ROAMING_MODE;
/**
* Whether WFC roaming is enabled
@@ -10122,8 +10136,12 @@
* Type: int (0 for false, 1 for true)
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_ENABLED}
+ * instead
*/
- public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ @Deprecated
+ public static final String WFC_IMS_ROAMING_ENABLED =
+ SubscriptionManager.WFC_IMS_ROAMING_ENABLED;
/**
* Whether user can enable/disable LTE as a preferred network. A carrier might control
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 336fee1..551d54a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -96,7 +96,6 @@
"android_os_VintfRuntimeInfo.cpp",
"android_net_LocalSocketImpl.cpp",
"android_net_NetUtils.cpp",
- "android_net_TrafficStats.cpp",
"android_nio_utils.cpp",
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9059862..047fa84 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -173,7 +173,6 @@
extern int register_android_os_SharedMemory(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
-extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_StaticLayout(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
@@ -643,6 +642,7 @@
char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
std::string fingerprintBuf;
+ char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
bool checkJni = false;
property_get("dalvik.vm.checkjni", propBuf, "");
@@ -765,9 +765,15 @@
* Set suspend=y to pause during VM init and use android ADB transport.
*/
if (zygote) {
- addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y");
+ addOption("-XjdwpOptions:suspend=n,server=y");
}
+ // Set the JDWP provider. By default let the runtime choose.
+ parseRuntimeOption("dalvik.vm.jdwp-provider",
+ jdwpProviderBuf,
+ "-XjdwpProvider:",
+ "default");
+
parseRuntimeOption("dalvik.vm.lockprof.threshold",
lockProfThresholdBuf,
"-Xlockprofthreshold:");
@@ -1419,7 +1425,6 @@
REG_JNI(register_android_os_UEventObserver),
REG_JNI(register_android_net_LocalSocketImpl),
REG_JNI(register_android_net_NetworkUtils),
- REG_JNI(register_android_net_TrafficStats),
REG_JNI(register_android_os_MemoryFile),
REG_JNI(register_android_os_SharedMemory),
REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index fce5dd5..685df0f 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -236,17 +236,15 @@
return INSTALL_SUCCEEDED;
}
- char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 2];
+ char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 1];
if (strlcpy(localTmpFileName, nativeLibPath.c_str(), sizeof(localTmpFileName))
!= nativeLibPath.size()) {
ALOGD("Couldn't allocate local file name for library");
return INSTALL_FAILED_INTERNAL_ERROR;
}
- *(localTmpFileName + nativeLibPath.size()) = '/';
-
if (strlcpy(localTmpFileName + nativeLibPath.size(), TMP_FILE_PATTERN,
- TMP_FILE_PATTERN_LEN - nativeLibPath.size()) != TMP_FILE_PATTERN_LEN) {
+ TMP_FILE_PATTERN_LEN + 1) != TMP_FILE_PATTERN_LEN) {
ALOGI("Couldn't allocate temporary file name for library");
return INSTALL_FAILED_INTERNAL_ERROR;
}
diff --git a/core/res/res/layout/activity_list_item_2.xml b/core/res/res/layout/activity_list_item_2.xml
index 608e986..af1963c 100644
--- a/core/res/res/layout/activity_list_item_2.xml
+++ b/core/res/res/layout/activity_list_item_2.xml
@@ -21,5 +21,6 @@
android:textAppearance="?attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:drawablePadding="14dip"
+ android:textAlignment="viewStart"
android:paddingStart="?attr/listPreferredItemPaddingStart"
android:paddingEnd="?attr/listPreferredItemPaddingEnd" />
diff --git a/core/tests/packagemanagertests/Android.mk b/core/tests/packagemanagertests/Android.mk
index c1e8c98..5bfde78 100644
--- a/core/tests/packagemanagertests/Android.mk
+++ b/core/tests/packagemanagertests/Android.mk
@@ -10,7 +10,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- frameworks-base-testutils
+ frameworks-base-testutils \
+ mockito-target-minus-junit4
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCorePackageManagerTests
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index c4c14c9e..1d14fa0 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -89,4 +89,7 @@
// initialization with {}.
},
},
+ sanitize: {
+ blacklist: "libandroidfw_blacklist.txt",
+ },
}
diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blacklist.txt
new file mode 100644
index 0000000..dd17e4d
--- /dev/null
+++ b/libs/androidfw/libandroidfw_blacklist.txt
@@ -0,0 +1 @@
+src:*/ResourceTypes.cpp
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 1f56222..616558f 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,24 +17,23 @@
#include "tests/common/LeakChecker.h"
#include "tests/common/TestScene.h"
+#include "Properties.h"
#include "hwui/Typeface.h"
#include "protos/hwui.pb.h"
-#include "Properties.h"
#include <benchmark/benchmark.h>
-#include <../src/sysinfo.h>
#include <getopt.h>
+#include <pthread.h>
#include <stdio.h>
-#include <string>
#include <unistd.h>
+#include <string>
#include <unordered_map>
#include <vector>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
using namespace android;
using namespace android::uirenderer;
@@ -320,9 +319,6 @@
name_field_width += 5;
benchmark::BenchmarkReporter::Context context;
- context.num_cpus = benchmark::NumCPUs();
- context.mhz_per_cpu = benchmark::CyclesPerSecond() / 1000000.0f;
- context.cpu_scaling_enabled = benchmark::CpuScalingEnabled();
context.name_field_width = name_field_width;
gBenchmarkReporter->ReportContext(context);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7d7f9ae7..04be92e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1687,18 +1687,9 @@
}
private List<String> getSettingsNamesLocked(int settingsType, int userId) {
- boolean instantApp;
- if (UserHandle.getAppId(Binder.getCallingUid()) < Process.FIRST_APPLICATION_UID) {
- instantApp = false;
- } else {
- ApplicationInfo ai = getCallingApplicationInfoOrThrow();
- instantApp = ai.isInstantApp();
- }
- if (instantApp) {
- return new ArrayList<String>(getInstantAppAccessibleSettings(settingsType));
- } else {
- return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
- }
+ // Don't enforce the instant app whitelist for now -- its too prone to unintended breakage
+ // in the current form.
+ return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
}
private void enforceSettingReadable(String settingName, int settingsType, int userId) {
@@ -1711,8 +1702,10 @@
}
if (!getInstantAppAccessibleSettings(settingsType).contains(settingName)
&& !getOverlayInstantAppAccessibleSettings(settingsType).contains(settingName)) {
- throw new SecurityException("Setting " + settingName + " is not accessible from"
- + " ephemeral package " + getCallingPackage());
+ // Don't enforce the instant app whitelist for now -- its too prone to unintended
+ // breakage in the current form.
+ Slog.w(LOG_TAG, "Instant App " + ai.packageName
+ + " trying to access unexposed setting, this will be an error in the future.");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 533771a..13617f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -265,7 +265,9 @@
mStatusBarIconController.getTransitionsController().dump(fd, pw, args);
pw.println();
pw.println(" NavigationBarTransitionsController:");
- mNavigationBarController.dump(fd, pw, args);
+ if (mNavigationBarController != null) {
+ mNavigationBarController.dump(fd, pw, args);
+ }
pw.println();
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 48f3b9c..630d5f4 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4564,6 +4564,73 @@
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
+ // OPEN: Settings > Network & Internet > Mobile network
+ // CATEGORY: SETTINGS
+ SETTINGS_MOBILE_NETWORK_CATEGORY = 1200;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Roaming
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_DATA_ROAMING_TOGGLE = 1201;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Advanced
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_EXPAND_ADVANCED_FIELDS = 1202;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Enhanced 4G LTE Mode
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_ENHANCED_4G_LTE_MODE_TOGGLE = 1203;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Preferred network type
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_SELECT_PREFERRED_NETWORK = 1204;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Preferred network type (enabled networks)
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_SELECT_ENABLED_NETWORK = 1205;
+
+ // OPEN: Settings > Network & Internet > Mobile network > Carrier
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_EUICC_SETTING = 1206;
+
+ // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_WIFI_CALLING = 1207;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Carrier video calling
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_VIDEO_CALLING_TOGGLE = 1208;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Automatically select network
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_AUTO_SELECT_NETWORK_TOGGLE = 1209;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Network
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK = 1210;
+
+ // FIELD - Manually selected mobile network
+ FIELD_MOBILE_NETWORK = 1211;
+
+ // OPEN: Settings > Network & Internet > Mobile network > Access Point Names
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_APN_SETTINGS = 1212;
+
+ // OPEN: Settings > Network & Internet > Mobile network > Carrier settings
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_CARRIER_SETTINGS = 1213;
+
+ // OPEN: Settings > Network & Internet > Mobile network > System select
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_CDMA_SYSTEM_SELECT = 1214;
+
+ // OPEN: Settings > Network & Internet > Mobile network > CDMA subscription
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_CDMA_SUBSCRIPTION_SELECT = 1215;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Set up data service
+ // CATEGORY: SETTINGS
+ ACTION_MOBILE_NETWORK_SET_UP_DATA_SERVICE = 1216;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index e9eb3b3..d3ab125 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -34,6 +34,7 @@
import android.net.IpSecTransformResponse;
import android.net.IpSecUdpEncapResponse;
import android.net.NetworkUtils;
+import android.net.TrafficStats;
import android.net.util.NetdService;
import android.os.Binder;
import android.os.IBinder;
@@ -120,6 +121,7 @@
}
private final IpSecServiceConfiguration mSrvConfig;
+ final UidFdTagger mUidFdTagger;
/**
* Interface for user-reference and kernel-resource cleanup.
@@ -762,8 +764,23 @@
/** @hide */
@VisibleForTesting
public IpSecService(Context context, IpSecServiceConfiguration config) {
+ this(context, config, (fd, uid) -> {
+ try{
+ TrafficStats.setThreadStatsUid(uid);
+ TrafficStats.tagFileDescriptor(fd);
+ } finally {
+ TrafficStats.clearThreadStatsUid();
+ }
+ });
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public IpSecService(
+ Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) {
mContext = context;
mSrvConfig = config;
+ mUidFdTagger = uidFdTagger;
}
public void systemReady() {
@@ -925,6 +942,26 @@
}
/**
+ * Functional interface to do traffic tagging of given sockets to UIDs.
+ *
+ * <p>Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap
+ * sockets are billed to the UID that the UDP encap socket was created on behalf of.
+ *
+ * <p>Separate class so that the socket tagging logic can be mocked; TrafficStats uses static
+ * methods that cannot be easily mocked/tested.
+ */
+ @VisibleForTesting
+ public interface UidFdTagger {
+ /**
+ * Sets socket tag to assign all traffic to the provided UID.
+ *
+ * <p>Since the socket is created on behalf of an unprivileged application, all traffic
+ * should be accounted to the UID of the unprivileged application.
+ */
+ public void tag(FileDescriptor fd, int uid) throws IOException;
+ }
+
+ /**
* Open a socket via the system server and bind it to the specified port (random if port=0).
* This will return a PFD to the user that represent a bound UDP socket. The system server will
* cache the socket and a record of its owner so that it can and must be freed when no longer
@@ -939,7 +976,8 @@
}
checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
- UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+ int callingUid = Binder.getCallingUid();
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
int resourceId = mNextResourceId.getAndIncrement();
FileDescriptor sockFd = null;
try {
@@ -948,13 +986,8 @@
}
sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ mUidFdTagger.tag(sockFd, callingUid);
- if (port != 0) {
- Log.v(TAG, "Binding to port " + port);
- Os.bind(sockFd, INADDR_ANY, port);
- } else {
- port = bindToRandomPort(sockFd);
- }
// This code is common to both the unspecified and specified port cases
Os.setsockoptInt(
sockFd,
@@ -962,6 +995,14 @@
OsConstants.UDP_ENCAP,
OsConstants.UDP_ENCAP_ESPINUDP);
+ mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner(sockFd, callingUid);
+ if (port != 0) {
+ Log.v(TAG, "Binding to port " + port);
+ Os.bind(sockFd, INADDR_ANY, port);
+ } else {
+ port = bindToRandomPort(sockFd);
+ }
+
userRecord.mEncapSocketRecords.put(
resourceId,
new RefcountedResource<EncapSocketRecord>(
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7715727..c7a4315 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -305,6 +305,7 @@
} else {
for (Network underlying : underlyingNetworks) {
final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
+ if (underlyingCaps == null) continue;
for (int underlyingType : underlyingCaps.getTransportTypes()) {
transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 3af5265..db61ef5 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -873,6 +873,21 @@
}
}
+ @Override
+ public long getUidStats(int uid, int type) {
+ return nativeGetUidStat(uid, type);
+ }
+
+ @Override
+ public long getIfaceStats(String iface, int type) {
+ return nativeGetIfaceStat(iface, type);
+ }
+
+ @Override
+ public long getTotalStats(int type) {
+ return nativeGetTotalStat(type);
+ }
+
/**
* Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
* reflect current {@link #mPersistThreshold} value. Always defers to
@@ -1626,4 +1641,15 @@
return getGlobalLong(NETSTATS_UID_TAG_PERSIST_BYTES, def);
}
}
+
+ private static int TYPE_RX_BYTES;
+ private static int TYPE_RX_PACKETS;
+ private static int TYPE_TX_BYTES;
+ private static int TYPE_TX_PACKETS;
+ private static int TYPE_TCP_RX_PACKETS;
+ private static int TYPE_TCP_TX_PACKETS;
+
+ private static native long nativeGetTotalStat(int type);
+ private static native long nativeGetIfaceStat(String iface, int type);
+ private static native long nativeGetUidStat(int uid, int type);
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 27acaee..04fd3e3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -33,6 +33,7 @@
"com_android_server_location_ContextHubService.cpp",
"com_android_server_location_GnssLocationProvider.cpp",
"com_android_server_locksettings_SyntheticPasswordManager.cpp",
+ "com_android_server_net_NetworkStatsService.cpp",
"com_android_server_power_PowerManagerService.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index ae7d6da..b044a4e 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -100,7 +100,7 @@
return -1;
}
ALOGV("Registering callback...");
- set_wakeup_callback(&wakeup_callback);
+ autosuspend_set_wakeup_callback(&wakeup_callback);
}
// Wait for wakeup.
diff --git a/core/jni/android_net_TrafficStats.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
similarity index 79%
rename from core/jni/android_net_TrafficStats.cpp
rename to services/core/jni/com_android_server_net_NetworkStatsService.cpp
index d0c237d..8de24e5 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "TrafficStats"
+#define LOG_TAG "NetworkStatsNative"
#include <dirent.h>
#include <errno.h>
@@ -191,8 +191,24 @@
{"nativeGetUidStat", "(II)J", (void*) getUidStat},
};
-int register_android_net_TrafficStats(JNIEnv* env) {
- return RegisterMethodsOrDie(env, "android/net/TrafficStats", gMethods, NELEM(gMethods));
+int register_android_server_net_NetworkStatsService(JNIEnv* env) {
+ jclass netStatsService = env->FindClass("com/android/server/net/NetworkStatsService");
+ jfieldID rxBytesId = env->GetStaticFieldID(netStatsService, "TYPE_RX_BYTES", "I");
+ jfieldID rxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_RX_PACKETS", "I");
+ jfieldID txBytesId = env->GetStaticFieldID(netStatsService, "TYPE_TX_BYTES", "I");
+ jfieldID txPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TX_PACKETS", "I");
+ jfieldID tcpRxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_RX_PACKETS", "I");
+ jfieldID tcpTxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_TX_PACKETS", "I");
+
+ env->SetStaticIntField(netStatsService, rxBytesId, RX_BYTES);
+ env->SetStaticIntField(netStatsService, rxPacketsId, RX_PACKETS);
+ env->SetStaticIntField(netStatsService, txBytesId, TX_BYTES);
+ env->SetStaticIntField(netStatsService, txPacketsId, TX_PACKETS);
+ env->SetStaticIntField(netStatsService, tcpRxPacketsId, TCP_RX_PACKETS);
+ env->SetStaticIntField(netStatsService, tcpTxPacketsId, TCP_TX_PACKETS);
+
+ return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods,
+ NELEM(gMethods));
}
}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index e8ef168..8dfbbf3 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -52,6 +52,7 @@
int register_android_server_SyntheticPasswordManager(JNIEnv* env);
int register_android_server_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
+int register_android_server_net_NetworkStatsService(JNIEnv* env);
};
using namespace android;
@@ -98,6 +99,7 @@
register_android_server_SyntheticPasswordManager(env);
register_android_server_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
+ register_android_server_net_NetworkStatsService(env);
return JNI_VERSION_1_4;
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 7ea42da..28d6d07 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -831,6 +831,77 @@
}
@Test
+ public void testCancelAllCancelNotificationsFromListener_ForegroundServiceFlag()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+ mNotificationManagerService.addNotification(newGroup);
+ mNotificationManagerService.getBinderService().cancelNotificationsFromListener(null, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_ForegroundServiceFlagWithParameter()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+ mNotificationManagerService.addNotification(newGroup);
+ String[] keys = {parent.sbn.getKey(), child.sbn.getKey(),
+ child2.sbn.getKey(), newGroup.sbn.getKey()};
+ mNotificationManagerService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+ mNotificationManagerService.addNotification(newGroup);
+ mNotificationManagerService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
+ parent.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
public void testFindGroupNotificationsLocked() throws Exception {
// make sure the same notification can be found in both lists and returned
final NotificationRecord group1 = generateNotificationRecord(
@@ -1692,4 +1763,157 @@
preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
}
+
+ @Test
+ public void testCancelAllNotifications_CancelsNoClearFlagOnGoing() throws Exception {
+ final NotificationRecord notif = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
+ mNotificationManagerService.addNotification(notif);
+ mNotificationManagerService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0,
+ Notification.FLAG_ONGOING_EVENT, true, notif.getUserId(), 0, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(notif.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_NoClearFlagWithParameter()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_NO_CLEAR;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+ mNotificationManagerService.addNotification(newGroup);
+ String[] keys = {parent.sbn.getKey(), child.sbn.getKey(),
+ child2.sbn.getKey(), newGroup.sbn.getKey()};
+ mNotificationManagerService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag() throws Exception {
+ final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+ sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+ sbn.getId(), sbn.getNotification(), sbn.getUserId());
+ mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllNotifications_CancelsOnGoingFlag() throws Exception {
+ final NotificationRecord notif = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mNotificationManagerService.addNotification(notif);
+ mNotificationManagerService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, true,
+ notif.getUserId(), 0, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(notif.sbn.getPackageName());
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testUserInitiatedCancelAllOnClearAll_OnGoingFlag() throws Exception {
+ final NotificationRecord notif = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ mNotificationManagerService.addNotification(notif);
+
+ mNotificationManagerService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
+ notif.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(notif.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_OnGoingFlag() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+ mNotificationManagerService.addNotification(newGroup);
+ mNotificationManagerService.getBinderService().cancelNotificationsFromListener(null, null);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
+
+ @Test
+ public void testCancelAllCancelNotificationsFromListener_OnGoingFlagWithParameter()
+ throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+ mNotificationManagerService.addNotification(newGroup);
+ String[] keys = {parent.sbn.getKey(), child.sbn.getKey(),
+ child2.sbn.getKey(), newGroup.sbn.getKey()};
+ mNotificationManagerService.getBinderService().cancelNotificationsFromListener(null, keys);
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ // Flags aren't checked in the cancel children call,
+ // so all of the notifications are canceled (expected value is 0)
+ assertEquals(0, notifs.length);
+ }
+
+ @Test
+ public void testUserInitiatedCancelAllWithGroup_OnGoingFlag() throws Exception {
+ final NotificationRecord parent = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord child = generateNotificationRecord(
+ mTestNotificationChannel, 2, "group", false);
+ final NotificationRecord child2 = generateNotificationRecord(
+ mTestNotificationChannel, 3, "group", false);
+ child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
+ final NotificationRecord newGroup = generateNotificationRecord(
+ mTestNotificationChannel, 4, "group2", false);
+ mNotificationManagerService.addNotification(parent);
+ mNotificationManagerService.addNotification(child);
+ mNotificationManagerService.addNotification(child2);
+ mNotificationManagerService.addNotification(newGroup);
+ mNotificationManagerService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(),
+ parent.getUserId());
+ waitForIdle();
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(parent.sbn.getPackageName());
+ assertEquals(1, notifs.length);
+ }
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 5cd2044..2091101 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -868,7 +868,8 @@
* @hide
*/
@IntDef({HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_DEST_NOT_SUPPORTED,
- HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED})
+ HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED,
+ HANDOVER_FAILURE_ONGOING_EMERG_CALL})
@Retention(RetentionPolicy.SOURCE)
public @interface HandoverFailureErrors {}
@@ -896,6 +897,12 @@
*/
public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4;
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
+ * is ongoing emergency call.
+ */
+ public static final int HANDOVER_FAILURE_ONGOING_EMERG_CALL = 5;
+
/**
* Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
@@ -1945,6 +1952,15 @@
}
}
+ /** {@hide} */
+ final void internalOnHandoverFailed(int error) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onHandoverFailed(call, error));
+ }
+ }
+
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index da8ac5e..4fd602f 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -143,6 +144,7 @@
private static final String SESSION_START_RTT = "CS.+RTT";
private static final String SESSION_STOP_RTT = "CS.-RTT";
private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
+ private static final String SESSION_HANDOVER_FAILED = "CS.haF";
private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
private static final int MSG_CREATE_CONNECTION = 2;
@@ -172,6 +174,7 @@
private static final int MSG_ON_STOP_RTT = 27;
private static final int MSG_RTT_UPGRADE_RESPONSE = 28;
private static final int MSG_CREATE_CONNECTION_COMPLETE = 29;
+ private static final int MSG_HANDOVER_FAILED = 32;
private static Connection sNullConnection;
@@ -275,6 +278,22 @@
}
@Override
+ public void handoverFailed(String callId, ConnectionRequest request, int reason,
+ Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_HANDOVER_FAILED);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = request;
+ args.arg3 = Log.createSubsession();
+ args.arg4 = reason;
+ mHandler.obtainMessage(MSG_HANDOVER_FAILED, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void abort(String callId, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_ABORT);
try {
@@ -723,6 +742,36 @@
}
break;
}
+ case MSG_HANDOVER_FAILED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg3, SESSION_HANDLER +
+ SESSION_HANDOVER_FAILED);
+ try {
+ final String id = (String) args.arg1;
+ final ConnectionRequest request = (ConnectionRequest) args.arg2;
+ final int reason = (int) args.arg4;
+ if (!mAreAccountsInitialized) {
+ Log.d(this, "Enqueueing pre-init request %s", id);
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER
+ + SESSION_HANDOVER_FAILED + ".pICR",
+ null /*lock*/) {
+ @Override
+ public void loggedRun() {
+ handoverFailed(id, request, reason);
+ }
+ }.prepare());
+ } else {
+ Log.i(this, "createConnectionFailed %s", id);
+ handoverFailed(id, request, reason);
+ }
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
case MSG_ABORT: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
@@ -1371,13 +1420,25 @@
isIncoming,
isUnknown);
- Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
- : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
- : onCreateOutgoingConnection(callManagerAccount, request);
+ Connection connection = null;
+ if (getApplicationContext().getApplicationInfo().targetSdkVersion >
+ Build.VERSION_CODES.O_MR1 && request.getExtras() != null &&
+ request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER,false)) {
+ if (!isIncoming) {
+ connection = onCreateOutgoingHandoverConnection(callManagerAccount, request);
+ } else {
+ connection = onCreateIncomingHandoverConnection(callManagerAccount, request);
+ }
+ } else {
+ connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
+ : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
+ : onCreateOutgoingConnection(callManagerAccount, request);
+ }
Log.d(this, "createConnection, connection: %s", connection);
if (connection == null) {
+ Log.i(this, "createConnection, implementation returned null connection.");
connection = Connection.createFailedConnection(
- new DisconnectCause(DisconnectCause.ERROR));
+ new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"));
}
connection.setTelecomCallId(callId);
@@ -1442,6 +1503,13 @@
}
}
+ private void handoverFailed(final String callId, final ConnectionRequest request,
+ int reason) {
+
+ Log.i(this, "handoverFailed %s", callId);
+ onHandoverFailed(request, reason);
+ }
+
/**
* Called by Telecom when the creation of a new Connection has completed and it is now added
* to Telecom.
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index d558bba..74fa62d 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -80,6 +80,7 @@
private static final int MSG_ON_CONNECTION_EVENT = 9;
private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
private static final int MSG_ON_RTT_INITIATION_FAILURE = 11;
+ private static final int MSG_ON_HANDOVER_FAILED = 12;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -150,6 +151,12 @@
mPhone.internalOnRttInitiationFailure(callId, reason);
break;
}
+ case MSG_ON_HANDOVER_FAILED: {
+ String callId = (String) msg.obj;
+ int error = msg.arg1;
+ mPhone.internalOnHandoverFailed(callId, error);
+ break;
+ }
default:
break;
}
@@ -225,6 +232,11 @@
public void onRttInitiationFailure(String callId, int reason) {
mHandler.obtainMessage(MSG_ON_RTT_INITIATION_FAILURE, reason, 0, callId).sendToTarget();
}
+
+ @Override
+ public void onHandoverFailed(String callId, int error) {
+ mHandler.obtainMessage(MSG_ON_HANDOVER_FAILED, error, 0, callId).sendToTarget();
+ }
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 421b1a4..b5394b9 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -223,6 +223,13 @@
}
}
+ final void internalOnHandoverFailed(String callId, int error) {
+ Call call = mCallByTelecomCallId.get(callId);
+ if (call != null) {
+ call.internalOnHandoverFailed(error);
+ }
+ }
+
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index e428286..732d00d 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -100,4 +100,7 @@
void respondToRttUpgradeRequest(String callId, in ParcelFileDescriptor fromInCall,
in ParcelFileDescriptor toInCall, in Session.Info sessionInfo);
+
+ void handoverFailed(String callId, in ConnectionRequest request,
+ int error, in Session.Info sessionInfo);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index e8cf8e9..110109e 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -54,4 +54,6 @@
void onRttUpgradeRequest(String callId, int id);
void onRttInitiationFailure(String callId, int reason);
+
+ void onHandoverFailed(String callId, int error);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d80ad36..514222d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1712,6 +1712,13 @@
public static final String KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL =
"spn_display_rule_use_roaming_from_service_state_bool";
+ /**
+ * Determines whether any carrier has been identified and its specific config has been applied,
+ * default to false.
+ * @hide
+ */
+ public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1995,6 +2002,7 @@
sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
}
/**
@@ -2040,6 +2048,33 @@
}
/**
+ * Determines whether a configuration {@link PersistableBundle} obtained from
+ * {@link #getConfig()} or {@link #getConfigForSubId(int)} corresponds to an identified carrier.
+ * <p>
+ * When an app receives the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}
+ * broadcast which informs it that the carrier configuration has changed, it is possible
+ * that another reload of the carrier configuration has begun since the intent was sent.
+ * In this case, the carrier configuration the app fetches (e.g. via {@link #getConfig()})
+ * may not represent the configuration for the current carrier. It should be noted that it
+ * does not necessarily mean the configuration belongs to current carrier when this function
+ * return true because it may belong to another previous identified carrier. Users should
+ * always call {@link #getConfig()} or {@link #getConfigForSubId(int)} after receiving the
+ * broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED}.
+ * </p>
+ * <p>
+ * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
+ * use this method to confirm whether any carrier specific configuration has been applied.
+ * </p>
+ *
+ * @param bundle the configuration bundle to be checked.
+ * @return boolean true if any carrier specific configuration bundle has been applied, false
+ * otherwise or the bundle is null.
+ */
+ public static boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) {
+ return bundle != null && bundle.getBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL);
+ }
+
+ /**
* Calling this method triggers telephony services to fetch the current carrier configuration.
* <p>
* Normally this does not need to be called because the platform reloads config on its own.
diff --git a/telephony/java/com/android/ims/internal/ISmsListener.aidl b/telephony/java/android/telephony/CellIdentityCdma.aidl
similarity index 61%
copy from telephony/java/com/android/ims/internal/ISmsListener.aidl
copy to telephony/java/android/telephony/CellIdentityCdma.aidl
index 1266f04..b31ad0b 100644
--- a/telephony/java/com/android/ims/internal/ISmsListener.aidl
+++ b/telephony/java/android/telephony/CellIdentityCdma.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 The Android Open Source Project
+ * Copyright 2017 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.
@@ -14,14 +14,7 @@
* limitations under the License.
*/
-package com.android.ims.internal;
+/** @hide */
+package android.telephony;
-/**
- * See SmsFeature for more information.
- * {@hide}
- */
-interface ISmsListener {
- void setSentSmsResult(in int messageRef, in int result);
- void setSentSmsStatusReport(in int format, in byte[] pdu);
- void deliverSms(in int format, in byte[] pdu);
-}
\ No newline at end of file
+parcelable CellIdentityCdma;
diff --git a/telephony/java/com/android/ims/internal/ISmsListener.aidl b/telephony/java/android/telephony/CellIdentityGsm.aidl
similarity index 61%
copy from telephony/java/com/android/ims/internal/ISmsListener.aidl
copy to telephony/java/android/telephony/CellIdentityGsm.aidl
index 1266f04..bcc0751 100644
--- a/telephony/java/com/android/ims/internal/ISmsListener.aidl
+++ b/telephony/java/android/telephony/CellIdentityGsm.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 The Android Open Source Project
+ * Copyright 2017 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.
@@ -14,14 +14,7 @@
* limitations under the License.
*/
-package com.android.ims.internal;
+/** @hide */
+package android.telephony;
-/**
- * See SmsFeature for more information.
- * {@hide}
- */
-interface ISmsListener {
- void setSentSmsResult(in int messageRef, in int result);
- void setSentSmsStatusReport(in int format, in byte[] pdu);
- void deliverSms(in int format, in byte[] pdu);
-}
\ No newline at end of file
+parcelable CellIdentityGsm;
diff --git a/telephony/java/com/android/ims/internal/ISmsListener.aidl b/telephony/java/android/telephony/CellIdentityLte.aidl
similarity index 61%
copy from telephony/java/com/android/ims/internal/ISmsListener.aidl
copy to telephony/java/android/telephony/CellIdentityLte.aidl
index 1266f04..940d170 100644
--- a/telephony/java/com/android/ims/internal/ISmsListener.aidl
+++ b/telephony/java/android/telephony/CellIdentityLte.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 The Android Open Source Project
+ * Copyright 2017 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.
@@ -14,14 +14,7 @@
* limitations under the License.
*/
-package com.android.ims.internal;
+/** @hide */
+package android.telephony;
-/**
- * See SmsFeature for more information.
- * {@hide}
- */
-interface ISmsListener {
- void setSentSmsResult(in int messageRef, in int result);
- void setSentSmsStatusReport(in int format, in byte[] pdu);
- void deliverSms(in int format, in byte[] pdu);
-}
\ No newline at end of file
+parcelable CellIdentityLte;
diff --git a/telephony/java/com/android/ims/internal/ISmsListener.aidl b/telephony/java/android/telephony/CellIdentityWcdma.aidl
similarity index 61%
copy from telephony/java/com/android/ims/internal/ISmsListener.aidl
copy to telephony/java/android/telephony/CellIdentityWcdma.aidl
index 1266f04..462ce2c 100644
--- a/telephony/java/com/android/ims/internal/ISmsListener.aidl
+++ b/telephony/java/android/telephony/CellIdentityWcdma.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 The Android Open Source Project
+ * Copyright 2017 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.
@@ -14,14 +14,7 @@
* limitations under the License.
*/
-package com.android.ims.internal;
+/** @hide */
+package android.telephony;
-/**
- * See SmsFeature for more information.
- * {@hide}
- */
-interface ISmsListener {
- void setSentSmsResult(in int messageRef, in int result);
- void setSentSmsStatusReport(in int format, in byte[] pdu);
- void deliverSms(in int format, in byte[] pdu);
-}
\ No newline at end of file
+parcelable CellIdentityWcdma;
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index a554c69..059a2d0 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -502,8 +502,10 @@
* Asynchronous errors through the callback may include any error not specific to the
* streaming use-case.
* @param request The request that specifies what should be downloaded.
+ * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
+ * and some other error code otherwise.
*/
- public void download(@NonNull DownloadRequest request) {
+ public int download(@NonNull DownloadRequest request) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
@@ -519,13 +521,16 @@
setTempFileRootDirectory(tempRootDirectory);
}
- writeDownloadRequestToken(request);
try {
- downloadService.download(request);
+ int result = downloadService.download(request);
+ if (result == MbmsErrors.SUCCESS) {
+ writeDownloadRequestToken(request);
+ }
+ return result;
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ return MbmsErrors.ERROR_MIDDLEWARE_LOST;
}
}
@@ -565,8 +570,10 @@
* @param callback The callback that should be called when the middleware has information to
* share on the download.
* @param handler The {@link Handler} on which calls to {@code callback} should be enqueued on.
+ * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
+ * and some other error code otherwise.
*/
- public void registerStateCallback(@NonNull DownloadRequest request,
+ public int registerStateCallback(@NonNull DownloadRequest request,
@NonNull DownloadStateCallback callback, @NonNull Handler handler) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
@@ -583,16 +590,15 @@
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
}
- sendErrorToApp(result, null);
- return;
+ return result;
}
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
- return;
+ return MbmsErrors.ERROR_MIDDLEWARE_LOST;
}
mInternalDownloadCallbacks.put(callback, internalCallback);
+ return MbmsErrors.SUCCESS;
}
/**
@@ -606,8 +612,10 @@
*
* @param request The {@link DownloadRequest} provided during registration
* @param callback The callback provided during registration.
+ * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
+ * and some other error code otherwise.
*/
- public void unregisterStateCallback(@NonNull DownloadRequest request,
+ public int unregisterStateCallback(@NonNull DownloadRequest request,
@NonNull DownloadStateCallback callback) {
try {
IMbmsDownloadService downloadService = mService.get();
@@ -617,6 +625,9 @@
InternalDownloadStateCallback internalCallback =
mInternalDownloadCallbacks.get(callback);
+ if (internalCallback == null) {
+ throw new IllegalArgumentException("Provided callback was never registered");
+ }
try {
int result = downloadService.unregisterStateCallback(request, internalCallback);
@@ -624,12 +635,12 @@
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
}
- sendErrorToApp(result, null);
+ return result;
}
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ return MbmsErrors.ERROR_MIDDLEWARE_LOST;
}
} finally {
InternalDownloadStateCallback internalCallback =
@@ -638,6 +649,7 @@
internalCallback.stop();
}
}
+ return MbmsErrors.SUCCESS;
}
/**
@@ -647,8 +659,10 @@
* this method will throw an {@link IllegalArgumentException}.
*
* @param downloadRequest The download request that you wish to cancel.
+ * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
+ * and some other error code otherwise.
*/
- public void cancelDownload(@NonNull DownloadRequest downloadRequest) {
+ public int cancelDownload(@NonNull DownloadRequest downloadRequest) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
@@ -660,16 +674,15 @@
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
}
- sendErrorToApp(result, null);
- return;
+ } else {
+ deleteDownloadRequestToken(downloadRequest);
}
+ return result;
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
- return;
+ return MbmsErrors.ERROR_MIDDLEWARE_LOST;
}
- deleteDownloadRequestToken(downloadRequest);
}
/**
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index f15fde8..a277212 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -19,50 +19,92 @@
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.annotation.IntDef;
import android.util.Log;
import com.android.internal.telephony.ITelephony;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
- * Allows applications to request the system to perform a network scan.
- *
- * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} will
- * receive a NetworkScan which contains the callback method to stop the scan requested.
- * @hide
+ * The caller of
+ * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, NetworkScanCallback)}
+ * will receive an instance of {@link NetworkScan}, which contains a callback method
+ * {@link #stop()} for stopping the in-progress scan.
*/
public class NetworkScan {
- public static final String TAG = "NetworkScan";
+ private static final String TAG = "NetworkScan";
// Below errors are mapped from RadioError which is returned from RIL. We will consolidate
// RadioErrors during the mapping if those RadioErrors mean no difference to the users.
+
+ /**
+ * Defines acceptable values of scan error code.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ERROR_MODEM_ERROR, ERROR_INVALID_SCAN, ERROR_MODEM_UNAVAILABLE, ERROR_UNSUPPORTED,
+ ERROR_RADIO_INTERFACE_ERROR, ERROR_INVALID_SCANID, ERROR_INTERRUPTED})
+ public @interface ScanErrorCode {}
+
+ /**
+ * The RIL has successfully performed the network scan.
+ */
public static final int SUCCESS = 0; // RadioError:NONE
+
+ /**
+ * The scan has failed due to some modem errors.
+ */
public static final int ERROR_MODEM_ERROR = 1; // RadioError:RADIO_NOT_AVAILABLE
// RadioError:NO_MEMORY
// RadioError:INTERNAL_ERR
// RadioError:MODEM_ERR
// RadioError:OPERATION_NOT_ALLOWED
+
+ /**
+ * The parameters of the scan is invalid.
+ */
public static final int ERROR_INVALID_SCAN = 2; // RadioError:INVALID_ARGUMENTS
- public static final int ERROR_MODEM_BUSY = 3; // RadioError:DEVICE_IN_USE
+
+ /**
+ * The modem can not perform the scan because it is doing something else.
+ */
+ public static final int ERROR_MODEM_UNAVAILABLE = 3; // RadioError:DEVICE_IN_USE
+
+ /**
+ * The modem does not support the request scan.
+ */
public static final int ERROR_UNSUPPORTED = 4; // RadioError:REQUEST_NOT_SUPPORTED
+
// Below errors are generated at the Telephony.
- public static final int ERROR_RIL_ERROR = 10000; // Nothing or only exception is
- // returned from RIL.
- public static final int ERROR_INVALID_SCANID = 10001; // The scanId is invalid. The user is
- // either trying to stop a scan which
- // does not exist or started by others.
- public static final int ERROR_INTERRUPTED = 10002; // Scan was interrupted by another scan
- // with higher priority.
+
+ /**
+ * The RIL returns nothing or exceptions.
+ */
+ public static final int ERROR_RADIO_INTERFACE_ERROR = 10000;
+
+ /**
+ * The scan ID is invalid. The user is either trying to stop a scan which does not exist
+ * or started by others.
+ */
+ public static final int ERROR_INVALID_SCANID = 10001;
+
+ /**
+ * The scan has been interrupted by another scan with higher priority.
+ */
+ public static final int ERROR_INTERRUPTED = 10002;
+
private final int mScanId;
private final int mSubId;
/**
* Stops the network scan
*
- * This is the callback method to stop an ongoing scan. When user requests a new scan,
- * a NetworkScan object will be returned, and the user can stop the scan by calling this
- * method.
+ * Use this method to stop an ongoing scan. When user requests a new scan, a {@link NetworkScan}
+ * object will be returned, and the user can stop the scan by calling this method.
*/
public void stop() throws RemoteException {
try {
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
index 9674c93..ea503c3 100644
--- a/telephony/java/android/telephony/NetworkScanRequest.java
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -16,11 +16,14 @@
package android.telephony;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Defines a request to peform a network scan.
@@ -28,7 +31,6 @@
* This class defines whether the network scan will be performed only once or periodically until
* cancelled, when the scan is performed periodically, the time interval is not controlled by the
* user but defined by the modem vendor.
- * @hide
*/
public final class NetworkScanRequest implements Parcelable {
@@ -54,6 +56,14 @@
/** @hide */
public static final int MAX_INCREMENTAL_PERIODICITY_SEC = 10;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ SCAN_TYPE_ONE_SHOT,
+ SCAN_TYPE_PERIODIC,
+ })
+ public @interface ScanType {}
+
/** Performs the scan only once */
public static final int SCAN_TYPE_ONE_SHOT = 0;
/**
@@ -65,21 +75,21 @@
public static final int SCAN_TYPE_PERIODIC = 1;
/** Defines the type of the scan. */
- public int scanType;
+ private int mScanType;
/**
* Search periodicity (in seconds).
* Expected range for the input is [5s - 300s]
- * This value must be less than or equal to maxSearchTime
+ * This value must be less than or equal to mMaxSearchTime
*/
- public int searchPeriodicity;
+ private int mSearchPeriodicity;
/**
* Maximum duration of the periodic search (in seconds).
* Expected range for the input is [60s - 3600s]
* If the search lasts this long, it will be terminated.
*/
- public int maxSearchTime;
+ private int mMaxSearchTime;
/**
* Indicates whether the modem should report incremental
@@ -87,18 +97,18 @@
* FALSE – Incremental results are not reported.
* TRUE (default) – Incremental results are reported
*/
- public boolean incrementalResults;
+ private boolean mIncrementalResults;
/**
* Indicates the periodicity with which the modem should
* report incremental results to the client (in seconds).
* Expected range for the input is [1s - 10s]
- * This value must be less than or equal to maxSearchTime
+ * This value must be less than or equal to mMaxSearchTime
*/
- public int incrementalResultsPeriodicity;
+ private int mIncrementalResultsPeriodicity;
/** Describes the radio access technologies with bands or channels that need to be scanned. */
- public RadioAccessSpecifier[] specifiers;
+ private RadioAccessSpecifier[] mSpecifiers;
/**
* Describes the List of PLMN ids (MCC-MNC)
@@ -107,20 +117,24 @@
* If list not sent, search to be completed till end and all PLMNs found to be reported.
* Max size of array is MAX_MCC_MNC_LIST_SIZE
*/
- public ArrayList<String> mccMncs;
+ private ArrayList<String> mMccMncs;
/**
- * Creates a new NetworkScanRequest with scanType and network specifiers
+ * Creates a new NetworkScanRequest with mScanType and network mSpecifiers
*
- * @param scanType The type of the scan
+ * @param scanType The type of the scan, can be either one shot or periodic
* @param specifiers the radio network with bands / channels to be scanned
- * @param searchPeriodicity Search periodicity (in seconds)
- * @param maxSearchTime Maximum duration of the periodic search (in seconds)
+ * @param searchPeriodicity The modem will restart the scan every searchPeriodicity seconds if
+ * no network has been found, until it reaches the maxSearchTime. Only
+ * valid when scan type is periodic scan.
+ * @param maxSearchTime Maximum duration of the search (in seconds)
* @param incrementalResults Indicates whether the modem should report incremental
* results of the network scan to the client
* @param incrementalResultsPeriodicity Indicates the periodicity with which the modem should
- * report incremental results to the client (in seconds)
- * @param mccMncs Describes the List of PLMN ids (MCC-MNC)
+ * report incremental results to the client (in seconds),
+ * only valid when incrementalResults is true
+ * @param mccMncs Describes the list of PLMN ids (MCC-MNC), once any network in the list has
+ * been found, the scan will be terminated by the modem.
*/
public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers,
int searchPeriodicity,
@@ -128,19 +142,63 @@
boolean incrementalResults,
int incrementalResultsPeriodicity,
ArrayList<String> mccMncs) {
- this.scanType = scanType;
- this.specifiers = specifiers;
- this.searchPeriodicity = searchPeriodicity;
- this.maxSearchTime = maxSearchTime;
- this.incrementalResults = incrementalResults;
- this.incrementalResultsPeriodicity = incrementalResultsPeriodicity;
- if (mccMncs != null) {
- this.mccMncs = mccMncs;
+ this.mScanType = scanType;
+ this.mSpecifiers = specifiers.clone();
+ this.mSearchPeriodicity = searchPeriodicity;
+ this.mMaxSearchTime = maxSearchTime;
+ this.mIncrementalResults = incrementalResults;
+ this.mIncrementalResultsPeriodicity = incrementalResultsPeriodicity;
+ if (mMccMncs != null) {
+ this.mMccMncs = (ArrayList<String>) mccMncs.clone();
} else {
- this.mccMncs = new ArrayList<>();
+ this.mMccMncs = new ArrayList<>();
}
}
+ /** Returns the type of the scan. */
+ @ScanType
+ public int getScanType() {
+ return mScanType;
+ }
+
+ /** Returns the search periodicity in seconds. */
+ public int getSearchPeriodicity() {
+ return mSearchPeriodicity;
+ }
+
+ /** Returns maximum duration of the periodic search in seconds. */
+ public int getMaxSearchTime() {
+ return mMaxSearchTime;
+ }
+
+ /**
+ * Returns whether incremental result is enabled.
+ * FALSE – Incremental results is not enabled.
+ * TRUE – Incremental results is reported.
+ */
+ public boolean getIncrementalResults() {
+ return mIncrementalResults;
+ }
+
+ /** Returns the periodicity in seconds of incremental results. */
+ public int getIncrementalResultsPeriodicity() {
+ return mIncrementalResultsPeriodicity;
+ }
+
+ /** Returns the radio access technologies with bands or channels that need to be scanned. */
+ public RadioAccessSpecifier[] getSpecifiers() {
+ return mSpecifiers.clone();
+ }
+
+ /**
+ * Returns the List of PLMN ids (MCC-MNC) for early termination of scan.
+ * If any PLMN of this list is found, search should end at that point and
+ * results with all PLMN found till that point should be sent as response.
+ */
+ public ArrayList<String> getPlmns() {
+ return (ArrayList<String>) mMccMncs.clone();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -148,26 +206,26 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(scanType);
- dest.writeParcelableArray(specifiers, flags);
- dest.writeInt(searchPeriodicity);
- dest.writeInt(maxSearchTime);
- dest.writeBoolean(incrementalResults);
- dest.writeInt(incrementalResultsPeriodicity);
- dest.writeStringList(mccMncs);
+ dest.writeInt(mScanType);
+ dest.writeParcelableArray(mSpecifiers, flags);
+ dest.writeInt(mSearchPeriodicity);
+ dest.writeInt(mMaxSearchTime);
+ dest.writeBoolean(mIncrementalResults);
+ dest.writeInt(mIncrementalResultsPeriodicity);
+ dest.writeStringList(mMccMncs);
}
private NetworkScanRequest(Parcel in) {
- scanType = in.readInt();
- specifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
+ mScanType = in.readInt();
+ mSpecifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
Object.class.getClassLoader(),
RadioAccessSpecifier.class);
- searchPeriodicity = in.readInt();
- maxSearchTime = in.readInt();
- incrementalResults = in.readBoolean();
- incrementalResultsPeriodicity = in.readInt();
- mccMncs = new ArrayList<>();
- in.readStringList(mccMncs);
+ mSearchPeriodicity = in.readInt();
+ mMaxSearchTime = in.readInt();
+ mIncrementalResults = in.readBoolean();
+ mIncrementalResultsPeriodicity = in.readInt();
+ mMccMncs = new ArrayList<>();
+ in.readStringList(mMccMncs);
}
@Override
@@ -184,25 +242,25 @@
return false;
}
- return (scanType == nsr.scanType
- && Arrays.equals(specifiers, nsr.specifiers)
- && searchPeriodicity == nsr.searchPeriodicity
- && maxSearchTime == nsr.maxSearchTime
- && incrementalResults == nsr.incrementalResults
- && incrementalResultsPeriodicity == nsr.incrementalResultsPeriodicity
- && (((mccMncs != null)
- && mccMncs.equals(nsr.mccMncs))));
+ return (mScanType == nsr.mScanType
+ && Arrays.equals(mSpecifiers, nsr.mSpecifiers)
+ && mSearchPeriodicity == nsr.mSearchPeriodicity
+ && mMaxSearchTime == nsr.mMaxSearchTime
+ && mIncrementalResults == nsr.mIncrementalResults
+ && mIncrementalResultsPeriodicity == nsr.mIncrementalResultsPeriodicity
+ && (((mMccMncs != null)
+ && mMccMncs.equals(nsr.mMccMncs))));
}
@Override
public int hashCode () {
- return ((scanType * 31)
- + (Arrays.hashCode(specifiers)) * 37
- + (searchPeriodicity * 41)
- + (maxSearchTime * 43)
- + ((incrementalResults == true? 1 : 0) * 47)
- + (incrementalResultsPeriodicity * 53)
- + (mccMncs.hashCode() * 59));
+ return ((mScanType * 31)
+ + (Arrays.hashCode(mSpecifiers)) * 37
+ + (mSearchPeriodicity * 41)
+ + (mMaxSearchTime * 43)
+ + ((mIncrementalResults == true? 1 : 0) * 47)
+ + (mIncrementalResultsPeriodicity * 53)
+ + (mMccMncs.hashCode() * 59));
}
public static final Creator<NetworkScanRequest> CREATOR =
diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java
index 33ce8b4..5412c61 100644
--- a/telephony/java/android/telephony/RadioAccessSpecifier.java
+++ b/telephony/java/android/telephony/RadioAccessSpecifier.java
@@ -25,34 +25,40 @@
* Describes a particular radio access network to be scanned.
*
* The scan can be performed on either bands or channels for a specific radio access network type.
- * @hide
*/
public final class RadioAccessSpecifier implements Parcelable {
/**
* The radio access network that needs to be scanned
*
+ * This parameter must be provided or else the scan will be rejected.
+ *
* See {@link RadioNetworkConstants.RadioAccessNetworks} for details.
*/
- public int radioAccessNetwork;
+ private int mRadioAccessNetwork;
/**
* The frequency bands that need to be scanned
*
- * bands must be used together with radioAccessNetwork
+ * When no specific bands are specified (empty array or null), all the frequency bands
+ * supported by the modem will be scanned.
*
* See {@link RadioNetworkConstants} for details.
*/
- public int[] bands;
+ private int[] mBands;
/**
* The frequency channels that need to be scanned
*
- * channels must be used together with radioAccessNetwork
+ * When any specific channels are provided for scan, the corresponding frequency bands that
+ * contains those channels must also be provided, or else the channels will be ignored.
*
- * See {@link RadioNetworkConstants.RadioAccessNetworks} for details.
+ * When no specific channels are specified (empty array or null), all the frequency channels
+ * supported by the modem will be scanned.
+ *
+ * See {@link RadioNetworkConstants} for details.
*/
- public int[] channels;
+ private int[] mChannels;
/**
* Creates a new RadioAccessSpecifier with radio network, bands and channels
@@ -65,9 +71,34 @@
* @param channels the frequency bands to be scanned
*/
public RadioAccessSpecifier(int ran, int[] bands, int[] channels) {
- this.radioAccessNetwork = ran;
- this.bands = bands;
- this.channels = channels;
+ this.mRadioAccessNetwork = ran;
+ this.mBands = bands.clone();
+ this.mChannels = channels.clone();
+ }
+
+ /**
+ * Returns the radio access network that needs to be scanned.
+ *
+ * The returned value is define in {@link RadioNetworkConstants.RadioAccessNetworks};
+ */
+ public int getRadioAccessNetwork() {
+ return mRadioAccessNetwork;
+ }
+
+ /**
+ * Returns the frequency bands that need to be scanned.
+ *
+ * The returned value is defined in either of {@link RadioNetworkConstants.GeranBands},
+ * {@link RadioNetworkConstants.UtranBands} and {@link RadioNetworkConstants.EutranBands}, and
+ * it depends on the returned value of {@link #getRadioAccessNetwork()}.
+ */
+ public int[] getBands() {
+ return mBands.clone();
+ }
+
+ /** Returns the frequency channels that need to be scanned. */
+ public int[] getChannels() {
+ return mChannels.clone();
}
public static final Parcelable.Creator<RadioAccessSpecifier> CREATOR =
@@ -90,15 +121,15 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(radioAccessNetwork);
- dest.writeIntArray(bands);
- dest.writeIntArray(channels);
+ dest.writeInt(mRadioAccessNetwork);
+ dest.writeIntArray(mBands);
+ dest.writeIntArray(mChannels);
}
private RadioAccessSpecifier(Parcel in) {
- radioAccessNetwork = in.readInt();
- bands = in.createIntArray();
- channels = in.createIntArray();
+ mRadioAccessNetwork = in.readInt();
+ mBands = in.createIntArray();
+ mChannels = in.createIntArray();
}
@Override
@@ -115,15 +146,15 @@
return false;
}
- return (radioAccessNetwork == ras.radioAccessNetwork
- && Arrays.equals(bands, ras.bands)
- && Arrays.equals(channels, ras.channels));
+ return (mRadioAccessNetwork == ras.mRadioAccessNetwork
+ && Arrays.equals(mBands, ras.mBands)
+ && Arrays.equals(mChannels, ras.mChannels));
}
@Override
public int hashCode () {
- return ((radioAccessNetwork * 31)
- + (Arrays.hashCode(bands) * 37)
- + (Arrays.hashCode(channels)) * 39);
+ return ((mRadioAccessNetwork * 31)
+ + (Arrays.hashCode(mBands) * 37)
+ + (Arrays.hashCode(mChannels)) * 39);
}
}
diff --git a/telephony/java/android/telephony/RadioNetworkConstants.java b/telephony/java/android/telephony/RadioNetworkConstants.java
index 1a9072d..5f5dd82 100644
--- a/telephony/java/android/telephony/RadioNetworkConstants.java
+++ b/telephony/java/android/telephony/RadioNetworkConstants.java
@@ -18,7 +18,6 @@
/**
* Contains radio access network related constants.
- * @hide
*/
public final class RadioNetworkConstants {
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 6029995..78a4c65 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -339,6 +339,7 @@
* Send a text based SMS without writing it into the SMS Provider.
*
* <p>Requires Permission:
+ * {@link android.Manifest.permission#SEND_SMS} and
* {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
* privileges.
* </p>
@@ -347,7 +348,10 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ android.Manifest.permission.SEND_SMS
+ })
public void sendTextMessageWithoutPersisting(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
@@ -1123,6 +1127,8 @@
// SMS send failure result codes
+ /** No error. {@hide}*/
+ static public final int RESULT_ERROR_NONE = 0;
/** Generic failure cause */
static public final int RESULT_ERROR_GENERIC_FAILURE = 1;
/** Failed because radio was explicitly turned off */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index c84db95..64cc7c1 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -361,6 +361,42 @@
public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
/**
+ * TelephonyProvider column name for enable Volte.
+ *@hide
+ */
+ public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+ /**
+ * TelephonyProvider column name for enable VT (Video Telephony over IMS)
+ *@hide
+ */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /**
+ * TelephonyProvider column name for enable Wifi calling
+ *@hide
+ */
+ public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+ /**
+ * TelephonyProvider column name for Wifi calling mode
+ *@hide
+ */
+ public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+ /**
+ * TelephonyProvider column name for Wifi calling mode in roaming
+ *@hide
+ */
+ public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+ /**
+ * TelephonyProvider column name for enable Wifi calling in roaming
+ *@hide
+ */
+ public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+ /**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
*
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index d7b6142..942ea00 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -3342,6 +3342,12 @@
public static final String APN = "apn";
/**
+ * Prefix of Integrated Circuit Card Identifier.
+ * <P>Type: TEXT </P>
+ */
+ public static final String ICCID_PREFIX = "iccid_prefix";
+
+ /**
* User facing carrier name.
* <P>Type: TEXT </P>
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 82464c1..7245dac 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4764,15 +4764,14 @@
* Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
* Or the calling app has carrier privileges. @see #hasCarrierPrivileges
- *
- * @hide
- * TODO: Add an overload that takes no args.
*/
- public void setNetworkSelectionModeAutomatic(int subId) {
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setNetworkSelectionModeAutomatic() {
try {
ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.setNetworkSelectionModeAutomatic(subId);
+ if (telephony != null) {
+ telephony.setNetworkSelectionModeAutomatic(getSubId());
+ }
} catch (RemoteException ex) {
Rlog.e(TAG, "setNetworkSelectionModeAutomatic RemoteException", ex);
} catch (NullPointerException ex) {
@@ -4820,9 +4819,9 @@
*
* @param request Contains all the RAT with bands/channels that need to be scanned.
* @param callback Returns network scan results or errors.
- * @return A NetworkScan obj which contains a callback which can stop the scan.
- * @hide
+ * @return A NetworkScan obj which contains a callback which can be used to stop the scan.
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public NetworkScan requestNetworkScan(
NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) {
synchronized (this) {
@@ -4841,15 +4840,20 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
* Or the calling app has carrier privileges. @see #hasCarrierPrivileges
*
- * @hide
- * TODO: Add an overload that takes no args.
+ * @param operatorNumeric the PLMN ID of the network to select.
+ * @param persistSelection whether the selection will persist until reboot. If true, only allows
+ * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
+ * normal network selection next time.
+ * @return true on success; false on any failure.
*/
- public boolean setNetworkSelectionModeManual(int subId, OperatorInfo operator,
- boolean persistSelection) {
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
try {
ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.setNetworkSelectionModeManual(subId, operator, persistSelection);
+ if (telephony != null) {
+ return telephony.setNetworkSelectionModeManual(
+ getSubId(), operatorNumeric, persistSelection);
+ }
} catch (RemoteException ex) {
Rlog.e(TAG, "setNetworkSelectionModeManual RemoteException", ex);
} catch (NullPointerException ex) {
@@ -4874,8 +4878,9 @@
public boolean setPreferredNetworkType(int subId, int networkType) {
try {
ITelephony telephony = getITelephony();
- if (telephony != null)
+ if (telephony != null) {
return telephony.setPreferredNetworkType(subId, networkType);
+ }
} catch (RemoteException ex) {
Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex);
} catch (NullPointerException ex) {
@@ -5854,45 +5859,6 @@
return false;
}
- /**
- * This function retrieves value for setting "name+subId", and if that is not found
- * retrieves value for setting "name", and if that is not found throws
- * SettingNotFoundException
- *
- * @hide
- */
- public static int getIntWithSubId(ContentResolver cr, String name, int subId)
- throws SettingNotFoundException {
- try {
- return Settings.Global.getInt(cr, name + subId);
- } catch (SettingNotFoundException e) {
- try {
- int val = Settings.Global.getInt(cr, name);
- Settings.Global.putInt(cr, name + subId, val);
-
- /* We are now moving from 'setting' to 'setting+subId', and using the value stored
- * for 'setting' as default. Reset the default (since it may have a user set
- * value). */
- int default_val = val;
- if (name.equals(Settings.Global.MOBILE_DATA)) {
- default_val = "true".equalsIgnoreCase(
- SystemProperties.get("ro.com.android.mobiledata", "true")) ? 1 : 0;
- } else if (name.equals(Settings.Global.DATA_ROAMING)) {
- default_val = "true".equalsIgnoreCase(
- SystemProperties.get("ro.com.android.dataroaming", "false")) ? 1 : 0;
- }
-
- if (default_val != val) {
- Settings.Global.putInt(cr, name, default_val);
- }
-
- return val;
- } catch (SettingNotFoundException exc) {
- throw new SettingNotFoundException(name);
- }
- }
- }
-
/**
* Returns the IMS Registration Status
* @hide
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 7bcdcdc..c182e34 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -38,7 +38,6 @@
/**
* Manages the radio access network scan requests and callbacks.
- * @hide
*/
public final class TelephonyScanManager {
@@ -55,7 +54,8 @@
public static final int CALLBACK_SCAN_COMPLETE = 3;
/**
- * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} should
+ * The caller of
+ * {@link TelephonyManager#requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} should
* implement and provide this callback so that the scan results or errors can be returned.
*/
public static abstract class NetworkScanCallback {
@@ -75,8 +75,10 @@
*
* This callback will be called whenever there is any error about the scan, and the scan
* will be terminated. onComplete() will NOT be called.
+ *
+ * @param error Error code when the scan is failed, as defined in {@link NetworkScan}.
*/
- public void onError(int error) {}
+ public void onError(@NetworkScan.ScanErrorCode int error) {}
}
private static class NetworkScanInfo {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a13af5f..84d0087 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -168,12 +168,10 @@
public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
private final Context mContext;
- private final IEuiccController mController;
/** @hide */
public EuiccManager(Context context) {
mContext = context;
- mController = IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
}
/**
@@ -189,7 +187,7 @@
public boolean isEnabled() {
// In the future, this may reach out to IEuiccController (if non-null) to check any dynamic
// restrictions.
- return mController != null;
+ return getIEuiccController() != null;
}
/**
@@ -206,7 +204,7 @@
return null;
}
try {
- return mController.getEid();
+ return getIEuiccController().getEid();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -232,7 +230,7 @@
return;
}
try {
- mController.downloadSubscription(subscription, switchAfterDownload,
+ getIEuiccController().downloadSubscription(subscription, switchAfterDownload,
mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -296,7 +294,7 @@
return;
}
try {
- mController.continueOperation(resolutionIntent, resolutionExtras);
+ getIEuiccController().continueOperation(resolutionIntent, resolutionExtras);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -328,7 +326,7 @@
return;
}
try {
- mController.getDownloadableSubscriptionMetadata(
+ getIEuiccController().getDownloadableSubscriptionMetadata(
subscription, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -358,7 +356,7 @@
return;
}
try {
- mController.getDefaultDownloadableSubscriptionList(
+ getIEuiccController().getDefaultDownloadableSubscriptionList(
mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -377,7 +375,7 @@
return null;
}
try {
- return mController.getEuiccInfo();
+ return getIEuiccController().getEuiccInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -402,7 +400,7 @@
return;
}
try {
- mController.deleteSubscription(
+ getIEuiccController().deleteSubscription(
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -429,7 +427,7 @@
return;
}
try {
- mController.switchToSubscription(
+ getIEuiccController().switchToSubscription(
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -455,7 +453,8 @@
return;
}
try {
- mController.updateSubscriptionNickname(subscriptionId, nickname, callbackIntent);
+ getIEuiccController().updateSubscriptionNickname(
+ subscriptionId, nickname, callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -477,7 +476,7 @@
return;
}
try {
- mController.eraseSubscriptions(callbackIntent);
+ getIEuiccController().eraseSubscriptions(callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -507,7 +506,7 @@
return;
}
try {
- mController.retainSubscriptionsForFactoryReset(callbackIntent);
+ getIEuiccController().retainSubscriptionsForFactoryReset(callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -520,4 +519,8 @@
// Caller canceled the callback; do nothing.
}
}
+
+ private static IEuiccController getIEuiccController() {
+ return IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/SmsFeature.java b/telephony/java/android/telephony/ims/feature/SmsFeature.java
deleted file mode 100644
index c1366db..0000000
--- a/telephony/java/android/telephony/ims/feature/SmsFeature.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2017 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.ims.feature;
-
-import android.annotation.SystemApi;
-import android.os.RemoteException;
-import com.android.ims.internal.IImsSmsFeature;
-import com.android.ims.internal.ISmsListener;
-
-/**
- * Base implementation of SMS over IMS functionality.
- *
- * @hide
- */
-public class SmsFeature extends ImsFeature {
- /**
- * SMS over IMS format is 3gpp.
- */
- public static final int IMS_SMS_FORMAT_3GPP = 1;
-
- /**
- * SMS over IMS format is 3gpp2.
- */
- public static final int IMS_SMS_FORMAT_3GPP2 = 2;
-
- /**
- * Message was sent successfully.
- */
- public static final int SEND_STATUS_OK = 1;
-
- /**
- * IMS provider failed to send the message and platform should not retry falling back to sending
- * the message using the radio.
- */
- public static final int SEND_STATUS_ERROR = 2;
-
- /**
- * IMS provider failed to send the message and platform should retry again after setting TP-RD bit
- * to high.
- */
- public static final int SEND_STATUS_ERROR_RETRY = 3;
-
- /**
- * IMS provider failed to send the message and platform should retry falling back to sending
- * the message using the radio.
- */
- public static final int SEND_STATUS_ERROR_FALLBACK = 4;
-
- /**
- * Message was delivered successfully.
- */
- public static final int DELIVER_STATUS_OK = 1;
-
- /**
- * Message was not delivered.
- */
- public static final int DELIVER_STATUS_ERROR = 2;
-
- // Lock for feature synchronization
- private final Object mLock = new Object();
- private ISmsListener mSmsListener;
-
- private final IImsSmsFeature mIImsSmsBinder = new IImsSmsFeature.Stub() {
- @Override
- public void registerSmsListener(ISmsListener listener) {
- synchronized (mLock) {
- SmsFeature.this.registerSmsListener(listener);
- }
- }
-
- @Override
- public void sendSms(int format, int messageRef, boolean retry, byte[] pdu) {
- synchronized (mLock) {
- SmsFeature.this.sendSms(format, messageRef, retry, pdu);
- }
- }
-
- @Override
- public void acknowledgeSms(int messageRef, int result) {
- synchronized (mLock) {
- SmsFeature.this.acknowledgeSms(messageRef, result);
- }
- }
-
- @Override
- public int getSmsFormat() {
- synchronized (mLock) {
- return SmsFeature.this.getSmsFormat();
- }
- }
- };
-
- /**
- * Registers a listener responsible for handling tasks like delivering messages.
-
- * @param listener listener to register.
- *
- * @hide
- */
- @SystemApi
- public final void registerSmsListener(ISmsListener listener) {
- synchronized (mLock) {
- mSmsListener = listener;
- }
- }
-
- /**
- * This method will be triggered by the platform when the user attempts to send an SMS. This
- * method should be implemented by the IMS providers to provide implementation of sending an SMS
- * over IMS.
- *
- * @param format the format of the message. One of {@link #IMS_SMS_FORMAT_3GPP} or
- * {@link #IMS_SMS_FORMAT_3GPP2}
- * @param messageRef the message reference.
- * @param retry whether it is a retry of an already attempted message or not.
- * @param pdu PDUs representing the contents of the message.
- */
- public void sendSms(int format, int messageRef, boolean isRetry, byte[] pdu) {
- }
-
- /**
- * This method will be triggered by the platform after {@link #deliverSms(int, byte[])} has been
- * called to deliver the result to the IMS provider. It will also be triggered after
- * {@link #setSentSmsResult(int, int)} has been called to provide the result of the operation.
- *
- * @param result Should be {@link #DELIVER_STATUS_OK} if the message was delivered successfully,
- * {@link #DELIVER_STATUS_ERROR} otherwise.
- * @param messageRef the message reference.
- */
- public void acknowledgeSms(int messageRef, int result) {
-
- }
-
- /**
- * This method should be triggered by the IMS providers when there is an incoming message. The
- * platform will deliver the message to the messages database and notify the IMS provider of the
- * result by calling {@link #acknowledgeSms(int)}.
- *
- * This method must not be called before {@link #onFeatureReady()} is called.
- *
- * @param format the format of the message.One of {@link #IMS_SMS_FORMAT_3GPP} or
- * {@link #IMS_SMS_FORMAT_3GPP2}
- * @param pdu PDUs representing the contents of the message.
- * @throws IllegalStateException if called before {@link #onFeatureReady()}
- */
- public final void deliverSms(int format, byte[] pdu) throws IllegalStateException {
- // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
- // otherwise.
- try {
- mSmsListener.deliverSms(format, pdu);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * This method should be triggered by the IMS providers to pass the result of the sent message
- * to the platform.
- *
- * This method must not be called before {@link #onFeatureReady()} is called.
- *
- * @param messageRef the message reference.
- * @param result One of {@link #SEND_STATUS_OK}, {@link #SEND_STATUS_ERROR},
- * {@link #SEND_STATUS_ERROR_RETRY}, {@link #SEND_STATUS_ERROR_FALLBACK}
- * @throws IllegalStateException if called before {@link #onFeatureReady()}
- */
- public final void setSentSmsResult(int messageRef, int result) throws IllegalStateException {
- // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
- // otherwise.
- try {
- mSmsListener.setSentSmsResult(messageRef, result);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Sets the status report of the sent message.
- *
- * @param format Should be {@link #IMS_SMS_FORMAT_3GPP} or {@link #IMS_SMS_FORMAT_3GPP2}
- * @param pdu PDUs representing the content of the status report.
- * @throws IllegalStateException if called before {@link #onFeatureReady()}
- */
- public final void setSentSmsStatusReport(int format, byte[] pdu) {
- // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
- // otherwise.
- try {
- mSmsListener.setSentSmsStatusReport(format, pdu);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Returns the SMS format. Default is {@link #IMS_SMS_FORMAT_3GPP} unless overridden by IMS
- * Provider.
- *
- * @return sms format.
- */
- public int getSmsFormat() {
- return IMS_SMS_FORMAT_3GPP;
- }
-
- /**
- * {@inheritDoc}
- */
- public void onFeatureReady() {
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onFeatureRemoved() {
-
- }
-
- /**
- * @hide
- */
- @Override
- public final IImsSmsFeature getBinder() {
- return mIImsSmsBinder;
- }
-}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/internal/SmsImplBase.java b/telephony/java/android/telephony/ims/internal/SmsImplBase.java
new file mode 100644
index 0000000..47414cf
--- /dev/null
+++ b/telephony/java/android/telephony/ims/internal/SmsImplBase.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2017 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.ims.internal;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import android.telephony.ims.internal.aidl.IImsSmsListener;
+import android.telephony.ims.internal.feature.MmTelFeature;
+import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base implementation for SMS over IMS.
+ *
+ * Any service wishing to provide SMS over IMS should extend this class and implement all methods
+ * that the service supports.
+ * @hide
+ */
+public class SmsImplBase {
+ private static final String LOG_TAG = "SmsImplBase";
+
+ @IntDef({
+ SEND_STATUS_OK,
+ SEND_STATUS_ERROR,
+ SEND_STATUS_ERROR_RETRY,
+ SEND_STATUS_ERROR_FALLBACK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SendStatusResult {}
+ /**
+ * Message was sent successfully.
+ */
+ public static final int SEND_STATUS_OK = 1;
+
+ /**
+ * IMS provider failed to send the message and platform should not retry falling back to sending
+ * the message using the radio.
+ */
+ public static final int SEND_STATUS_ERROR = 2;
+
+ /**
+ * IMS provider failed to send the message and platform should retry again after setting TP-RD bit
+ * to high.
+ */
+ public static final int SEND_STATUS_ERROR_RETRY = 3;
+
+ /**
+ * IMS provider failed to send the message and platform should retry falling back to sending
+ * the message using the radio.
+ */
+ public static final int SEND_STATUS_ERROR_FALLBACK = 4;
+
+ @IntDef({
+ DELIVER_STATUS_OK,
+ DELIVER_STATUS_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DeliverStatusResult {}
+ /**
+ * Message was delivered successfully.
+ */
+ public static final int DELIVER_STATUS_OK = 1;
+
+ /**
+ * Message was not delivered.
+ */
+ public static final int DELIVER_STATUS_ERROR = 2;
+
+ @IntDef({
+ STATUS_REPORT_STATUS_OK,
+ STATUS_REPORT_STATUS_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StatusReportResult {}
+
+ /**
+ * Status Report was set successfully.
+ */
+ public static final int STATUS_REPORT_STATUS_OK = 1;
+
+ /**
+ * Error while setting status report.
+ */
+ public static final int STATUS_REPORT_STATUS_ERROR = 2;
+
+
+ // Lock for feature synchronization
+ private final Object mLock = new Object();
+ private IImsSmsListener mListener;
+
+ /**
+ * Registers a listener responsible for handling tasks like delivering messages.
+ *
+ * @param listener listener to register.
+ *
+ * @hide
+ */
+ public final void registerSmsListener(IImsSmsListener listener) {
+ synchronized (mLock) {
+ mListener = listener;
+ }
+ }
+
+ /**
+ * This method will be triggered by the platform when the user attempts to send an SMS. This
+ * method should be implemented by the IMS providers to provide implementation of sending an SMS
+ * over IMS.
+ *
+ * @param smsc the Short Message Service Center address.
+ * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
+ * {@link SmsMessage#FORMAT_3GPP2}.
+ * @param messageRef the message reference.
+ * @param isRetry whether it is a retry of an already attempted message or not.
+ * @param pdu PDUs representing the contents of the message.
+ */
+ public void sendSms(int messageRef, String format, String smsc, boolean isRetry, byte[] pdu) {
+ // Base implementation returns error. Should be overridden.
+ try {
+ onSendSmsResult(messageRef, SEND_STATUS_ERROR, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Can not send sms: " + e.getMessage());
+ }
+ }
+
+ /**
+ * This method will be triggered by the platform after {@link #onSmsReceived(String, byte[])} has
+ * been called to deliver the result to the IMS provider.
+ *
+ * @param result result of delivering the message. Valid values are defined in
+ * {@link DeliverStatusResult}
+ * @param messageRef the message reference or -1 of unavailable.
+ */
+ public void acknowledgeSms(int messageRef, @DeliverStatusResult int result) {
+
+ }
+
+ /**
+ * This method will be triggered by the platform after
+ * {@link #onSmsStatusReportReceived(int, int, byte[])} has been called to provide the result to
+ * the IMS provider.
+ *
+ * @param result result of delivering the message. Valid values are defined in
+ * {@link StatusReportResult}
+ * @param messageRef the message reference or -1 of unavailable.
+ */
+ public void acknowledgeSmsReport(int messageRef, @StatusReportResult int result) {
+
+ }
+
+ /**
+ * This method should be triggered by the IMS providers when there is an incoming message. The
+ * platform will deliver the message to the messages database and notify the IMS provider of the
+ * result by calling {@link #acknowledgeSms(int, int)}.
+ *
+ * This method must not be called before {@link MmTelFeature#onFeatureReady()} is called.
+ *
+ * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
+ * {@link SmsMessage#FORMAT_3GPP2}.
+ * @param pdu PDUs representing the contents of the message.
+ * @throws IllegalStateException if called before {@link MmTelFeature#onFeatureReady()}
+ */
+ public final void onSmsReceived(String format, byte[] pdu) throws IllegalStateException {
+ synchronized (mLock) {
+ if (mListener == null) {
+ throw new IllegalStateException("Feature not ready.");
+ }
+ try {
+ mListener.onSmsReceived(format, pdu);
+ acknowledgeSms(-1, DELIVER_STATUS_OK);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Can not deliver sms: " + e.getMessage());
+ acknowledgeSms(-1, DELIVER_STATUS_ERROR);
+ }
+ }
+ }
+
+ /**
+ * This method should be triggered by the IMS providers to pass the result of the sent message
+ * to the platform.
+ *
+ * This method must not be called before {@link MmTelFeature#onFeatureReady()} is called.
+ *
+ * @param messageRef the message reference. Should be between 0 and 255 per TS.123.040
+ * @param status result of sending the SMS. Valid values are defined in {@link SendStatusResult}
+ * @param reason reason in case status is failure. Valid values are:
+ * {@link SmsManager#RESULT_ERROR_NONE},
+ * {@link SmsManager#RESULT_ERROR_GENERIC_FAILURE},
+ * {@link SmsManager#RESULT_ERROR_RADIO_OFF},
+ * {@link SmsManager#RESULT_ERROR_NULL_PDU},
+ * {@link SmsManager#RESULT_ERROR_NO_SERVICE},
+ * {@link SmsManager#RESULT_ERROR_LIMIT_EXCEEDED},
+ * {@link SmsManager#RESULT_ERROR_SHORT_CODE_NOT_ALLOWED},
+ * {@link SmsManager#RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED}
+ * @throws IllegalStateException if called before {@link MmTelFeature#onFeatureReady()}
+ * @throws RemoteException if the connection to the framework is not available. If this happens
+ * attempting to send the SMS should be aborted.
+ */
+ public final void onSendSmsResult(int messageRef, @SendStatusResult int status, int reason)
+ throws IllegalStateException, RemoteException {
+ synchronized (mLock) {
+ if (mListener == null) {
+ throw new IllegalStateException("Feature not ready.");
+ }
+ mListener.onSendSmsResult(messageRef, status, reason);
+ }
+ }
+
+ /**
+ * Sets the status report of the sent message.
+ *
+ * @param messageRef the message reference.
+ * @param format the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
+ * {@link SmsMessage#FORMAT_3GPP2}.
+ * @param pdu PDUs representing the content of the status report.
+ * @throws IllegalStateException if called before {@link MmTelFeature#onFeatureReady()}
+ */
+ public final void onSmsStatusReportReceived(int messageRef, String format, byte[] pdu) {
+ synchronized (mLock) {
+ if (mListener == null) {
+ throw new IllegalStateException("Feature not ready.");
+ }
+ try {
+ mListener.onSmsStatusReportReceived(messageRef, format, pdu);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Can not process sms status report: " + e.getMessage());
+ acknowledgeSmsReport(messageRef, STATUS_REPORT_STATUS_ERROR);
+ }
+ }
+ }
+
+ /**
+ * Returns the SMS format. Default is {@link SmsMessage#FORMAT_3GPP} unless overridden by IMS
+ * Provider.
+ *
+ * @return the format of the message. Valid values are {@link SmsMessage#FORMAT_3GPP} and
+ * {@link SmsMessage#FORMAT_3GPP2}.
+ */
+ public String getSmsFormat() {
+ return SmsMessage.FORMAT_3GPP;
+ }
+
+}
diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl
index 7125781..d976686 100644
--- a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl
+++ b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl
@@ -18,6 +18,7 @@
import android.os.Message;
import android.telephony.ims.internal.aidl.IImsMmTelListener;
+import android.telephony.ims.internal.aidl.IImsSmsListener;
import android.telephony.ims.internal.aidl.IImsCapabilityCallback;
import android.telephony.ims.internal.aidl.IImsCallSessionListener;
import android.telephony.ims.internal.feature.CapabilityChangeRequest;
@@ -30,7 +31,7 @@
import com.android.ims.internal.IImsUt;
/**
- * See MmTelFeature for more information.
+ * See SmsImplBase for more information.
* {@hide}
*/
interface IImsMmTelFeature {
@@ -49,4 +50,10 @@
IImsCapabilityCallback c);
oneway void queryCapabilityConfiguration(int capability, int radioTech,
IImsCapabilityCallback c);
+ // SMS APIs
+ void setSmsListener(IImsSmsListener l);
+ oneway void sendSms(int messageRef, String format, String smsc, boolean retry, in byte[] pdu);
+ oneway void acknowledgeSms(int messageRef, int result);
+ oneway void acknowledgeSmsReport(int messageRef, int result);
+ String getSmsFormat();
}
diff --git a/telephony/java/com/android/ims/internal/ISmsListener.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl
similarity index 65%
rename from telephony/java/com/android/ims/internal/ISmsListener.aidl
rename to telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl
index 1266f04..468629a 100644
--- a/telephony/java/com/android/ims/internal/ISmsListener.aidl
+++ b/telephony/java/android/telephony/ims/internal/aidl/IImsSmsListener.aidl
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.ims.internal;
+package android.telephony.ims.internal.aidl;
/**
- * See SmsFeature for more information.
+ * See MMTelFeature for more information.
* {@hide}
*/
-interface ISmsListener {
- void setSentSmsResult(in int messageRef, in int result);
- void setSentSmsStatusReport(in int format, in byte[] pdu);
- void deliverSms(in int format, in byte[] pdu);
+interface IImsSmsListener {
+ void onSendSmsResult(in int messageRef, in int status, in int reason);
+ void onSmsStatusReportReceived(in int messageRef, in String format, in byte[] pdu);
+ void onSmsReceived(in String format, in byte[] pdu);
}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java
index f183a57..2f350c8 100644
--- a/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java
@@ -21,11 +21,15 @@
import android.os.RemoteException;
import android.telecom.TelecomManager;
import android.telephony.ims.internal.ImsCallSessionListener;
+import android.telephony.ims.internal.SmsImplBase;
+import android.telephony.ims.internal.SmsImplBase.DeliverStatusResult;
+import android.telephony.ims.internal.SmsImplBase.StatusReportResult;
import android.telephony.ims.internal.aidl.IImsCallSessionListener;
import android.telephony.ims.internal.aidl.IImsCapabilityCallback;
import android.telephony.ims.internal.aidl.IImsMmTelFeature;
import android.telephony.ims.internal.aidl.IImsMmTelListener;
import android.telephony.ims.internal.stub.ImsRegistrationImplBase;
+import android.telephony.ims.internal.aidl.IImsSmsListener;
import android.telephony.ims.stub.ImsEcbmImplBase;
import android.telephony.ims.stub.ImsMultiEndpointImplBase;
import android.telephony.ims.stub.ImsUtImplBase;
@@ -64,6 +68,11 @@
}
@Override
+ public void setSmsListener(IImsSmsListener l) throws RemoteException {
+ MmTelFeature.this.setSmsListener(l);
+ }
+
+ @Override
public int getFeatureState() throws RemoteException {
synchronized (mLock) {
return MmTelFeature.this.getFeatureState();
@@ -143,6 +152,34 @@
IImsCapabilityCallback c) {
queryCapabilityConfigurationInternal(capability, radioTech, c);
}
+
+ @Override
+ public void sendSms(int messageRef, String format, String smsc, boolean retry, byte[] pdu) {
+ synchronized (mLock) {
+ MmTelFeature.this.sendSms(messageRef, format, smsc, retry, pdu);
+ }
+ }
+
+ @Override
+ public void acknowledgeSms(int messageRef, int result) {
+ synchronized (mLock) {
+ MmTelFeature.this.acknowledgeSms(messageRef, result);
+ }
+ }
+
+ @Override
+ public void acknowledgeSmsReport(int messageRef, int result) {
+ synchronized (mLock) {
+ MmTelFeature.this.acknowledgeSmsReport(messageRef, result);
+ }
+ }
+
+ @Override
+ public String getSmsFormat() {
+ synchronized (mLock) {
+ return MmTelFeature.this.getSmsFormat();
+ }
+ }
};
/**
@@ -171,7 +208,8 @@
value = {
CAPABILITY_TYPE_VOICE,
CAPABILITY_TYPE_VIDEO,
- CAPABILITY_TYPE_UT
+ CAPABILITY_TYPE_UT,
+ CAPABILITY_TYPE_SMS
})
@Retention(RetentionPolicy.SOURCE)
public @interface MmTelCapability {}
@@ -191,6 +229,11 @@
*/
public static final int CAPABILITY_TYPE_UT = 1 << 2;
+ /**
+ * This MmTelFeature supports SMS (IR.92)
+ */
+ public static final int CAPABILITY_TYPE_SMS = 1 << 3;
+
@Override
public final void addCapabilities(@MmTelCapability int capabilities) {
super.addCapabilities(capabilities);
@@ -239,6 +282,10 @@
}
}
+ private void setSmsListener(IImsSmsListener listener) {
+ getSmsImplementation().registerSmsListener(listener);
+ }
+
private void queryCapabilityConfigurationInternal(int capability, int radioTech,
IImsCapabilityCallback c) {
boolean enabled = queryCapabilityConfiguration(capability, radioTech);
@@ -400,6 +447,32 @@
// Base Implementation - Should be overridden
}
+ private void sendSms(int messageRef, String format, String smsc, boolean isRetry, byte[] pdu) {
+ getSmsImplementation().sendSms(messageRef, format, smsc, isRetry, pdu);
+ }
+
+ private void acknowledgeSms(int messageRef, @DeliverStatusResult int result) {
+ getSmsImplementation().acknowledgeSms(messageRef, result);
+ }
+
+ private void acknowledgeSmsReport(int messageRef, @StatusReportResult int result) {
+ getSmsImplementation().acknowledgeSmsReport(messageRef, result);
+ }
+
+ private String getSmsFormat() {
+ return getSmsImplementation().getSmsFormat();
+ }
+
+ /**
+ * Must be overridden by IMS Provider to be able to support SMS over IMS. Otherwise a default
+ * non-functional implementation is returned.
+ *
+ * @return an instance of {@link SmsImplBase} which should be implemented by the IMS Provider.
+ */
+ protected SmsImplBase getSmsImplementation() {
+ return new SmsImplBase();
+ }
+
/**{@inheritDoc}*/
@Override
public void onFeatureRemoved() {
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index 8529f52..f78e7a6 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -51,8 +51,8 @@
/** @hide */
public ServiceInfo(Map<Locale, String> newNames, String newClassName, List<Locale> newLocales,
String newServiceId, Date start, Date end) {
- if (newNames == null || newNames.isEmpty() || TextUtils.isEmpty(newClassName)
- || newLocales == null || newLocales.isEmpty() || TextUtils.isEmpty(newServiceId)
+ if (newNames == null || newClassName == null
+ || newLocales == null || newServiceId == null
|| start == null || end == null) {
throw new IllegalArgumentException("Bad ServiceInfo construction");
}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 6ad54c1..4f6f68c 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -104,6 +104,9 @@
// MT : No action from user after alerting the call
public static final int CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE = 203;
+ //Call was blocked by call barring
+ public static final int CODE_CALL_BARRED = 240;
+
//Call failures for FDN
public static final int CODE_FDN_BLOCKED = 241;
diff --git a/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl b/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl
deleted file mode 100644
index 5068128..0000000
--- a/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2017 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.ims.internal;
-
-import com.android.ims.internal.ISmsListener;
-
-/**
- * See SmsFeature for more information.
- *
- * {@hide}
- */
-interface IImsSmsFeature {
- void registerSmsListener(in ISmsListener listener);
- void sendSms(in int format, in int messageRef, in boolean retry, in byte[] pdu);
- void acknowledgeSms(in int messageRef, in int result);
- int getSmsFormat();
-}
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index fd6091a..64083e3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -846,13 +846,13 @@
* Ask the radio to connect to the input network and change selection mode to manual.
*
* @param subId the id of the subscription.
- * @param operatorInfo the operator to attach to.
- * @param persistSelection should the selection persist till reboot or its
- * turned off? Will also result in notification being not shown to
- * the user if the signal is lost.
+ * @param operatorNumeric the PLMN of the operator to attach to.
+ * @param persistSelection Whether the selection will persist until reboot. If true, only allows
+ * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
+ * normal network selection next time.
* @return true if the request suceeded.
*/
- boolean setNetworkSelectionModeManual(int subId, in OperatorInfo operator,
+ boolean setNetworkSelectionModeManual(int subId, in String operatorNumeric,
boolean persistSelection);
/**
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index e2d25b8..f804cb0 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -417,6 +417,8 @@
int RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION = 141;
int RIL_REQUEST_START_NETWORK_SCAN = 142;
int RIL_REQUEST_STOP_NETWORK_SCAN = 143;
+ int RIL_REQUEST_GET_SLOT_STATUS = 144;
+ int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 145;
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
@@ -471,4 +473,5 @@
int RIL_UNSOL_MODEM_RESTART = 1047;
int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1048;
int RIL_UNSOL_NETWORK_SCAN_RESULT = 1049;
+ int RIL_UNSOL_ICC_SLOT_STATUS = 1050;
}
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 99a82ad..9f8b3a8 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -32,6 +32,12 @@
public class IccUtils {
static final String LOG_TAG="IccUtils";
+ // A table mapping from a number to a hex character for fast encoding hex strings.
+ private static final char[] HEX_CHARS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+
/**
* Many fields in GSM SIM's are stored as nibble-swizzled BCD
*
@@ -62,6 +68,41 @@
}
/**
+ * Converts a bcd byte array to String with offset 0 and byte array length.
+ */
+ public static String bcdToString(byte[] data) {
+ return bcdToString(data, 0, data.length);
+ }
+
+ /**
+ * Converts BCD string to bytes.
+ *
+ * @param bcd This should have an even length. If not, an "0" will be appended to the string.
+ */
+ public static byte[] bcdToBytes(String bcd) {
+ byte[] output = new byte[(bcd.length() + 1) / 2];
+ bcdToBytes(bcd, output);
+ return output;
+ }
+
+ /**
+ * Converts BCD string to bytes and put it into the given byte array.
+ *
+ * @param bcd This should have an even length. If not, an "0" will be appended to the string.
+ * @param bytes If the array size is less than needed, the rest of the BCD string isn't be
+ * converted. If the array size is more than needed, the rest of array remains unchanged.
+ */
+ public static void bcdToBytes(String bcd, byte[] bytes) {
+ if (bcd.length() % 2 != 0) {
+ bcd += "0";
+ }
+ int size = Math.min(bytes.length * 2, bcd.length());
+ for (int i = 0, j = 0; i + 1 < size; i += 2, j++) {
+ bytes[j] = (byte) (charToByte(bcd.charAt(i + 1)) << 4 | charToByte(bcd.charAt(i)));
+ }
+ }
+
+ /**
* PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3
* Returns a concatenated string of MCC+MNC, stripping
* all invalid character 'f'
@@ -94,10 +135,10 @@
int v;
v = data[i] & 0xf;
- ret.append("0123456789abcdef".charAt(v));
+ ret.append(HEX_CHARS[v]);
v = (data[i] >> 4) & 0xf;
- ret.append("0123456789abcdef".charAt(v));
+ ret.append(HEX_CHARS[v]);
}
return ret.toString();
@@ -305,7 +346,7 @@
return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim());
}
- static int
+ public static int
hexCharToInt(char c) {
if (c >= '0' && c <= '9') return (c - '0');
if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
@@ -361,11 +402,11 @@
b = 0x0f & (bytes[i] >> 4);
- ret.append("0123456789abcdef".charAt(b));
+ ret.append(HEX_CHARS[b]);
b = 0x0f & bytes[i];
- ret.append("0123456789abcdef".charAt(b));
+ ret.append(HEX_CHARS[b]);
}
return ret.toString();
@@ -416,7 +457,6 @@
if ((data[offset] & 0x40) != 0) {
// FIXME(mkf) add country initials here
-
}
return ret;
@@ -575,4 +615,239 @@
}
return iccId.substring( 0, position );
}
+
+ /**
+ * Converts a series of bytes to an integer. This method currently only supports positive 32-bit
+ * integers.
+ *
+ * @param src The source bytes.
+ * @param offset The position of the first byte of the data to be converted. The data is base
+ * 256 with the most significant digit first.
+ * @param length The length of the data to be converted. It must be <= 4.
+ * @throws IllegalArgumentException If {@code length} is bigger than 4 or {@code src} cannot be
+ * parsed as a positive integer.
+ * @throws IndexOutOfBoundsException If the range defined by {@code offset} and {@code length}
+ * exceeds the bounds of {@code src}.
+ */
+ public static int bytesToInt(byte[] src, int offset, int length) {
+ if (length > 4) {
+ throw new IllegalArgumentException(
+ "length must be <= 4 (only 32-bit integer supported): " + length);
+ }
+ if (offset < 0 || length < 0 || offset + length > src.length) {
+ throw new IndexOutOfBoundsException(
+ "Out of the bounds: src=["
+ + src.length
+ + "], offset="
+ + offset
+ + ", length="
+ + length);
+ }
+ int result = 0;
+ for (int i = 0; i < length; i++) {
+ result = (result << 8) | (src[offset + i] & 0xFF);
+ }
+ if (result < 0) {
+ throw new IllegalArgumentException(
+ "src cannot be parsed as a positive integer: " + result);
+ }
+ return result;
+ }
+
+ /**
+ * Converts a series of bytes to a raw long variable which can be both positive and negative.
+ * This method currently only supports 64-bit long variable.
+ *
+ * @param src The source bytes.
+ * @param offset The position of the first byte of the data to be converted. The data is base
+ * 256 with the most significant digit first.
+ * @param length The length of the data to be converted. It must be <= 8.
+ * @throws IllegalArgumentException If {@code length} is bigger than 8.
+ * @throws IndexOutOfBoundsException If the range defined by {@code offset} and {@code length}
+ * exceeds the bounds of {@code src}.
+ */
+ public static long bytesToRawLong(byte[] src, int offset, int length) {
+ if (length > 8) {
+ throw new IllegalArgumentException(
+ "length must be <= 8 (only 64-bit long supported): " + length);
+ }
+ if (offset < 0 || length < 0 || offset + length > src.length) {
+ throw new IndexOutOfBoundsException(
+ "Out of the bounds: src=["
+ + src.length
+ + "], offset="
+ + offset
+ + ", length="
+ + length);
+ }
+ long result = 0;
+ for (int i = 0; i < length; i++) {
+ result = (result << 8) | (src[offset + i] & 0xFF);
+ }
+ return result;
+ }
+
+ /**
+ * Converts an integer to a new byte array with base 256 and the most significant digit first.
+ *
+ * @throws IllegalArgumentException If {@code value} is negative.
+ */
+ public static byte[] unsignedIntToBytes(int value) {
+ if (value < 0) {
+ throw new IllegalArgumentException("value must be 0 or positive: " + value);
+ }
+ byte[] bytes = new byte[byteNumForUnsignedInt(value)];
+ unsignedIntToBytes(value, bytes, 0);
+ return bytes;
+ }
+
+ /**
+ * Converts an integer to a new byte array with base 256 and the most significant digit first.
+ * The first byte's highest bit is used for sign. If the most significant digit is larger than
+ * 127, an extra byte (0) will be prepended before it. This method currently doesn't support
+ * negative values.
+ *
+ * @throws IllegalArgumentException If {@code value} is negative.
+ */
+ public static byte[] signedIntToBytes(int value) {
+ if (value < 0) {
+ throw new IllegalArgumentException("value must be 0 or positive: " + value);
+ }
+ byte[] bytes = new byte[byteNumForSignedInt(value)];
+ signedIntToBytes(value, bytes, 0);
+ return bytes;
+ }
+
+ /**
+ * Converts an integer to a series of bytes with base 256 and the most significant digit first.
+ *
+ * @param value The integer to be converted.
+ * @param dest The destination byte array.
+ * @param offset The start offset of the byte array.
+ * @return The number of byte needeed.
+ * @throws IllegalArgumentException If {@code value} is negative.
+ * @throws IndexOutOfBoundsException If {@code offset} exceeds the bounds of {@code dest}.
+ */
+ public static int unsignedIntToBytes(int value, byte[] dest, int offset) {
+ return intToBytes(value, dest, offset, false);
+ }
+
+ /**
+ * Converts an integer to a series of bytes with base 256 and the most significant digit first.
+ * The first byte's highest bit is used for sign. If the most significant digit is larger than
+ * 127, an extra byte (0) will be prepended before it. This method currently doesn't support
+ * negative values.
+ *
+ * @throws IllegalArgumentException If {@code value} is negative.
+ * @throws IndexOutOfBoundsException If {@code offset} exceeds the bounds of {@code dest}.
+ */
+ public static int signedIntToBytes(int value, byte[] dest, int offset) {
+ return intToBytes(value, dest, offset, true);
+ }
+
+ /**
+ * Calculates the number of required bytes to represent {@code value}. The bytes will be base
+ * 256 with the most significant digit first.
+ *
+ * @throws IllegalArgumentException If {@code value} is negative.
+ */
+ public static int byteNumForUnsignedInt(int value) {
+ return byteNumForInt(value, false);
+ }
+
+ /**
+ * Calculates the number of required bytes to represent {@code value}. The bytes will be base
+ * 256 with the most significant digit first. If the most significant digit is larger than 127,
+ * an extra byte (0) will be prepended before it. This method currently only supports positive
+ * integers.
+ *
+ * @throws IllegalArgumentException If {@code value} is negative.
+ */
+ public static int byteNumForSignedInt(int value) {
+ return byteNumForInt(value, true);
+ }
+
+ private static int intToBytes(int value, byte[] dest, int offset, boolean signed) {
+ int l = byteNumForInt(value, signed);
+ if (offset < 0 || offset + l > dest.length) {
+ throw new IndexOutOfBoundsException("Not enough space to write. Required bytes: " + l);
+ }
+ for (int i = l - 1, v = value; i >= 0; i--, v >>>= 8) {
+ byte b = (byte) (v & 0xFF);
+ dest[offset + i] = b;
+ }
+ return l;
+ }
+
+ private static int byteNumForInt(int value, boolean signed) {
+ if (value < 0) {
+ throw new IllegalArgumentException("value must be 0 or positive: " + value);
+ }
+ if (signed) {
+ if (value <= 0x7F) {
+ return 1;
+ }
+ if (value <= 0x7FFF) {
+ return 2;
+ }
+ if (value <= 0x7FFFFF) {
+ return 3;
+ }
+ } else {
+ if (value <= 0xFF) {
+ return 1;
+ }
+ if (value <= 0xFFFF) {
+ return 2;
+ }
+ if (value <= 0xFFFFFF) {
+ return 3;
+ }
+ }
+ return 4;
+ }
+
+
+ /**
+ * Counts the number of trailing zero bits of a byte.
+ */
+ public static byte countTrailingZeros(byte b) {
+ if (b == 0) {
+ return 8;
+ }
+ int v = b & 0xFF;
+ byte c = 7;
+ if ((v & 0x0F) != 0) {
+ c -= 4;
+ }
+ if ((v & 0x33) != 0) {
+ c -= 2;
+ }
+ if ((v & 0x55) != 0) {
+ c -= 1;
+ }
+ return c;
+ }
+
+ /**
+ * Converts a byte to a hex string.
+ */
+ public static String byteToHex(byte b) {
+ return new String(new char[] {HEX_CHARS[(b & 0xFF) >>> 4], HEX_CHARS[b & 0xF]});
+ }
+
+ /**
+ * 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.
+ */
+ private static byte charToByte(char c) {
+ if (c >= 0x30 && c <= 0x39) {
+ return (byte) (c - 0x30);
+ } else if (c >= 0x41 && c <= 0x46) {
+ return (byte) (c - 0x37);
+ } else if (c >= 0x61 && c <= 0x66) {
+ return (byte) (c - 0x57);
+ }
+ return 0;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/uicc/asn1/Asn1Decoder.java b/telephony/java/com/android/internal/telephony/uicc/asn1/Asn1Decoder.java
new file mode 100644
index 0000000..1ad0b66
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/uicc/asn1/Asn1Decoder.java
@@ -0,0 +1,151 @@
+/*
+ * 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.uicc.asn1;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+/**
+ * This represents a decoder helping decode an array of bytes or a hex string into
+ * {@link Asn1Node}s. This class tracks the next position for decoding. This class is not
+ * thread-safe.
+ */
+public final class Asn1Decoder {
+ // Source byte array.
+ private final byte[] mSrc;
+ // Next position of the byte in the source array for decoding.
+ private int mPosition;
+ // Exclusive end of the range in the array for decoding.
+ private final int mEnd;
+
+ /** Creates a decoder on a hex string. */
+ public Asn1Decoder(String hex) {
+ this(IccUtils.hexStringToBytes(hex));
+ }
+
+ /** Creates a decoder on a byte array. */
+ public Asn1Decoder(byte[] src) {
+ this(src, 0, src.length);
+ }
+
+ /**
+ * Creates a decoder on a byte array slice.
+ *
+ * @throws IndexOutOfBoundsException If the range defined by {@code offset} and {@code length}
+ * exceeds the bounds of {@code bytes}.
+ */
+ public Asn1Decoder(byte[] bytes, int offset, int length) {
+ if (offset < 0 || length < 0 || offset + length > bytes.length) {
+ throw new IndexOutOfBoundsException(
+ "Out of the bounds: bytes=["
+ + bytes.length
+ + "], offset="
+ + offset
+ + ", length="
+ + length);
+ }
+ mSrc = bytes;
+ mPosition = offset;
+ mEnd = offset + length;
+ }
+
+ /** @return The next start position for decoding. */
+ public int getPosition() {
+ return mPosition;
+ }
+
+ /** Returns whether the node has a next node. */
+ public boolean hasNextNode() {
+ return mPosition < mEnd;
+ }
+
+ /**
+ * Parses the next node. If the node is a constructed node, its children will be parsed only
+ * when they are accessed, e.g., though {@link Asn1Node#getChildren()}.
+ *
+ * @return The next decoded {@link Asn1Node}. If success, the next decoding position will also
+ * be updated. If any error happens, e.g., moving over the end position, {@code null}
+ * will be returned and the next decoding position won't be modified.
+ * @throws InvalidAsn1DataException If the bytes cannot be parsed.
+ */
+ public Asn1Node nextNode() throws InvalidAsn1DataException {
+ if (mPosition >= mEnd) {
+ throw new IllegalStateException("No bytes to parse.");
+ }
+
+ int offset = mPosition;
+
+ // Extracts the tag.
+ int tagStart = offset;
+ byte b = mSrc[offset++];
+ if ((b & 0x1F) == 0x1F) {
+ // High-tag-number form
+ while (offset < mEnd && (mSrc[offset++] & 0x80) != 0) {
+ // Do nothing.
+ }
+ }
+ if (offset >= mEnd) {
+ // No length bytes or the tag is too long.
+ throw new InvalidAsn1DataException(0, "Invalid length at position: " + offset);
+ }
+ int tag;
+ try {
+ tag = IccUtils.bytesToInt(mSrc, tagStart, offset - tagStart);
+ } catch (IllegalArgumentException e) {
+ // Cannot parse the tag as an integer.
+ throw new InvalidAsn1DataException(0, "Cannot parse tag at position: " + tagStart, e);
+ }
+
+ // Extracts the length.
+ int dataLen;
+ b = mSrc[offset++];
+ if ((b & 0x80) == 0) {
+ // Short-form length
+ dataLen = b;
+ } else {
+ // Long-form length
+ int lenLen = b & 0x7F;
+ if (offset + lenLen > mEnd) {
+ // No enough bytes for the long-form length
+ throw new InvalidAsn1DataException(
+ tag, "Cannot parse length at position: " + offset);
+ }
+ try {
+ dataLen = IccUtils.bytesToInt(mSrc, offset, lenLen);
+ } catch (IllegalArgumentException e) {
+ // Cannot parse the data length as an integer.
+ throw new InvalidAsn1DataException(
+ tag, "Cannot parse length at position: " + offset, e);
+ }
+ offset += lenLen;
+ }
+ if (offset + dataLen > mEnd) {
+ // No enough data left.
+ throw new InvalidAsn1DataException(
+ tag,
+ "Incomplete data at position: "
+ + offset
+ + ", expected bytes: "
+ + dataLen
+ + ", actual bytes: "
+ + (mEnd - offset));
+ }
+
+ Asn1Node root = new Asn1Node(tag, mSrc, offset, dataLen);
+ mPosition = offset + dataLen;
+ return root;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/uicc/asn1/Asn1Node.java b/telephony/java/com/android/internal/telephony/uicc/asn1/Asn1Node.java
new file mode 100644
index 0000000..5eb1d5c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/uicc/asn1/Asn1Node.java
@@ -0,0 +1,598 @@
+/*
+ * 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.uicc.asn1;
+
+import android.annotation.Nullable;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This represents a primitive or constructed data defined by ASN.1. A constructed node can have
+ * child nodes. A non-constructed node can have a value. This class is read-only. To build a node,
+ * you can use the {@link #newBuilder(int)} method to get a {@link Builder} instance. This class is
+ * not thread-safe.
+ */
+public final class Asn1Node {
+ private static final int INT_BYTES = Integer.SIZE / Byte.SIZE;
+ private static final List<Asn1Node> EMPTY_NODE_LIST = Collections.emptyList();
+
+ // Bytes for boolean values.
+ private static final byte[] TRUE_BYTES = new byte[] {-1};
+ private static final byte[] FALSE_BYTES = new byte[] {0};
+
+ /**
+ * This class is used to build an Asn1Node instance of a constructed tag. This class is not
+ * thread-safe.
+ */
+ public static final class Builder {
+ private final int mTag;
+ private final List<Asn1Node> mChildren;
+
+ private Builder(int tag) {
+ if (!isConstructedTag(tag)) {
+ throw new IllegalArgumentException(
+ "Builder should be created for a constructed tag: " + tag);
+ }
+ mTag = tag;
+ mChildren = new ArrayList<>();
+ }
+
+ /**
+ * Adds a child from an existing node.
+ *
+ * @return This builder.
+ * @throws IllegalArgumentException If the child is a non-existing node.
+ */
+ public Builder addChild(Asn1Node child) {
+ mChildren.add(child);
+ return this;
+ }
+
+ /**
+ * Adds a child from another builder. The child will be built with the call to this method,
+ * and any changes to the child builder after the call to this method doesn't have effect.
+ *
+ * @return This builder.
+ */
+ public Builder addChild(Builder child) {
+ mChildren.add(child.build());
+ return this;
+ }
+
+ /**
+ * Adds children from bytes. This method calls {@link Asn1Decoder} to verify the {@code
+ * encodedBytes} and adds all nodes parsed from it as children.
+ *
+ * @return This builder.
+ * @throws InvalidAsn1DataException If the data bytes cannot be parsed.
+ */
+ public Builder addChildren(byte[] encodedBytes) throws InvalidAsn1DataException {
+ Asn1Decoder subDecoder = new Asn1Decoder(encodedBytes, 0, encodedBytes.length);
+ while (subDecoder.hasNextNode()) {
+ mChildren.add(subDecoder.nextNode());
+ }
+ return this;
+ }
+
+ /**
+ * Adds a child of non-constructed tag with an integer as the data.
+ *
+ * @return This builder.
+ * @throws IllegalStateException If the {@code tag} is not constructed..
+ */
+ public Builder addChildAsInteger(int tag, int value) {
+ if (isConstructedTag(tag)) {
+ throw new IllegalStateException("Cannot set value of a constructed tag: " + tag);
+ }
+ byte[] dataBytes = IccUtils.signedIntToBytes(value);
+ addChild(new Asn1Node(tag, dataBytes, 0, dataBytes.length));
+ return this;
+ }
+
+ /**
+ * Adds a child of non-constructed tag with a string as the data.
+ *
+ * @return This builder.
+ * @throws IllegalStateException If the {@code tag} is not constructed..
+ */
+ public Builder addChildAsString(int tag, String value) {
+ if (isConstructedTag(tag)) {
+ throw new IllegalStateException("Cannot set value of a constructed tag: " + tag);
+ }
+ byte[] dataBytes = value.getBytes(StandardCharsets.UTF_8);
+ addChild(new Asn1Node(tag, dataBytes, 0, dataBytes.length));
+ return this;
+ }
+
+ /**
+ * Adds a child of non-constructed tag with a byte array as the data.
+ *
+ * @param value The value will be owned by this node.
+ * @return This builder.
+ * @throws IllegalStateException If the {@code tag} is not constructed..
+ */
+ public Builder addChildAsBytes(int tag, byte[] value) {
+ if (isConstructedTag(tag)) {
+ throw new IllegalStateException("Cannot set value of a constructed tag: " + tag);
+ }
+ addChild(new Asn1Node(tag, value, 0, value.length));
+ return this;
+ }
+
+ /**
+ * Adds a child of non-constructed tag with a byte array as the data from a hex string.
+ *
+ * @return This builder.
+ * @throws IllegalStateException If the {@code tag} is not constructed..
+ */
+ public Builder addChildAsBytesFromHex(int tag, String hex) {
+ return addChildAsBytes(tag, IccUtils.hexStringToBytes(hex));
+ }
+
+ /**
+ * Adds a child of non-constructed tag with bits as the data.
+ *
+ * @return This builder.
+ * @throws IllegalStateException If the {@code tag} is not constructed..
+ */
+ public Builder addChildAsBits(int tag, int value) {
+ if (isConstructedTag(tag)) {
+ throw new IllegalStateException("Cannot set value of a constructed tag: " + tag);
+ }
+ // Always allocate 5 bytes for simplicity.
+ byte[] dataBytes = new byte[INT_BYTES + 1];
+ // Puts the integer into the byte[1-4].
+ value = Integer.reverse(value);
+ int dataLength = 0;
+ for (int i = 1; i < dataBytes.length; i++) {
+ dataBytes[i] = (byte) (value >> ((INT_BYTES - i) * Byte.SIZE));
+ if (dataBytes[i] != 0) {
+ dataLength = i;
+ }
+ }
+ dataLength++;
+ // The first byte is the number of trailing zeros of the last byte.
+ dataBytes[0] = IccUtils.countTrailingZeros(dataBytes[dataLength - 1]);
+ addChild(new Asn1Node(tag, dataBytes, 0, dataLength));
+ return this;
+ }
+
+ /**
+ * Adds a child of non-constructed tag with a boolean as the data.
+ *
+ * @return This builder.
+ * @throws IllegalStateException If the {@code tag} is not constructed..
+ */
+ public Builder addChildAsBoolean(int tag, boolean value) {
+ if (isConstructedTag(tag)) {
+ throw new IllegalStateException("Cannot set value of a constructed tag: " + tag);
+ }
+ addChild(new Asn1Node(tag, value ? TRUE_BYTES : FALSE_BYTES, 0, 1));
+ return this;
+ }
+
+ /** Builds the node. */
+ public Asn1Node build() {
+ return new Asn1Node(mTag, mChildren);
+ }
+ }
+
+ private final int mTag;
+ private final boolean mConstructed;
+ // Do not use this field directly in the methods other than the constructor and encoding
+ // methods (e.g., toBytes()), but always use getChildren() instead.
+ private final List<Asn1Node> mChildren;
+
+ // Byte array that actually holds the data. For a non-constructed node, this stores its actual
+ // value. If the value is not set, this is null. For constructed node, this stores encoded data
+ // of its children, which will be decoded on the first call to getChildren().
+ private @Nullable byte[] mDataBytes;
+ // Offset of the data in above byte array.
+ private int mDataOffset;
+ // Length of the data in above byte array. If it's a constructed node, this is always the total
+ // length of all its children.
+ private int mDataLength;
+ // Length of the total bytes required to encode this node.
+ private int mEncodedLength;
+
+ /**
+ * Creates a new ASN.1 data node builder with the given tag. The tag is an encoded tag including
+ * the tag class, tag number, and constructed mask.
+ */
+ public static Builder newBuilder(int tag) {
+ return new Builder(tag);
+ }
+
+ private static boolean isConstructedTag(int tag) {
+ // Constructed mask is at the 6th bit.
+ byte[] tagBytes = IccUtils.unsignedIntToBytes(tag);
+ return (tagBytes[0] & 0x20) != 0;
+ }
+
+ private static int calculateEncodedBytesNumForLength(int length) {
+ // Constructed mask is at the 6th bit.
+ int len = 1;
+ if (length > 127) {
+ len += IccUtils.byteNumForUnsignedInt(length);
+ }
+ return len;
+ }
+
+ /**
+ * Creates a node with given data bytes. If it is a constructed node, its children will be
+ * parsed when they are visited.
+ */
+ Asn1Node(int tag, @Nullable byte[] src, int offset, int length) {
+ mTag = tag;
+ // Constructed mask is at the 6th bit.
+ mConstructed = isConstructedTag(tag);
+ mDataBytes = src;
+ mDataOffset = offset;
+ mDataLength = length;
+ mChildren = mConstructed ? new ArrayList<Asn1Node>() : EMPTY_NODE_LIST;
+ mEncodedLength =
+ IccUtils.byteNumForUnsignedInt(mTag)
+ + calculateEncodedBytesNumForLength(mDataLength)
+ + mDataLength;
+ }
+
+ /** Creates a constructed node with given children. */
+ private Asn1Node(int tag, List<Asn1Node> children) {
+ mTag = tag;
+ mConstructed = true;
+ mChildren = children;
+
+ mDataLength = 0;
+ int size = children.size();
+ for (int i = 0; i < size; i++) {
+ mDataLength += children.get(i).mEncodedLength;
+ }
+ mEncodedLength =
+ IccUtils.byteNumForUnsignedInt(mTag)
+ + calculateEncodedBytesNumForLength(mDataLength)
+ + mDataLength;
+ }
+
+ public int getTag() {
+ return mTag;
+ }
+
+ public boolean isConstructed() {
+ return mConstructed;
+ }
+
+ /**
+ * Tests if a node has a child.
+ *
+ * @param tag The tag of an immediate child.
+ * @param tags The tags of lineal descendant.
+ */
+ public boolean hasChild(int tag, int... tags) throws InvalidAsn1DataException {
+ try {
+ getChild(tag, tags);
+ } catch (TagNotFoundException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Gets the first child node having the given {@code tag} and {@code tags}.
+ *
+ * @param tag The tag of an immediate child.
+ * @param tags The tags of lineal descendant.
+ * @throws TagNotFoundException If the child cannot be found.
+ */
+ public Asn1Node getChild(int tag, int... tags)
+ throws TagNotFoundException, InvalidAsn1DataException {
+ if (!mConstructed) {
+ throw new TagNotFoundException(tag);
+ }
+ int index = 0;
+ Asn1Node node = this;
+ while (node != null) {
+ List<Asn1Node> children = node.getChildren();
+ int size = children.size();
+ Asn1Node foundChild = null;
+ for (int i = 0; i < size; i++) {
+ Asn1Node child = children.get(i);
+ if (child.getTag() == tag) {
+ foundChild = child;
+ break;
+ }
+ }
+ node = foundChild;
+ if (index >= tags.length) {
+ break;
+ }
+ tag = tags[index++];
+ }
+ if (node == null) {
+ throw new TagNotFoundException(tag);
+ }
+ return node;
+ }
+
+ /**
+ * Gets all child nodes which have the given {@code tag}.
+ *
+ * @return If this is primitive or no such children are found, an empty list will be returned.
+ */
+ public List<Asn1Node> getChildren(int tag)
+ throws TagNotFoundException, InvalidAsn1DataException {
+ if (!mConstructed) {
+ return EMPTY_NODE_LIST;
+ }
+
+ List<Asn1Node> children = getChildren();
+ if (children.isEmpty()) {
+ return EMPTY_NODE_LIST;
+ }
+ List<Asn1Node> output = new ArrayList<>();
+ int size = children.size();
+ for (int i = 0; i < size; i++) {
+ Asn1Node child = children.get(i);
+ if (child.getTag() == tag) {
+ output.add(child);
+ }
+ }
+ return output.isEmpty() ? EMPTY_NODE_LIST : output;
+ }
+
+ /**
+ * Gets all child nodes of this node. If it's a constructed node having encoded data, it's
+ * children will be decoded here.
+ *
+ * @return If this is primitive, an empty list will be returned. Do not modify the returned list
+ * directly.
+ */
+ public List<Asn1Node> getChildren() throws InvalidAsn1DataException {
+ if (!mConstructed) {
+ return EMPTY_NODE_LIST;
+ }
+
+ if (mDataBytes != null) {
+ Asn1Decoder subDecoder = new Asn1Decoder(mDataBytes, mDataOffset, mDataLength);
+ while (subDecoder.hasNextNode()) {
+ mChildren.add(subDecoder.nextNode());
+ }
+ mDataBytes = null;
+ mDataOffset = 0;
+ }
+ return mChildren;
+ }
+
+ /** @return Whether this node has a value. False will be returned for a constructed node. */
+ public boolean hasValue() {
+ return !mConstructed && mDataBytes != null;
+ }
+
+ /**
+ * @return The data as an integer. If the data length is larger than 4, only the first 4 bytes
+ * will be parsed.
+ * @throws InvalidAsn1DataException If the data bytes cannot be parsed.
+ */
+ public int asInteger() throws InvalidAsn1DataException {
+ if (mConstructed) {
+ throw new IllegalStateException("Cannot get value of a constructed node.");
+ }
+ if (mDataBytes == null) {
+ throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null.");
+ }
+ try {
+ return IccUtils.bytesToInt(mDataBytes, mDataOffset, mDataLength);
+ } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+ throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e);
+ }
+ }
+
+ /**
+ * @return The data as a long variable which can be both positive and negative. If the data
+ * length is larger than 8, only the first 8 bytes will be parsed.
+ * @throws InvalidAsn1DataException If the data bytes cannot be parsed.
+ */
+ public long asRawLong() throws InvalidAsn1DataException {
+ if (mConstructed) {
+ throw new IllegalStateException("Cannot get value of a constructed node.");
+ }
+ if (mDataBytes == null) {
+ throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null.");
+ }
+ try {
+ return IccUtils.bytesToRawLong(mDataBytes, mDataOffset, mDataLength);
+ } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+ throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e);
+ }
+ }
+
+ /**
+ * @return The data as a string in UTF-8 encoding.
+ * @throws InvalidAsn1DataException If the data bytes cannot be parsed.
+ */
+ public String asString() throws InvalidAsn1DataException {
+ if (mConstructed) {
+ throw new IllegalStateException("Cannot get value of a constructed node.");
+ }
+ if (mDataBytes == null) {
+ throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null.");
+ }
+ try {
+ return new String(mDataBytes, mDataOffset, mDataLength, StandardCharsets.UTF_8);
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e);
+ }
+ }
+
+ /**
+ * @return The data as a byte array.
+ * @throws InvalidAsn1DataException If the data bytes cannot be parsed.
+ */
+ public byte[] asBytes() throws InvalidAsn1DataException {
+ if (mConstructed) {
+ throw new IllegalStateException("Cannot get value of a constructed node.");
+ }
+ if (mDataBytes == null) {
+ throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null.");
+ }
+ byte[] output = new byte[mDataLength];
+ try {
+ System.arraycopy(mDataBytes, mDataOffset, output, 0, mDataLength);
+ } catch (IndexOutOfBoundsException e) {
+ throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e);
+ }
+ return output;
+ }
+
+ /**
+ * Gets the data as an integer for BIT STRING. DER actually stores the bits in a reversed order.
+ * The returned integer here has the order fixed (first bit is at the lowest position). This
+ * method currently only support at most 32 bits which fit in an integer.
+ *
+ * @return The data as an integer. If this is constructed, a {@code null} will be returned.
+ * @throws InvalidAsn1DataException If the data bytes cannot be parsed.
+ */
+ public int asBits() throws InvalidAsn1DataException {
+ if (mConstructed) {
+ throw new IllegalStateException("Cannot get value of a constructed node.");
+ }
+ if (mDataBytes == null) {
+ throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null.");
+ }
+ int bits;
+ try {
+ bits = IccUtils.bytesToInt(mDataBytes, mDataOffset + 1, mDataLength - 1);
+ } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+ throw new InvalidAsn1DataException(mTag, "Cannot parse data bytes.", e);
+ }
+ for (int i = mDataLength - 1; i < INT_BYTES; i++) {
+ bits <<= Byte.SIZE;
+ }
+ return Integer.reverse(bits);
+ }
+
+ /**
+ * @return The data as a boolean.
+ * @throws InvalidAsn1DataException If the data bytes cannot be parsed.
+ */
+ public boolean asBoolean() throws InvalidAsn1DataException {
+ if (mConstructed) {
+ throw new IllegalStateException("Cannot get value of a constructed node.");
+ }
+ if (mDataBytes == null) {
+ throw new InvalidAsn1DataException(mTag, "Data bytes cannot be null.");
+ }
+ if (mDataLength != 1) {
+ throw new InvalidAsn1DataException(
+ mTag, "Cannot parse data bytes as boolean: length=" + mDataLength);
+ }
+ if (mDataOffset < 0 || mDataOffset >= mDataBytes.length) {
+ throw new InvalidAsn1DataException(
+ mTag,
+ "Cannot parse data bytes.",
+ new ArrayIndexOutOfBoundsException(mDataOffset));
+ }
+ // ASN.1 has "true" as 0xFF.
+ if (mDataBytes[mDataOffset] == -1) {
+ return Boolean.TRUE;
+ } else if (mDataBytes[mDataOffset] == 0) {
+ return Boolean.FALSE;
+ }
+ throw new InvalidAsn1DataException(
+ mTag, "Cannot parse data bytes as boolean: " + mDataBytes[mDataOffset]);
+ }
+
+ /** @return The number of required bytes for encoding this node in DER. */
+ public int getEncodedLength() {
+ return mEncodedLength;
+ }
+
+ /** @return The number of required bytes for encoding this node's data in DER. */
+ public int getDataLength() {
+ return mDataLength;
+ }
+
+ /**
+ * Writes the DER encoded bytes of this node into a byte array. The number of written bytes is
+ * {@link #getEncodedLength()}.
+ *
+ * @throws IndexOutOfBoundsException If the {@code dest} doesn't have enough space to write.
+ */
+ public void writeToBytes(byte[] dest, int offset) {
+ if (offset < 0 || offset + mEncodedLength > dest.length) {
+ throw new IndexOutOfBoundsException(
+ "Not enough space to write. Required bytes: " + mEncodedLength);
+ }
+ write(dest, offset);
+ }
+
+ /** Writes the DER encoded bytes of this node into a new byte array. */
+ public byte[] toBytes() {
+ byte[] dest = new byte[mEncodedLength];
+ write(dest, 0);
+ return dest;
+ }
+
+ /** Gets a hex string representing the DER encoded bytes of this node. */
+ public String toHex() {
+ return IccUtils.bytesToHexString(toBytes());
+ }
+
+ /** Gets header (tag + length) as hex string. */
+ public String getHeadAsHex() {
+ String headHex = IccUtils.bytesToHexString(IccUtils.unsignedIntToBytes(mTag));
+ if (mDataLength <= 127) {
+ headHex += IccUtils.byteToHex((byte) mDataLength);
+ } else {
+ byte[] lenBytes = IccUtils.unsignedIntToBytes(mDataLength);
+ headHex += IccUtils.byteToHex((byte) (lenBytes.length | 0x80));
+ headHex += IccUtils.bytesToHexString(lenBytes);
+ }
+ return headHex;
+ }
+
+ /** Returns the new offset where to write the next node data. */
+ private int write(byte[] dest, int offset) {
+ // Writes the tag.
+ offset += IccUtils.unsignedIntToBytes(mTag, dest, offset);
+ // Writes the length.
+ if (mDataLength <= 127) {
+ dest[offset++] = (byte) mDataLength;
+ } else {
+ // Bytes required for encoding the length
+ int lenLen = IccUtils.unsignedIntToBytes(mDataLength, dest, ++offset);
+ dest[offset - 1] = (byte) (lenLen | 0x80);
+ offset += lenLen;
+ }
+ // Writes the data.
+ if (mConstructed && mDataBytes == null) {
+ int size = mChildren.size();
+ for (int i = 0; i < size; i++) {
+ Asn1Node child = mChildren.get(i);
+ offset = child.write(dest, offset);
+ }
+ } else if (mDataBytes != null) {
+ System.arraycopy(mDataBytes, mDataOffset, dest, offset, mDataLength);
+ offset += mDataLength;
+ }
+ return offset;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/uicc/asn1/InvalidAsn1DataException.java b/telephony/java/com/android/internal/telephony/uicc/asn1/InvalidAsn1DataException.java
new file mode 100644
index 0000000..c151468
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/uicc/asn1/InvalidAsn1DataException.java
@@ -0,0 +1,45 @@
+/*
+ * 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.uicc.asn1;
+
+/**
+ * Exception for invalid ASN.1 data in DER encoding which cannot be parsed as a node or a specific
+ * data type.
+ */
+public class InvalidAsn1DataException extends Exception {
+ private final int mTag;
+
+ public InvalidAsn1DataException(int tag, String message) {
+ super(message);
+ mTag = tag;
+ }
+
+ public InvalidAsn1DataException(int tag, String message, Throwable throwable) {
+ super(message, throwable);
+ mTag = tag;
+ }
+
+ /** @return The tag which has the invalid data. */
+ public int getTag() {
+ return mTag;
+ }
+
+ @Override
+ public String getMessage() {
+ return super.getMessage() + " (tag=" + mTag + ")";
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/uicc/asn1/TagNotFoundException.java b/telephony/java/com/android/internal/telephony/uicc/asn1/TagNotFoundException.java
new file mode 100644
index 0000000..f79021e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/uicc/asn1/TagNotFoundException.java
@@ -0,0 +1,38 @@
+/*
+ * 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.uicc.asn1;
+
+/**
+ * Exception for getting a child of a {@link Asn1Node} with a non-existing tag.
+ */
+public class TagNotFoundException extends Exception {
+ private final int mTag;
+
+ public TagNotFoundException(int tag) {
+ mTag = tag;
+ }
+
+ /** @return The tag which has the invalid data. */
+ public int getTag() {
+ return mTag;
+ }
+
+ @Override
+ public String getMessage() {
+ return super.getMessage() + " (tag=" + mTag + ")";
+ }
+}
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 558dbb6..473dc538 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -73,18 +73,18 @@
}
@Test
- public void testToSafeString() {
+ public void testToOuiString() {
String[][] macs = {
- {"07:00:d3:56:8a:c4", "07:00:d3:00:00:00"},
- {"33:33:aa:bb:cc:dd", "33:33:aa:00:00:00"},
- {"06:00:00:00:00:00", "06:00:00:00:00:00"},
- {"07:00:d3:56:8a:c4", "07:00:d3:00:00:00"}
+ {"07:00:d3:56:8a:c4", "07:00:d3"},
+ {"33:33:aa:bb:cc:dd", "33:33:aa"},
+ {"06:00:00:00:00:00", "06:00:00"},
+ {"07:00:d3:56:8a:c4", "07:00:d3"}
};
for (String[] pair : macs) {
String mac = pair[0];
String expected = pair[1];
- assertEquals(expected, MacAddress.fromString(mac).toSafeString());
+ assertEquals(expected, MacAddress.fromString(mac).toOuiString());
}
}
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 8683c12..5d1e10e 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -27,6 +27,7 @@
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -40,10 +41,14 @@
import android.net.IpSecUdpEncapResponse;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.system.ErrnoException;
import android.system.Os;
+import android.system.StructStat;
+
+import dalvik.system.SocketTagger;
import java.io.FileDescriptor;
import java.net.InetAddress;
@@ -56,6 +61,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
/** Unit tests for {@link IpSecService}. */
@SmallTest
@@ -411,4 +417,84 @@
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
}
}
+
+ @Test
+ public void testUidFdtagger() throws Exception {
+ SocketTagger actualSocketTagger = SocketTagger.get();
+
+ try {
+ FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ // Has to be done after socket creation because BlockGuardOS calls tag on new sockets
+ SocketTagger mockSocketTagger = mock(SocketTagger.class);
+ SocketTagger.set(mockSocketTagger);
+
+ mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID);
+ verify(mockSocketTagger).tag(eq(sockFd));
+ } finally {
+ SocketTagger.set(actualSocketTagger);
+ }
+ }
+
+ /**
+ * Checks if two file descriptors point to the same file.
+ *
+ * <p>According to stat.h documentation, the correct way to check for equivalent or duplicated
+ * file descriptors is to check their inode and device. These two entries uniquely identify any
+ * file.
+ */
+ private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) {
+ try {
+ StructStat fd1Stat = Os.fstat(fd1);
+ StructStat fd2Stat = Os.fstat(fd2);
+
+ return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev;
+ } catch (ErrnoException e) {
+ return false;
+ }
+ }
+
+ @Test
+ public void testOpenUdpEncapSocketTagsSocket() throws Exception {
+ IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
+ IpSecService testIpSecService =
+ new IpSecService(mMockContext, mMockIpSecSrvConfig, mockTagger);
+
+ IpSecUdpEncapResponse udpEncapResp =
+ testIpSecService.openUdpEncapsulationSocket(0, new Binder());
+ assertNotNull(udpEncapResp);
+ assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
+
+ FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
+ ArgumentMatcher<FileDescriptor> fdMatcher =
+ (argFd) -> {
+ return fileDescriptorsEqual(sockFd, argFd);
+ };
+ verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid()));
+
+ testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
+ udpEncapResp.fileDescriptor.close();
+ }
+
+ @Test
+ public void testOpenUdpEncapsulationSocketCallsSetEncapSocketOwner() throws Exception {
+ IpSecUdpEncapResponse udpEncapResp =
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+
+ FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
+ ArgumentMatcher<FileDescriptor> fdMatcher = (arg) -> {
+ try {
+ StructStat sockStat = Os.fstat(sockFd);
+ StructStat argStat = Os.fstat(arg);
+
+ return sockStat.st_ino == argStat.st_ino
+ && sockStat.st_dev == argStat.st_dev;
+ } catch (ErrnoException e) {
+ return false;
+ }
+ };
+
+ verify(mMockNetd).ipSecSetEncapSocketOwner(argThat(fdMatcher), eq(Os.getuid()));
+ mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
+ }
}
diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk
index 0e36981..a58ce78 100644
--- a/tests/testables/Android.mk
+++ b/tests/testables/Android.mk
@@ -25,10 +25,9 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- mockito-target-minus-junit4 \
legacy-android-test
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner mockito-target-minus-junit4
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk
index 43d1e37..700b7cb 100644
--- a/tests/utils/testutils/Android.mk
+++ b/tests/utils/testutils/Android.mk
@@ -25,9 +25,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- legacy-android-test \
- mockito-target-minus-junit4
+ legacy-android-test
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+ mockito-target-minus-junit4
include $(BUILD_STATIC_JAVA_LIBRARY)