Merge "Reduce blocking time when waiting for CharacteristicWrite queue to clear up."
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
index fbc611a..9d92e0f 100644
--- a/MULTIUSER_OWNERS
+++ b/MULTIUSER_OWNERS
@@ -1,4 +1,5 @@
# OWNERS of Multiuser related files
bookatz@google.com
+olilan@google.com
omakoto@google.com
yamasani@google.com
diff --git a/StubLibraries.bp b/StubLibraries.bp
index d090296..31fecd1 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -59,19 +59,13 @@
},
dists: [
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/public/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/public/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -115,19 +109,13 @@
},
dists: [
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -151,37 +139,25 @@
},
dists: [
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/test/api",
dest: "android.txt",
tag: ".api.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/test/api",
dest: "removed.txt",
tag: ".removed-api.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/test/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/test/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -210,19 +186,13 @@
},
dists: [
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/module-lib/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/module-lib/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
@@ -282,10 +252,7 @@
java_version: "1.8",
compile_dex: true,
dist: {
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
tag: ".jar",
dest: "android-non-updatable.jar",
},
@@ -341,10 +308,7 @@
java_defaults {
name: "android_stubs_dists_default",
dist: {
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
tag: ".jar",
dest: "android.jar",
},
@@ -376,10 +340,7 @@
dists: [
{
// Legacy dist path
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
tag: ".jar",
dest: "android_system.jar",
},
@@ -412,6 +373,7 @@
static_libs: [
"android-non-updatable.stubs.module_lib",
"art.module.public.api.stubs.module_lib",
+ "i18n.module.public.api.stubs",
],
dist: {
dir: "apistubs/android/module-lib",
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index c251529a..e5b0742 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -125,7 +125,7 @@
* will not be invoked.
*
* @param params Parameters specifying info about this job, including the optional
- * extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle).
+ * extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle)}.
* This object serves to identify this specific running job instance when calling
* {@link #jobFinished(JobParameters, boolean)}.
* @return {@code true} if your service will continue running, using a separate thread
diff --git a/api/Android.bp b/api/Android.bp
index ed2247b..c6ea175 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -120,10 +120,7 @@
dest: "current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/public/api",
dest: "android.txt",
},
@@ -205,10 +202,7 @@
dest: "removed.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/public/api",
dest: "removed.txt",
},
@@ -244,10 +238,7 @@
dest: "system-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system/api",
dest: "android.txt",
},
@@ -302,10 +293,7 @@
dest: "system-removed.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system/api",
dest: "removed.txt",
},
@@ -342,10 +330,7 @@
dest: "module-lib-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/module-lib/api",
dest: "android.txt",
},
@@ -402,10 +387,7 @@
dest: "module-lib-removed.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/module-lib/api",
dest: "removed.txt",
},
@@ -446,10 +428,7 @@
dest: "system-server-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system-server/api",
dest: "android.txt",
},
@@ -473,10 +452,7 @@
dest: "system-server-removed.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system-server/api",
dest: "removed.txt",
},
@@ -514,9 +490,6 @@
tools: ["api_versions_trimmer"],
cmd: "$(location api_versions_trimmer) $(out) $(in)",
dist: {
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
},
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 896060b..b42d6aa 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -21542,6 +21542,7 @@
public class MediaActionSound {
ctor public MediaActionSound();
method public void load(int);
+ method public static boolean mustPlayShutterSound();
method public void play(int);
method public void release();
field public static final int FOCUS_COMPLETE = 1; // 0x1
@@ -42579,6 +42580,7 @@
method @Deprecated public int getMnc();
method @Nullable public String getMncString();
method public String getNumber();
+ method public int getPortIndex();
method public int getSimSlotIndex();
method public int getSubscriptionId();
method public int getSubscriptionType();
@@ -43125,14 +43127,28 @@
method public int describeContents();
method public int getCardId();
method @Nullable public String getEid();
- method @Nullable public String getIccId();
- method public int getSlotIndex();
+ method @Deprecated @Nullable public String getIccId();
+ method public int getPhysicalSlotIndex();
+ method @NonNull public java.util.Collection<android.telephony.UiccPortInfo> getPorts();
+ method @Deprecated public int getSlotIndex();
method public boolean isEuicc();
+ method public boolean isMultipleEnabledProfilesSupported();
method public boolean isRemovable();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccCardInfo> CREATOR;
}
+ public final class UiccPortInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getIccId();
+ method @IntRange(from=0) public int getLogicalSlotIndex();
+ method @IntRange(from=0) public int getPortIndex();
+ method public boolean isActive();
+ method public void writeToParcel(@Nullable android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccPortInfo> CREATOR;
+ field public static final String ICCID_REDACTED = "FFFFFFFFFFFFFFFFFFFF";
+ }
+
public abstract class VisualVoicemailService extends android.app.Service {
ctor public VisualVoicemailService();
method public android.os.IBinder onBind(android.content.Intent);
@@ -43433,6 +43449,7 @@
method @Nullable public String getEid();
method @Nullable public android.telephony.euicc.EuiccInfo getEuiccInfo();
method public boolean isEnabled();
+ method public boolean isSimPortAvailable(int);
method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 81b4ee8..a646a68 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -113,6 +113,8 @@
public class AudioManager {
method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
+ method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio();
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
@@ -202,6 +204,10 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
}
+ public final class IpSecManager {
+ field public static final int DIRECTION_FWD = 2; // 0x2
+ }
+
public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
method public int getResourceId();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index bb454a6..9bca7fc 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5252,6 +5252,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
+ method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleStreamVolume(int);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -5841,9 +5842,11 @@
method @Nullable @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, @NonNull android.media.tv.TvInputInfo, @Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.TvInputManager.HardwareCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
+ method @NonNull public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames(@NonNull String);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TUNED_INFO) public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
+ method @Nullable public android.os.IBinder getExtensionInterface(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean isSingleSessionActive();
@@ -5874,6 +5877,9 @@
public abstract class TvInputService extends android.app.Service {
method @Nullable public android.os.IBinder createExtension();
+ method @NonNull public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames();
+ method @Nullable public android.os.IBinder getExtensionInterface(@NonNull String);
+ method @Nullable public String getExtensionInterfacePermission(@NonNull String);
method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
@@ -9448,7 +9454,9 @@
field public static final int MATCH_ALL_APN_SET_ID = -1; // 0xffffffff
field public static final String MAX_CONNECTIONS = "max_conns";
field public static final String MODEM_PERSIST = "modem_cognitive";
- field public static final String MTU = "mtu";
+ field @Deprecated public static final String MTU = "mtu";
+ field public static final String MTU_V4 = "mtu_v4";
+ field public static final String MTU_V6 = "mtu_v6";
field public static final int NO_APN_SET_ID = 0; // 0x0
field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
field public static final int UNEDITED = 0; // 0x0
@@ -12133,6 +12141,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimSlotMapping(@NonNull java.util.Collection<android.telephony.UiccSlotMapping>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>);
method @Deprecated public void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
@@ -12144,7 +12153,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
method public void updateServiceLocation();
@@ -12318,10 +12327,11 @@
method public int describeContents();
method public String getCardId();
method public int getCardStateInfo();
- method public boolean getIsActive();
+ method @Deprecated public boolean getIsActive();
method public boolean getIsEuicc();
method public boolean getIsExtendedApduSupported();
- method public int getLogicalSlotIdx();
+ method @Deprecated public int getLogicalSlotIdx();
+ method @NonNull public java.util.Collection<android.telephony.UiccPortInfo> getPorts();
method public boolean isRemovable();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1
@@ -12331,6 +12341,15 @@
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccSlotInfo> CREATOR;
}
+ public final class UiccSlotMapping implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0) public int getLogicalSlotIndex();
+ method @IntRange(from=0) public int getPhysicalSlotIndex();
+ method @IntRange(from=0) public int getPortIndex();
+ method public void writeToParcel(@Nullable android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccSlotMapping> CREATOR;
+ }
+
public abstract class VisualVoicemailService extends android.app.Service {
method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, String, short, String, android.app.PendingIntent);
method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
@@ -12513,6 +12532,7 @@
method public final int getSlotIndex();
method public final void notifyApnUnthrottled(@NonNull String);
method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
+ method public final void notifyDataProfileUnthrottled(@NonNull android.telephony.data.DataProfile);
method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback);
method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
@@ -12523,6 +12543,7 @@
public class DataServiceCallback {
method public void onApnUnthrottled(@NonNull String);
method public void onDataCallListChanged(@NonNull java.util.List<android.telephony.data.DataCallResponse>);
+ method public void onDataProfileUnthrottled(@NonNull android.telephony.data.DataProfile);
method public void onDeactivateDataCallComplete(int);
method public void onRequestDataCallListComplete(int, @NonNull java.util.List<android.telephony.data.DataCallResponse>);
method public void onSetDataProfileComplete(int);
@@ -12622,7 +12643,8 @@
method public void authenticateServer(String, String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
method public void cancelSession(String, byte[], @android.telephony.euicc.EuiccCardManager.CancelReason int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
method public void deleteProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method @Deprecated public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void disableProfile(@Nullable String, @Nullable String, int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
method public void listNotifications(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
method public void loadBoundProfilePackage(String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
method public void prepareDownload(String, @Nullable byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
@@ -12640,7 +12662,8 @@
method public void retrieveNotificationList(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
method public void setDefaultSmdpAddress(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
method public void setNickname(String, String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void switchToProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
+ method @Deprecated public void switchToProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
+ method public void switchToProfile(@Nullable String, @Nullable String, int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
field public static final int CANCEL_REASON_END_USER_REJECTED = 0; // 0x0
field public static final int CANCEL_REASON_POSTPONED = 1; // 0x1
field public static final int CANCEL_REASON_PPR_NOT_ALLOWED = 3; // 0x3
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 9b37457..c6c64b0 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3086,6 +3086,9 @@
BluetoothCsipSetCoordinator csipSetCoordinator =
new BluetoothCsipSetCoordinator(context, listener, this);
return true;
+ } else if (profile == BluetoothProfile.LE_CALL_CONTROL) {
+ BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener);
+ return true;
} else {
return false;
}
@@ -3188,6 +3191,10 @@
(BluetoothCsipSetCoordinator) proxy;
csipSetCoordinator.close();
break;
+ case BluetoothProfile.LE_CALL_CONTROL:
+ BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy;
+ tbs.close();
+ break;
}
}
diff --git a/core/java/android/bluetooth/BluetoothLeCall.java b/core/java/android/bluetooth/BluetoothLeCall.java
new file mode 100644
index 0000000..fb7789d
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeCall.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2021 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * 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.bluetooth;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * Representation of Call
+ *
+ * @hide
+ */
+public final class BluetoothLeCall implements Parcelable {
+
+ /** @hide */
+ @IntDef(prefix = "STATE_", value = {
+ STATE_INCOMING,
+ STATE_DIALING,
+ STATE_ALERTING,
+ STATE_ACTIVE,
+ STATE_LOCALLY_HELD,
+ STATE_REMOTELY_HELD,
+ STATE_LOCALLY_AND_REMOTELY_HELD
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ }
+
+ /**
+ * A remote party is calling (incoming call).
+ *
+ * @hide
+ */
+ public static final int STATE_INCOMING = 0x00;
+
+ /**
+ * The process to call the remote party has started but the remote party is not
+ * being alerted (outgoing call).
+ *
+ * @hide
+ */
+ public static final int STATE_DIALING = 0x01;
+
+ /**
+ * A remote party is being alerted (outgoing call).
+ *
+ * @hide
+ */
+ public static final int STATE_ALERTING = 0x02;
+
+ /**
+ * The call is in an active conversation.
+ *
+ * @hide
+ */
+ public static final int STATE_ACTIVE = 0x03;
+
+ /**
+ * The call is connected but held locally. “Locally Held” implies that either
+ * the server or the client can affect the state.
+ *
+ * @hide
+ */
+ public static final int STATE_LOCALLY_HELD = 0x04;
+
+ /**
+ * The call is connected but held remotely. “Remotely Held” means that the state
+ * is controlled by the remote party of a call.
+ *
+ * @hide
+ */
+ public static final int STATE_REMOTELY_HELD = 0x05;
+
+ /**
+ * The call is connected but held both locally and remotely.
+ *
+ * @hide
+ */
+ public static final int STATE_LOCALLY_AND_REMOTELY_HELD = 0x06;
+
+ /**
+ * Whether the call direction is outgoing.
+ *
+ * @hide
+ */
+ public static final int FLAG_OUTGOING_CALL = 0x00000001;
+
+ /**
+ * Whether the call URI and Friendly Name are withheld by server.
+ *
+ * @hide
+ */
+ public static final int FLAG_WITHHELD_BY_SERVER = 0x00000002;
+
+ /**
+ * Whether the call URI and Friendly Name are withheld by network.
+ *
+ * @hide
+ */
+ public static final int FLAG_WITHHELD_BY_NETWORK = 0x00000004;
+
+ /** Unique UUID that identifies this call */
+ private UUID mUuid;
+
+ /** Remote Caller URI */
+ private String mUri;
+
+ /** Caller friendly name */
+ private String mFriendlyName;
+
+ /** Call state */
+ private @State int mState;
+
+ /** Call flags */
+ private int mCallFlags;
+
+ /** @hide */
+ public BluetoothLeCall(@NonNull BluetoothLeCall that) {
+ mUuid = new UUID(that.getUuid().getMostSignificantBits(),
+ that.getUuid().getLeastSignificantBits());
+ mUri = that.mUri;
+ mFriendlyName = that.mFriendlyName;
+ mState = that.mState;
+ mCallFlags = that.mCallFlags;
+ }
+
+ /** @hide */
+ public BluetoothLeCall(@NonNull UUID uuid, @NonNull String uri, @NonNull String friendlyName,
+ @State int state, int callFlags) {
+ mUuid = uuid;
+ mUri = uri;
+ mFriendlyName = friendlyName;
+ mState = state;
+ mCallFlags = callFlags;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ BluetoothLeCall that = (BluetoothLeCall) o;
+ return mUuid.equals(that.mUuid) && mUri.equals(that.mUri)
+ && mFriendlyName.equals(that.mFriendlyName) && mState == that.mState
+ && mCallFlags == that.mCallFlags;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUuid, mUri, mFriendlyName, mState, mCallFlags);
+ }
+
+ /**
+ * Returns a string representation of this BluetoothLeCall.
+ *
+ * <p>
+ * Currently this is the UUID.
+ *
+ * @return string representation of this BluetoothLeCall
+ */
+ @Override
+ public String toString() {
+ return mUuid.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeParcelable(new ParcelUuid(mUuid), 0);
+ out.writeString(mUri);
+ out.writeString(mFriendlyName);
+ out.writeInt(mState);
+ out.writeInt(mCallFlags);
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<BluetoothLeCall> CREATOR =
+ new Parcelable.Creator<BluetoothLeCall>() {
+ public BluetoothLeCall createFromParcel(Parcel in) {
+ return new BluetoothLeCall(in);
+ }
+
+ public BluetoothLeCall[] newArray(int size) {
+ return new BluetoothLeCall[size];
+ }
+ };
+
+ private BluetoothLeCall(Parcel in) {
+ mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
+ mUri = in.readString();
+ mFriendlyName = in.readString();
+ mState = in.readInt();
+ mCallFlags = in.readInt();
+ }
+
+ /**
+ * Returns an UUID of this BluetoothLeCall.
+ *
+ * <p>
+ * An UUID is unique identifier of a BluetoothLeCall.
+ *
+ * @return UUID of this BluetoothLeCall
+ * @hide
+ */
+ public @NonNull UUID getUuid() {
+ return mUuid;
+ }
+
+ /**
+ * Returns a URI of the remote party of this BluetoothLeCall.
+ *
+ * @return string representation of this BluetoothLeCall
+ * @hide
+ */
+ public @NonNull String getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns a friendly name of the call.
+ *
+ * @return friendly name representation of this BluetoothLeCall
+ * @hide
+ */
+ public @NonNull String getFriendlyName() {
+ return mFriendlyName;
+ }
+
+ /**
+ * Returns the call state.
+ *
+ * @return the state of this BluetoothLeCall
+ * @hide
+ */
+ public @State int getState() {
+ return mState;
+ }
+
+ /**
+ * Returns the call flags.
+ *
+ * @return call flags
+ * @hide
+ */
+ public int getCallFlags() {
+ return mCallFlags;
+ }
+
+ /**
+ * Whether the call direction is incoming.
+ *
+ * @return true if incoming call, false otherwise
+ * @hide
+ */
+ public boolean isIncomingCall() {
+ return (mCallFlags & FLAG_OUTGOING_CALL) == 0;
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothLeCallControl.java b/core/java/android/bluetooth/BluetoothLeCallControl.java
new file mode 100644
index 0000000..5283e08
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeCallControl.java
@@ -0,0 +1,911 @@
+/*
+ * Copyright 2019 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * 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.bluetooth;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.util.Log;
+import android.annotation.SuppressLint;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides the APIs to control the Call Control profile.
+ *
+ * <p>
+ * This class provides Bluetooth Telephone Bearer Service functionality,
+ * allowing applications to expose a GATT Service based interface to control the
+ * state of the calls by remote devices such as LE audio devices.
+ *
+ * <p>
+ * BluetoothLeCallControl is a proxy object for controlling the Bluetooth Telephone Bearer
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
+ * BluetoothLeCallControl proxy object.
+ *
+ * @hide
+ */
+public final class BluetoothLeCallControl implements BluetoothProfile {
+ private static final String TAG = "BluetoothLeCallControl";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /** @hide */
+ @IntDef(prefix = "RESULT_", value = {
+ RESULT_SUCCESS,
+ RESULT_ERROR_UNKNOWN_CALL_ID,
+ RESULT_ERROR_INVALID_URI,
+ RESULT_ERROR_APPLICATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Result {
+ }
+
+ /**
+ * Opcode write was successful.
+ *
+ * @hide
+ */
+ public static final int RESULT_SUCCESS = 0;
+
+ /**
+ * Unknown call Id has been used in the operation.
+ *
+ * @hide
+ */
+ public static final int RESULT_ERROR_UNKNOWN_CALL_ID = 1;
+
+ /**
+ * The URI provided in {@link Callback#onPlaceCallRequest} is invalid.
+ *
+ * @hide
+ */
+ public static final int RESULT_ERROR_INVALID_URI = 2;
+
+ /**
+ * Application internal error.
+ *
+ * @hide
+ */
+ public static final int RESULT_ERROR_APPLICATION = 3;
+
+ /** @hide */
+ @IntDef(prefix = "TERMINATION_REASON_", value = {
+ TERMINATION_REASON_INVALID_URI,
+ TERMINATION_REASON_FAIL,
+ TERMINATION_REASON_REMOTE_HANGUP,
+ TERMINATION_REASON_SERVER_HANGUP,
+ TERMINATION_REASON_LINE_BUSY,
+ TERMINATION_REASON_NETWORK_CONGESTION,
+ TERMINATION_REASON_CLIENT_HANGUP,
+ TERMINATION_REASON_NO_SERVICE,
+ TERMINATION_REASON_NO_ANSWER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TerminationReason {
+ }
+
+ /**
+ * Remote Caller ID value used to place a call was formed improperly.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_INVALID_URI = 0x00;
+
+ /**
+ * Call fail.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_FAIL = 0x01;
+
+ /**
+ * Remote party ended call.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_REMOTE_HANGUP = 0x02;
+
+ /**
+ * Call ended from the server.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_SERVER_HANGUP = 0x03;
+
+ /**
+ * Line busy.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_LINE_BUSY = 0x04;
+
+ /**
+ * Network congestion.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_NETWORK_CONGESTION = 0x05;
+
+ /**
+ * Client terminated.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_CLIENT_HANGUP = 0x06;
+
+ /**
+ * No service.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_NO_SERVICE = 0x07;
+
+ /**
+ * No answer.
+ *
+ * @hide
+ */
+ public static final int TERMINATION_REASON_NO_ANSWER = 0x08;
+
+ /*
+ * Flag indicating support for hold/unhold call feature.
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_HOLD_CALL = 0x00000001;
+
+ /**
+ * Flag indicating support for joining calls feature.
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_JOIN_CALLS = 0x00000002;
+
+ private static final int MESSAGE_TBS_SERVICE_CONNECTED = 102;
+ private static final int MESSAGE_TBS_SERVICE_DISCONNECTED = 103;
+
+ private static final int REG_TIMEOUT = 10000;
+
+ /**
+ * The template class is used to call callback functions on events from the TBS
+ * server. Callback functions are wrapped in this class and registered to the
+ * Android system during app registration.
+ *
+ * @hide
+ */
+ public abstract static class Callback {
+
+ private static final String TAG = "BluetoothLeCallControl.Callback";
+
+ /**
+ * Called when a remote client requested to accept the call.
+ *
+ * <p>
+ * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+ * request.
+ *
+ * @param requestId The Id of the request
+ * @param callId The call Id requested to be accepted
+ * @hide
+ */
+ public abstract void onAcceptCall(int requestId, @NonNull UUID callId);
+
+ /**
+ * A remote client has requested to terminate the call.
+ *
+ * <p>
+ * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+ * request.
+ *
+ * @param requestId The Id of the request
+ * @param callId The call Id requested to terminate
+ * @hide
+ */
+ public abstract void onTerminateCall(int requestId, @NonNull UUID callId);
+
+ /**
+ * A remote client has requested to hold the call.
+ *
+ * <p>
+ * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+ * request.
+ *
+ * @param requestId The Id of the request
+ * @param callId The call Id requested to be put on hold
+ * @hide
+ */
+ public void onHoldCall(int requestId, @NonNull UUID callId) {
+ Log.e(TAG, "onHoldCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
+ }
+
+ /**
+ * A remote client has requested to unhold the call.
+ *
+ * <p>
+ * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+ * request.
+ *
+ * @param requestId The Id of the request
+ * @param callId The call Id requested to unhold
+ * @hide
+ */
+ public void onUnholdCall(int requestId, @NonNull UUID callId) {
+ Log.e(TAG, "onUnholdCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
+ }
+
+ /**
+ * A remote client has requested to place a call.
+ *
+ * <p>
+ * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+ * request.
+ *
+ * @param requestId The Id of the request
+ * @param callId The Id to be assigned for the new call
+ * @param uri The caller URI requested
+ * @hide
+ */
+ public abstract void onPlaceCall(int requestId, @NonNull UUID callId, @NonNull String uri);
+
+ /**
+ * A remote client has requested to join the calls.
+ *
+ * <p>
+ * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
+ * request.
+ *
+ * @param requestId The Id of the request
+ * @param callIds The call Id list requested to join
+ * @hide
+ */
+ public void onJoinCalls(int requestId, @NonNull List<UUID> callIds) {
+ Log.e(TAG, "onJoinCalls: unimplemented, however CAPABILITY_JOIN_CALLS is set!");
+ }
+ }
+
+ private class CallbackWrapper extends IBluetoothLeCallControlCallback.Stub {
+
+ private final Executor mExecutor;
+ private final Callback mCallback;
+
+ CallbackWrapper(Executor executor, Callback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onBearerRegistered(int ccid) {
+ synchronized (mServerIfLock) {
+ if (mCallback != null) {
+ mCcid = ccid;
+ mServerIfLock.notifyAll();
+ } else {
+ // registration timeout
+ Log.e(TAG, "onBearerRegistered: mCallback is null");
+ }
+ }
+ }
+
+ @Override
+ public void onAcceptCall(int requestId, ParcelUuid uuid) {
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onAcceptCall(requestId, uuid.getUuid()));
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+
+ @Override
+ public void onTerminateCall(int requestId, ParcelUuid uuid) {
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onTerminateCall(requestId, uuid.getUuid()));
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+
+ @Override
+ public void onHoldCall(int requestId, ParcelUuid uuid) {
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onHoldCall(requestId, uuid.getUuid()));
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+
+ @Override
+ public void onUnholdCall(int requestId, ParcelUuid uuid) {
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onUnholdCall(requestId, uuid.getUuid()));
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+
+ @Override
+ public void onPlaceCall(int requestId, ParcelUuid uuid, String uri) {
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onPlaceCall(requestId, uuid.getUuid(), uri));
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+
+ @Override
+ public void onJoinCalls(int requestId, List<ParcelUuid> parcelUuids) {
+ List<UUID> uuids = new ArrayList<>();
+ for (ParcelUuid parcelUuid : parcelUuids) {
+ uuids.add(parcelUuid.getUuid());
+ }
+
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onJoinCalls(requestId, uuids));
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+ };
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private volatile IBluetoothLeCallControl mService;
+ private BluetoothAdapter mAdapter;
+ private int mCcid = 0;
+ private String mToken;
+ private Callback mCallback = null;
+ private Object mServerIfLock = new Object();
+
+ private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG)
+ Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ doUnbind();
+ } else {
+ doBind();
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothLeCallControl proxy object for interacting with the local Bluetooth
+ * telephone bearer service.
+ */
+ /* package */ BluetoothLeCallControl(Context context, ServiceListener listener) {
+ mContext = context;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mServiceListener = listener;
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ doBind();
+ }
+
+ private boolean doBind() {
+ synchronized (mConnection) {
+ if (mService == null) {
+ if (VDBG)
+ Log.d(TAG, "Binding service...");
+ try {
+ return mAdapter.getBluetoothManager().
+ bindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
+ mConnection);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to bind TelephoneBearerService", e);
+ }
+ }
+ }
+ return false;
+ }
+
+ private void doUnbind() {
+ synchronized (mConnection) {
+ if (mService != null) {
+ if (VDBG)
+ Log.d(TAG, "Unbinding service...");
+ try {
+ mAdapter.getBluetoothManager().
+ unbindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
+ mConnection);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to unbind TelephoneBearerService", e);
+ } finally {
+ mService = null;
+ }
+ }
+ }
+ }
+
+ /* package */ void close() {
+ if (VDBG)
+ log("close()");
+ unregisterBearer();
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException re) {
+ Log.e(TAG, "", re);
+ }
+ }
+ mServiceListener = null;
+ doUnbind();
+ }
+
+ private IBluetoothLeCallControl getService() {
+ return mService;
+ }
+
+ /**
+ * Not supported
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public int getConnectionState(@Nullable BluetoothDevice device) {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ /**
+ * Not supported
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getConnectedDevices() {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ /**
+ * Not supported
+ *
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ @NonNull int[] states) {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ /**
+ * Register Telephone Bearer exposing the interface that allows remote devices
+ * to track and control the call states.
+ *
+ * <p>
+ * This is an asynchronous call. The callback is used to notify success or
+ * failure if the function returns true.
+ *
+ * <p>
+ * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * <!-- The UCI is a String identifier of the telephone bearer as defined at
+ * https://www.bluetooth.com/specifications/assigned-numbers/uniform-caller-identifiers
+ * (login required). -->
+ *
+ * <!-- The examples of common URI schemes can be found in
+ * https://iana.org/assignments/uri-schemes/uri-schemes.xhtml -->
+ *
+ * <!-- The Technology is an integer value. The possible values are defined at
+ * https://www.bluetooth.com/specifications/assigned-numbers (login required).
+ * -->
+ *
+ * @param uci Bearer Unique Client Identifier
+ * @param uriSchemes URI Schemes supported list
+ * @param capabilities bearer capabilities
+ * @param provider Network provider name
+ * @param technology Network technology
+ * @param executor {@link Executor} object on which callback will be
+ * executed. The Executor object is required.
+ * @param callback {@link Callback} object to which callback messages will
+ * be sent. The Callback object is required.
+ * @return true on success, false otherwise
+ * @hide
+ */
+ @SuppressLint("ExecutorRegistration")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean registerBearer(@Nullable String uci,
+ @NonNull List<String> uriSchemes, int capabilities,
+ @NonNull String provider, int technology,
+ @NonNull Executor executor, @NonNull Callback callback) {
+ if (DBG) {
+ Log.d(TAG, "registerBearer");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("null parameter: " + callback);
+ }
+ if (mCcid != 0) {
+ return false;
+ }
+
+ mToken = uci;
+
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ synchronized (mServerIfLock) {
+ if (mCallback != null) {
+ Log.e(TAG, "Bearer can be opened only once");
+ return false;
+ }
+
+ mCallback = callback;
+ try {
+ CallbackWrapper callbackWrapper = new CallbackWrapper(executor, callback);
+ service.registerBearer(mToken, callbackWrapper, uci, uriSchemes, capabilities,
+ provider, technology);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ mCallback = null;
+ return false;
+ }
+
+ try {
+ mServerIfLock.wait(REG_TIMEOUT);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "" + e);
+ mCallback = null;
+ }
+
+ if (mCcid == 0) {
+ mCallback = null;
+ return false;
+ }
+
+ return true;
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+
+ return false;
+ }
+
+ /**
+ * Unregister Telephone Bearer Service and destroy all the associated data.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void unregisterBearer() {
+ if (DBG) {
+ Log.d(TAG, "unregisterBearer");
+ }
+ if (mCcid == 0) {
+ return;
+ }
+
+ int ccid = mCcid;
+ mCcid = 0;
+ mCallback = null;
+
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ try {
+ service.unregisterBearer(mToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ }
+
+ /**
+ * Get the Content Control ID (CCID) value.
+ *
+ * @return ccid Content Control ID value
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public int getContentControlId() {
+ return mCcid;
+ }
+
+ /**
+ * Notify about the newly added call.
+ *
+ * <p>
+ * This shall be called as early as possible after the call has been added.
+ *
+ * <p>
+ * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param call Newly added call
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void onCallAdded(@NonNull BluetoothLeCall call) {
+ if (DBG) {
+ Log.d(TAG, "onCallAdded: call=" + call);
+ }
+ if (mCcid == 0) {
+ return;
+ }
+
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ try {
+ service.callAdded(mCcid, call);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ }
+
+ /**
+ * Notify about the removed call.
+ *
+ * <p>
+ * This shall be called as early as possible after the call has been removed.
+ *
+ * <p>
+ * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param callId The Id of a call that has been removed
+ * @param reason Call termination reason
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void onCallRemoved(@NonNull UUID callId, @TerminationReason int reason) {
+ if (DBG) {
+ Log.d(TAG, "callRemoved: callId=" + callId);
+ }
+ if (mCcid == 0) {
+ return;
+ }
+
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ try {
+ service.callRemoved(mCcid, new ParcelUuid(callId), reason);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ }
+
+ /**
+ * Notify the call state change
+ *
+ * <p>
+ * This shall be called as early as possible after the state of the call has
+ * changed.
+ *
+ * <p>
+ * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param callId The call Id that state has been changed
+ * @param state Call state
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void onCallStateChanged(@NonNull UUID callId, @BluetoothLeCall.State int state) {
+ if (DBG) {
+ Log.d(TAG, "callStateChanged: callId=" + callId + " state=" + state);
+ }
+ if (mCcid == 0) {
+ return;
+ }
+
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ try {
+ service.callStateChanged(mCcid, new ParcelUuid(callId), state);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ }
+
+ /**
+ * Provide the current calls list
+ *
+ * <p>
+ * This function must be invoked after registration if application has any
+ * calls.
+ *
+ * @param calls current calls list
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void currentCallsList(@NonNull List<BluetoothLeCall> calls) {
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ try {
+ service.currentCallsList(mCcid, calls);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+
+ /**
+ * Provide the network current status
+ *
+ * <p>
+ * This function must be invoked on change of network state.
+ *
+ * <p>
+ * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * <!-- The Technology is an integer value. The possible values are defined at
+ * https://www.bluetooth.com/specifications/assigned-numbers (login required).
+ * -->
+ *
+ * @param provider Network provider name
+ * @param technology Network technology
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void networkStateChanged(@NonNull String provider, int technology) {
+ if (DBG) {
+ Log.d(TAG, "networkStateChanged: provider=" + provider + ", technology=" + technology);
+ }
+ if (mCcid == 0) {
+ return;
+ }
+
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ try {
+ service.networkStateChanged(mCcid, provider, technology);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ if (service == null) {
+ Log.w(TAG, "Proxy not attached to service");
+ }
+ }
+
+ /**
+ * Send a response to a call control request to a remote device.
+ *
+ * <p>
+ * This function must be invoked in when a request is received by one of these
+ * callback methods:
+ *
+ * <ul>
+ * <li>{@link Callback#onAcceptCall}
+ * <li>{@link Callback#onTerminateCall}
+ * <li>{@link Callback#onHoldCall}
+ * <li>{@link Callback#onUnholdCall}
+ * <li>{@link Callback#onPlaceCall}
+ * <li>{@link Callback#onJoinCalls}
+ * </ul>
+ *
+ * @param requestId The ID of the request that was received with the callback
+ * @param result The result of the request to be sent to the remote devices
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void requestResult(int requestId, @Result int result) {
+ if (DBG) {
+ Log.d(TAG, "requestResult: requestId=" + requestId + " result=" + result);
+ }
+ if (mCcid == 0) {
+ return;
+ }
+
+ final IBluetoothLeCallControl service = getService();
+ if (service != null) {
+ try {
+ service.requestResult(mCcid, requestId, result);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ private static boolean isValidDevice(@Nullable BluetoothDevice device) {
+ return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+
+ private final IBluetoothProfileServiceConnection mConnection =
+ new IBluetoothProfileServiceConnection.Stub() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) {
+ Log.d(TAG, "Proxy object connected");
+ }
+ mService = IBluetoothLeCallControl.Stub.asInterface(Binder.allowBlocking(service));
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_CONNECTED));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) {
+ Log.d(TAG, "Proxy object disconnected");
+ }
+ doUnbind();
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_DISCONNECTED));
+ }
+ };
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_TBS_SERVICE_CONNECTED: {
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.LE_CALL_CONTROL,
+ BluetoothLeCallControl.this);
+ }
+ break;
+ }
+ case MESSAGE_TBS_SERVICE_DISCONNECTED: {
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.LE_CALL_CONTROL);
+ }
+ break;
+ }
+ }
+ }
+ };
+}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index e137929..de2db9c 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -25,15 +25,10 @@
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -96,10 +91,6 @@
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
- private volatile IBluetoothPbap mService;
- private final Context mContext;
- private ServiceListener mServiceListener;
- private final BluetoothAdapter mAdapter;
private final AttributionSource mAttributionSource;
/** @hide */
@@ -113,87 +104,25 @@
*/
public static final int RESULT_CANCELED = 2;
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
- new IBluetoothStateChangeCallback.Stub() {
- public void onBluetoothStateChange(boolean up) {
- log("onBluetoothStateChange: up=" + up);
- if (!up) {
- doUnbind();
- } else {
- doBind();
- }
+ private BluetoothAdapter mAdapter;
+ private final BluetoothProfileConnector<IBluetoothPbap> mProfileConnector =
+ new BluetoothProfileConnector(this, BluetoothProfile.PBAP, "BluetoothPbap",
+ IBluetoothPbap.class.getName()) {
+ @Override
+ public IBluetoothPbap getServiceInterface(IBinder service) {
+ return IBluetoothPbap.Stub.asInterface(service);
}
- };
+ };
/**
* Create a BluetoothPbap proxy object.
*
* @hide
*/
- public BluetoothPbap(Context context, ServiceListener l, BluetoothAdapter adapter) {
- mContext = context;
- mServiceListener = l;
+ public BluetoothPbap(Context context, ServiceListener listener, BluetoothAdapter adapter) {
mAdapter = adapter;
mAttributionSource = adapter.getAttributionSource();
-
- // Preserve legacy compatibility where apps were depending on
- // registerStateChangeCallback() performing a permissions check which
- // has been relaxed in modern platform versions
- if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R
- && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Need BLUETOOTH permission");
- }
-
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "", re);
- }
- }
- doBind();
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission")
- boolean doBind() {
- synchronized (mConnection) {
- try {
- if (mService == null) {
- log("Binding service...");
- Intent intent = new Intent(IBluetoothPbap.class.getName());
- ComponentName comp = intent.resolveSystemService(
- mContext.getPackageManager(), 0);
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- UserHandle.CURRENT)) {
- Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent);
- return false;
- }
- }
- } catch (SecurityException se) {
- Log.e(TAG, "", se);
- return false;
- }
- }
- return true;
- }
-
- private void doUnbind() {
- synchronized (mConnection) {
- if (mService != null) {
- log("Unbinding service...");
- try {
- mContext.unbindService(mConnection);
- } catch (IllegalArgumentException ie) {
- Log.e(TAG, "", ie);
- } finally {
- mService = null;
- }
- }
- }
+ mProfileConnector.connect(context, listener);
}
/** @hide */
@@ -214,16 +143,11 @@
* @hide
*/
public synchronized void close() {
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "", re);
- }
- }
- doUnbind();
- mServiceListener = null;
+ mProfileConnector.disconnect();
+ }
+
+ private IBluetoothPbap getService() {
+ return (IBluetoothPbap) mProfileConnector.getService();
}
/**
@@ -236,7 +160,7 @@
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
log("getConnectedDevices()");
- final IBluetoothPbap service = mService;
+ final IBluetoothPbap service = getService();
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -265,7 +189,7 @@
public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
log("getConnectionState: device=" + device);
try {
- final IBluetoothPbap service = mService;
+ final IBluetoothPbap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
return service.getConnectionState(device, mAttributionSource);
}
@@ -289,7 +213,7 @@
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states));
- final IBluetoothPbap service = mService;
+ final IBluetoothPbap service = getService();
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
@@ -330,7 +254,7 @@
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
try {
- final IBluetoothPbap service = mService;
+ final IBluetoothPbap service = getService();
if (service != null && isEnabled()
&& isValidDevice(device)) {
if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
@@ -359,7 +283,7 @@
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
log("disconnect()");
- final IBluetoothPbap service = mService;
+ final IBluetoothPbap service = getService();
if (service == null) {
Log.w(TAG, "Proxy not attached to service");
return false;
@@ -373,25 +297,6 @@
return false;
}
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- log("Proxy object connected");
- mService = IBluetoothPbap.Stub.asInterface(service);
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.PBAP, BluetoothPbap.this);
- }
- }
-
- public void onServiceDisconnected(ComponentName className) {
- log("Proxy object disconnected");
- doUnbind();
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP);
- }
- }
- };
-
private boolean isEnabled() {
if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
return false;
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index e047e5d..d0f74e9 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -240,12 +240,19 @@
int LE_AUDIO_BROADCAST = 26;
/**
+ * @hide
+ * Telephone Bearer Service from Call Control Profile
+ *
+ */
+ int LE_CALL_CONTROL = 27;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- int MAX_PROFILE_ID = 26;
+ int MAX_PROFILE_ID = 27;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java
index ecd5e40..79373f1a 100644
--- a/core/java/android/bluetooth/BluetoothProfileConnector.java
+++ b/core/java/android/bluetooth/BluetoothProfileConnector.java
@@ -16,12 +16,16 @@
package android.bluetooth;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
@@ -29,6 +33,7 @@
import android.util.CloseGuard;
import android.util.Log;
+import java.util.List;
/**
* Connector for Bluetooth profile proxies to bind manager service and
* profile services
@@ -57,6 +62,29 @@
}
};
+ private @Nullable ComponentName resolveSystemService(@NonNull Intent intent,
+ @NonNull PackageManager pm, @PackageManager.ComponentInfoFlags int flags) {
+ List<ResolveInfo> results = pm.queryIntentServices(intent, flags);
+ if (results == null) {
+ return null;
+ }
+ ComponentName comp = null;
+ for (int i = 0; i < results.size(); i++) {
+ ResolveInfo ri = results.get(i);
+ if ((ri.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ continue;
+ }
+ ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName,
+ ri.serviceInfo.name);
+ if (comp != null) {
+ throw new IllegalStateException("Multiple system services handle " + intent
+ + ": " + comp + ", " + foundComp);
+ }
+ comp = foundComp;
+ }
+ return comp;
+ }
+
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
logDebug("Proxy object connected");
@@ -99,8 +127,8 @@
mCloseGuard.open("doUnbind");
try {
Intent intent = new Intent(mServiceName);
- ComponentName comp = intent.resolveSystemService(
- mContext.getPackageManager(), 0);
+ ComponentName comp = resolveSystemService(intent, mContext.getPackageManager(),
+ 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
UserHandle.CURRENT)) {
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 858819e..2a8ff51 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -189,7 +189,7 @@
@NonNull
@SystemApi
public static final ParcelUuid CAP =
- ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+ ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB");
/** @hide */
@NonNull
@SystemApi
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1552dbd..9659df6 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5408,7 +5408,9 @@
*
* <p>Targets provided in this way will be presented inline with all other targets provided
* by services from other apps. They will be prioritized before other service targets, but
- * after those targets provided by sources that the user has manually pinned to the front.</p>
+ * after those targets provided by sources that the user has manually pinned to the front.
+ * You can provide up to two targets on this extra (the limit of two targets
+ * starts in Android 10).</p>
*
* @see #ACTION_CHOOSER
*/
@@ -5519,9 +5521,11 @@
/**
* A Parcelable[] of {@link Intent} or
* {@link android.content.pm.LabeledIntent} objects as set with
- * {@link #putExtra(String, Parcelable[])} of additional activities to place
- * a the front of the list of choices, when shown to the user with a
- * {@link #ACTION_CHOOSER}.
+ * {@link #putExtra(String, Parcelable[])} to place
+ * at the front of the list of choices, when shown to the user with an
+ * {@link #ACTION_CHOOSER}. You can choose up to two additional activities
+ * to show before the app suggestions (the limit of two additional activities starts in
+ * Android 10).
*/
public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 6c39365..07babb1 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -913,7 +913,7 @@
private static final class DisplayListenerDelegate extends Handler {
public final DisplayListener mListener;
- public long mEventsMask;
+ public volatile long mEventsMask;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -933,12 +933,12 @@
removeCallbacksAndMessages(null);
}
- public synchronized void setEventsMask(@EventsMask long newEventsMask) {
+ public void setEventsMask(@EventsMask long newEventsMask) {
mEventsMask = newEventsMask;
}
@Override
- public synchronized void handleMessage(Message msg) {
+ public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DISPLAY_ADDED:
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
diff --git a/core/java/android/net/IInternalNetworkManagementListener.aidl b/core/java/android/net/IInternalNetworkManagementListener.aidl
new file mode 100644
index 0000000..69cde3b
--- /dev/null
+++ b/core/java/android/net/IInternalNetworkManagementListener.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2021, 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.net;
+
+import android.net.InternalNetworkManagementException;
+import android.net.Network;
+
+/** @hide */
+oneway interface IInternalNetworkManagementListener {
+ void onComplete(in Network network, in InternalNetworkManagementException exception);
+}
\ No newline at end of file
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index b18e9be..fab692c 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -142,8 +142,9 @@
boolean isBypassable,
boolean isMetered,
int maxMtu,
- boolean restrictToTestNetworks) {
- super(type);
+ boolean restrictToTestNetworks,
+ boolean excludeLocalRoutes) {
+ super(type, excludeLocalRoutes);
checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
@@ -403,7 +404,8 @@
&& mIsBypassable == other.mIsBypassable
&& mIsMetered == other.mIsMetered
&& mMaxMtu == other.mMaxMtu
- && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks;
+ && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
+ && mExcludeLocalRoutes == other.mExcludeLocalRoutes;
}
/**
@@ -417,7 +419,7 @@
@NonNull
public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
- mIsRestrictedToTestNetworks);
+ mIsRestrictedToTestNetworks, mExcludeLocalRoutes);
profile.type = mType;
profile.server = mServerAddr;
profile.ipsecIdentifier = mUserIdentity;
@@ -518,6 +520,8 @@
throw new IllegalArgumentException("Invalid auth method set");
}
+ builder.setExcludeLocalRoutes(profile.excludeLocalRoutes);
+
return builder.build();
}
@@ -657,6 +661,7 @@
private boolean mIsMetered = true;
private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
private boolean mIsRestrictedToTestNetworks = false;
+ private boolean mExcludeLocalRoutes = false;
/**
* Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -902,6 +907,18 @@
}
/**
+ * Sets whether the local traffic is exempted from the VPN.
+ *
+ * @hide TODO(184750836): unhide once the implementation is completed
+ */
+ @NonNull
+ @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+ public Builder setExcludeLocalRoutes(boolean excludeLocalRoutes) {
+ mExcludeLocalRoutes = excludeLocalRoutes;
+ return this;
+ }
+
+ /**
* Validates, builds and provisions the VpnProfile.
*
* @throws IllegalArgumentException if any of the required keys or values were invalid
@@ -924,7 +941,8 @@
mIsBypassable,
mIsMetered,
mMaxMtu,
- mIsRestrictedToTestNetworks);
+ mIsRestrictedToTestNetworks,
+ mExcludeLocalRoutes);
}
}
}
diff --git a/core/java/android/net/InternalNetworkManagementException.aidl b/core/java/android/net/InternalNetworkManagementException.aidl
new file mode 100644
index 0000000..dcce706
--- /dev/null
+++ b/core/java/android/net/InternalNetworkManagementException.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.net;
+
+ parcelable InternalNetworkManagementException;
\ No newline at end of file
diff --git a/core/java/android/net/InternalNetworkManagementException.java b/core/java/android/net/InternalNetworkManagementException.java
new file mode 100644
index 0000000..7f4e403
--- /dev/null
+++ b/core/java/android/net/InternalNetworkManagementException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 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.net;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class InternalNetworkManagementException
+ extends RuntimeException implements Parcelable {
+
+ /* @hide */
+ public InternalNetworkManagementException(@NonNull final Throwable t) {
+ super(t);
+ }
+
+ private InternalNetworkManagementException(@NonNull final Parcel source) {
+ super(source.readString());
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(getCause().getMessage());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<InternalNetworkManagementException> CREATOR =
+ new Parcelable.Creator<InternalNetworkManagementException>() {
+ @Override
+ public InternalNetworkManagementException[] newArray(int size) {
+ return new InternalNetworkManagementException[size];
+ }
+
+ @Override
+ public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) {
+ return new InternalNetworkManagementException(source);
+ }
+ };
+}
diff --git a/core/java/android/net/InternalNetworkUpdateRequest.aidl b/core/java/android/net/InternalNetworkUpdateRequest.aidl
new file mode 100644
index 0000000..da00cb9
--- /dev/null
+++ b/core/java/android/net/InternalNetworkUpdateRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.net;
+
+ parcelable InternalNetworkUpdateRequest;
\ No newline at end of file
diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/core/java/android/net/InternalNetworkUpdateRequest.java
new file mode 100644
index 0000000..6f09383
--- /dev/null
+++ b/core/java/android/net/InternalNetworkUpdateRequest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 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.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/** @hide */
+public final class InternalNetworkUpdateRequest implements Parcelable {
+ @NonNull
+ private final StaticIpConfiguration mIpConfig;
+ @Nullable
+ private final NetworkCapabilities mNetworkCapabilities;
+
+ @NonNull
+ public StaticIpConfiguration getIpConfig() {
+ return new StaticIpConfiguration(mIpConfig);
+ }
+
+ @NonNull
+ public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities == null
+ ? null : new NetworkCapabilities(mNetworkCapabilities);
+ }
+
+ /** @hide */
+ public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig,
+ @Nullable final NetworkCapabilities networkCapabilities) {
+ Objects.requireNonNull(ipConfig);
+ mIpConfig = new StaticIpConfiguration(ipConfig);
+ if (null == networkCapabilities) {
+ mNetworkCapabilities = null;
+ } else {
+ mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
+ }
+ }
+
+ private InternalNetworkUpdateRequest(@NonNull final Parcel source) {
+ Objects.requireNonNull(source);
+ mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source);
+ mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source);
+ }
+
+ @Override
+ public String toString() {
+ return "InternalNetworkUpdateRequest{"
+ + "mIpConfig=" + mIpConfig
+ + ", mNetworkCapabilities=" + mNetworkCapabilities + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ InternalNetworkUpdateRequest that = (InternalNetworkUpdateRequest) o;
+
+ return Objects.equals(that.getIpConfig(), mIpConfig)
+ && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIpConfig, mNetworkCapabilities);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ mIpConfig.writeToParcel(dest, flags);
+ mNetworkCapabilities.writeToParcel(dest, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<InternalNetworkUpdateRequest> CREATOR =
+ new Parcelable.Creator<InternalNetworkUpdateRequest>() {
+ @Override
+ public InternalNetworkUpdateRequest[] newArray(int size) {
+ return new InternalNetworkUpdateRequest[size];
+ }
+
+ @Override
+ public InternalNetworkUpdateRequest createFromParcel(@NonNull Parcel source) {
+ return new InternalNetworkUpdateRequest(source);
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 70fe5d6..8b3d49e 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -18,9 +18,11 @@
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.METERED_YES;
+import static android.net.NetworkTemplate.MATCH_BLUETOOTH;
import static android.net.NetworkTemplate.MATCH_CARRIER;
+import static android.net.NetworkTemplate.MATCH_ETHERNET;
import static android.net.NetworkTemplate.MATCH_MOBILE;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+import static android.net.NetworkTemplate.MATCH_WIFI;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,6 +44,7 @@
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.Objects;
+import java.util.Set;
/**
* Policy for networks matching a {@link NetworkTemplate}, including usage cycle
@@ -59,15 +62,16 @@
* Initial Version of the NetworkTemplate backup serializer.
*/
private static final int TEMPLATE_BACKUP_VERSION_1_INIT = 1;
+ private static final int TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED = 2;
/**
* Version of the NetworkTemplate backup serializer that added carrier template support.
*/
- private static final int TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2;
+ private static final int TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE = 3;
/**
* Latest Version of the NetworkTemplate Backup Serializer.
*/
private static final int TEMPLATE_BACKUP_VERSION_LATEST =
- TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE;
+ TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE;
public static final int CYCLE_NONE = -1;
public static final long WARNING_DISABLED = -1;
@@ -324,7 +328,7 @@
@NonNull
private byte[] getNetworkTemplateBytesForBackup() throws IOException {
- if (!template.isPersistable()) {
+ if (!isTemplatePersistable(this.template)) {
Log.wtf(TAG, "Trying to backup non-persistable template: " + this);
}
@@ -334,10 +338,9 @@
out.writeInt(TEMPLATE_BACKUP_VERSION_LATEST);
out.writeInt(template.getMatchRule());
- BackupUtils.writeString(out, template.getSubscriberId());
- BackupUtils.writeString(out, template.getNetworkId());
+ BackupUtils.writeString(out, template.getSubscriberIds().iterator().next());
+ BackupUtils.writeString(out, template.getWifiNetworkKey());
out.writeInt(template.getMeteredness());
- out.writeInt(template.getSubscriberIdMatchRule());
return baos.toByteArray();
}
@@ -346,36 +349,61 @@
private static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
throws IOException, BackupUtils.BadVersionException {
int version = in.readInt();
- if (version < TEMPLATE_BACKUP_VERSION_1_INIT || version > TEMPLATE_BACKUP_VERSION_LATEST) {
+ if (version < TEMPLATE_BACKUP_VERSION_1_INIT || version > TEMPLATE_BACKUP_VERSION_LATEST
+ || version == TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED) {
throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
}
int matchRule = in.readInt();
final String subscriberId = BackupUtils.readString(in);
- final String networkId = BackupUtils.readString(in);
+ final String wifiNetworkKey = BackupUtils.readString(in);
final int metered;
- final int subscriberIdMatchRule;
- if (version >= TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) {
+ if (version >= TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE) {
metered = in.readInt();
- subscriberIdMatchRule = in.readInt();
} else {
// For backward compatibility, fill the missing filters from match rules.
- metered = (matchRule == MATCH_MOBILE
- || matchRule == NetworkTemplate.MATCH_MOBILE_WILDCARD
- || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL;
- subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_CARRIER)
+ ? METERED_YES : METERED_ALL;
}
try {
- return new NetworkTemplate(matchRule,
- subscriberId, new String[]{subscriberId},
- networkId, metered, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
- NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
+ final NetworkTemplate.Builder builder = new NetworkTemplate.Builder(matchRule)
+ .setMeteredness(metered);
+ if (subscriberId != null) {
+ builder.setSubscriberIds(Set.of(subscriberId));
+ }
+ if (wifiNetworkKey != null) {
+ builder.setWifiNetworkKeys(Set.of(wifiNetworkKey));
+ }
+ return builder.build();
} catch (IllegalArgumentException e) {
throw new BackupUtils.BadVersionException(
"Restored network template contains unknown match rule " + matchRule, e);
}
}
+
+ /**
+ * Check if the template can be persisted into disk.
+ */
+ public static boolean isTemplatePersistable(@NonNull NetworkTemplate template) {
+ switch (template.getMatchRule()) {
+ case MATCH_BLUETOOTH:
+ case MATCH_ETHERNET:
+ return true;
+ case MATCH_CARRIER:
+ case MATCH_MOBILE:
+ return !template.getSubscriberIds().isEmpty();
+ case MATCH_WIFI:
+ if (template.getWifiNetworkKeys().isEmpty()
+ && template.getSubscriberIds().isEmpty()) {
+ return false;
+ }
+ return true;
+ default:
+ // Don't allow persistable for unknown types or legacy types such as
+ // MATCH_MOBILE_WILDCARD, MATCH_PROXY, etc.
+ return false;
+ }
+ }
}
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
index 445ec91..777a90c 100644
--- a/core/java/android/net/PlatformVpnProfile.java
+++ b/core/java/android/net/PlatformVpnProfile.java
@@ -66,15 +66,30 @@
@PlatformVpnType protected final int mType;
/** @hide */
- PlatformVpnProfile(@PlatformVpnType int type) {
+ protected final boolean mExcludeLocalRoutes;
+
+ /** @hide */
+ PlatformVpnProfile(@PlatformVpnType int type, boolean excludeLocalRoutes) {
mType = type;
+ mExcludeLocalRoutes = excludeLocalRoutes;
}
+
/** Returns the profile integer type. */
@PlatformVpnType
public final int getType() {
return mType;
}
+
+ /**
+ * Returns if the local traffic is exempted from the VPN.
+ *
+ * @hide TODO(184750836): unhide once the implementation is completed
+ */
+ public final boolean getExcludeLocalRoutes() {
+ return mExcludeLocalRoutes;
+ }
+
/** Returns a type string describing the VPN profile type */
@NonNull
public final String getTypeString() {
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 1e424d1..5d9f2189 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -10,9 +10,8 @@
# BatteryStats
per-file *BatteryConsumer* = file:/BATTERY_STATS_OWNERS
per-file BatteryManager* = file:/BATTERY_STATS_OWNERS
-per-file BatteryStats* = file:/BATTERY_STATS_OWNERS
-per-file BatteryUsageStats* = file:/BATTERY_STATS_OWNERS
per-file PowerComponents.java = file:/BATTERY_STATS_OWNERS
+per-file *Stats* = file:/BATTERY_STATS_OWNERS
# Multiuser
per-file IUser* = file:/MULTIUSER_OWNERS
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2d70bad..d0ef546 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5756,7 +5756,6 @@
MOVED_TO_GLOBAL.add(Settings.Global.CONNECTIVITY_CHANGE_DELAY);
MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_SERVER);
- MOVED_TO_GLOBAL.add(Settings.Global.NSD_ON);
MOVED_TO_GLOBAL.add(Settings.Global.SET_INSTALL_LOCATION);
MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_INSTALL_LOCATION);
MOVED_TO_GLOBAL.add(Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY);
@@ -12631,13 +12630,6 @@
@Readable
public static final String MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS =
"min_duration_between_recovery_steps";
- /**
- * Whether network service discovery is enabled.
- *
- * @hide
- */
- @Readable
- public static final String NSD_ON = "nsd_on";
/**
* Let user pick default install location.
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 0adc00e..1b26465 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3758,6 +3758,25 @@
public static final String NETWORK_TYPE_BITMASK = "network_type_bitmask";
/**
+ * Lingering radio technology (network type) bitmask.
+ * To check what values can be contained, refer to the NETWORK_TYPE_ constants in
+ * {@link android.telephony.TelephonyManager}.
+ * Bitmask for a radio tech R is (1 << (R - 1))
+ * <P>Type: INTEGER (long)</P>
+ * @hide
+ */
+ public static final String LINGERING_NETWORK_TYPE_BITMASK =
+ "lingering_network_type_bitmask";
+
+ /**
+ * Sets whether the PDU session brought up by this APN should always be on.
+ * See 3GPP TS 23.501 section 5.6.13
+ * <P>Type: INTEGER</P>
+ * @hide
+ */
+ public static final String ALWAYS_ON = "always_on";
+
+ /**
* MVNO type:
* {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
* <P>Type: TEXT</P>
@@ -3835,11 +3854,31 @@
* connected, in bytes.
* <p>Type: INTEGER </p>
* @hide
+ * @deprecated use {@link #MTU_V4} or {@link #MTU_V6} instead
*/
@SystemApi
+ @Deprecated
public static final String MTU = "mtu";
/**
+ * The MTU (maximum transmit unit) size of the mobile interface for IPv4 to which the APN is
+ * connected, in bytes.
+ * <p>Type: INTEGER </p>
+ * @hide
+ */
+ @SystemApi
+ public static final String MTU_V4 = "mtu_v4";
+
+ /**
+ * The MTU (maximum transmit unit) size of the mobile interface for IPv6 to which the APN is
+ * connected, in bytes.
+ * <p>Type: INTEGER </p>
+ * @hide
+ */
+ @SystemApi
+ public static final String MTU_V6 = "mtu_v6";
+
+ /**
* APN edit status. APN could be added/edited/deleted by a user or carrier.
* see all possible returned APN edit status.
* <ul>
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 13274c6..29c7796 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -465,7 +465,7 @@
* <p>Prior to Android {@link android.os.Build.VERSION_CODES#P}, the metrics covered just the
* scenarios where the service knew how to autofill an activity, but Android
* {@link android.os.Build.VERSION_CODES#P} introduced a new mechanism called field classification,
- * which allows the service to dinamically classify the meaning of fields based on the existing user
+ * which allows the service to dynamically classify the meaning of fields based on the existing user
* data known by the service.
*
* <p>Typically, field classification can be used to detect fields that can be autofilled with
diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java
index 052959a..1b6cb29 100644
--- a/core/java/com/android/internal/net/NetworkUtilsInternal.java
+++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java
@@ -74,35 +74,4 @@
return true;
}
-
- /**
- * Safely multiple a value by a rational.
- * <p>
- * Internally it uses integer-based math whenever possible, but switches
- * over to double-based math if values would overflow.
- * @hide
- */
- public static long multiplySafeByRational(long value, long num, long den) {
- if (den == 0) {
- throw new ArithmeticException("Invalid Denominator");
- }
- long x = value;
- long y = num;
-
- // Logic shamelessly borrowed from Math.multiplyExact()
- long r = x * y;
- long ax = Math.abs(x);
- long ay = Math.abs(y);
- if (((ax | ay) >>> 31 != 0)) {
- // Some bits greater than 2^31 that might cause overflow
- // Check the result using the divide operator
- // and check for the special case of Long.MIN_VALUE * -1
- if (((y != 0) && (r / y != x))
- || (x == Long.MIN_VALUE && y == -1)) {
- // Use double math to avoid overflowing
- return (long) (((double) num / den) * value);
- }
- }
- return r / den;
- }
}
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 5f84b5a..d8dc143 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -143,17 +143,24 @@
public boolean areAuthParamsInline = false; // 23
public final boolean isRestrictedToTestNetworks; // 24
+ public final boolean excludeLocalRoutes; // 25
+
// Helper fields.
@UnsupportedAppUsage
public transient boolean saveLogin = false;
public VpnProfile(String key) {
- this(key, false);
+ this(key, false, false);
}
public VpnProfile(String key, boolean isRestrictedToTestNetworks) {
+ this(key, isRestrictedToTestNetworks, false);
+ }
+
+ public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes) {
this.key = key;
this.isRestrictedToTestNetworks = isRestrictedToTestNetworks;
+ this.excludeLocalRoutes = excludeLocalRoutes;
}
@UnsupportedAppUsage
@@ -183,6 +190,7 @@
maxMtu = in.readInt();
areAuthParamsInline = in.readBoolean();
isRestrictedToTestNetworks = in.readBoolean();
+ excludeLocalRoutes = in.readBoolean();
}
/**
@@ -230,6 +238,7 @@
out.writeInt(maxMtu);
out.writeBoolean(areAuthParamsInline);
out.writeBoolean(isRestrictedToTestNetworks);
+ out.writeBoolean(excludeLocalRoutes);
}
/**
@@ -249,8 +258,9 @@
// 14-19: Standard profile, with option for serverCert, proxy
// 24: Standard profile with serverCert, proxy and platform-VPN parameters
// 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks
+ // 26: Standard profile with platform-VPN parameters and excludeLocalRoutes
if ((values.length < 14 || values.length > 19)
- && values.length != 24 && values.length != 25) {
+ && values.length != 24 && values.length != 25 && values.length != 26) {
return null;
}
@@ -261,7 +271,15 @@
isRestrictedToTestNetworks = false;
}
- VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks);
+ final boolean excludeLocalRoutes;
+ if (values.length >= 26) {
+ excludeLocalRoutes = Boolean.parseBoolean(values[25]);
+ } else {
+ excludeLocalRoutes = false;
+ }
+
+ VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks,
+ excludeLocalRoutes);
profile.name = values[0];
profile.type = Integer.parseInt(values[1]);
if (profile.type < 0 || profile.type > TYPE_MAX) {
@@ -371,6 +389,8 @@
builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks);
+ builder.append(VALUE_DELIMITER).append(excludeLocalRoutes);
+
return builder.toString().getBytes(StandardCharsets.UTF_8);
}
@@ -451,7 +471,7 @@
key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline,
- isRestrictedToTestNetworks);
+ isRestrictedToTestNetworks, excludeLocalRoutes);
}
/** Checks VPN profiles for interior equality. */
@@ -484,7 +504,8 @@
&& isMetered == other.isMetered
&& maxMtu == other.maxMtu
&& areAuthParamsInline == other.areAuthParamsInline
- && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks;
+ && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks
+ && excludeLocalRoutes == other.excludeLocalRoutes;
}
@NonNull
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a131111..0f98b74 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -228,8 +228,7 @@
// TODO: Rename the server-level flag or remove.
static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
// Flag to pass to the runtime when using the JIT Zygote image.
-static const char* kJitZygoteImageOption =
- "-Ximage:boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
+static const char* kJitZygoteImageOption = "-Xforcejitzygote";
// Feature flag name for disabling lock profiling.
static const char* DISABLE_LOCK_PROFILING = "disable_lock_profiling";
@@ -983,9 +982,9 @@
"--instruction-set-features=", "-Xcompiler-option");
/*
- * When running with debug.generate-debug-info, add --generate-debug-info to
- * the compiler options so that both JITted code and the boot image extension,
- * if it is compiled on device, will include native debugging information.
+ * When running with debug.generate-debug-info, add --generate-debug-info to the compiler
+ * options so that both JITted code and the boot image, if it is compiled on device, will
+ * include native debugging information.
*/
property_get("debug.generate-debug-info", propBuf, "");
bool generate_debug_info = (strcmp(propBuf, "true") == 0);
@@ -1008,7 +1007,7 @@
property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
parseExtraOpts(extraOptsBuf, NULL);
- // Extra options for boot image extension generation.
+ // Extra options for boot image generation.
if (skip_compilation) {
addOption("-Xnoimage-dex2oat");
} else {
@@ -1031,8 +1030,8 @@
parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
"-Ximage-compiler-option");
- // The runtime may compile a boot image extension, when necessary, not using installd.
- // Thus, we need to pass the instruction-set-features/variant as an image-compiler-option.
+ // The runtime may compile a boot image, when necessary, not using installd. Thus, we need
+ // to pass the instruction-set-features/variant as an image-compiler-option.
// Note: it is OK to reuse the buffer, as the values are exactly the same between
// * compiler-option, used for runtime compilation (DexClassLoader)
// * image-compiler-option, used for boot-image compilation on device
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 790c39e..832c498 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -55,13 +55,17 @@
per-file android_media_midi_* = file:/media/java/android/media/midi/OWNERS
per-file android_opengl_* = file:/opengl/java/android/opengl/OWNERS
per-file android_os_storage_* = file:/core/java/android/os/storage/OWNERS
-per-file android_se_* = file:/core/java/android/se/OWNERS
+per-file android_se_* = file:/omapi/java/android/se/OWNERS
per-file android_security_* = file:/core/java/android/security/OWNERS
per-file android_view_* = file:/core/java/android/view/OWNERS
per-file com_android_internal_net_* = file:/services/core/java/com/android/server/net/OWNERS
### Graphics ###
per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
+
+### Text ###
+per-file android_text_* = file:/core/java/android/text/OWNERS
+
# These are highly common-use files
per-file Android.bp = file:/graphics/java/android/graphics/OWNERS
per-file AndroidRuntime.cpp = file:/graphics/java/android/graphics/OWNERS
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index ca9124a..e035ab1 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -716,8 +716,6 @@
optional SettingProto nr_nsa_tracking_screen_off_mode = 153 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto nsd_on = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
-
message Ntp {
option (android.msg_privacy).dest = DEST_EXPLICIT;
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
index d936cad..3c8f90c 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
+++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
@@ -16,6 +16,10 @@
package android.net
+import android.net.NetworkTemplate.MATCH_BLUETOOTH
+import android.net.NetworkTemplate.MATCH_ETHERNET
+import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_WIFI
import android.text.format.Time.TIMEZONE_UTC
import androidx.test.runner.AndroidJUnit4
import org.junit.Test
@@ -24,16 +28,18 @@
import java.io.DataInputStream
import java.time.ZoneId
import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
private const val TEST_IMSI1 = "TESTIMSI1"
-private const val TEST_SSID1 = "TESTISSID1"
+private const val TEST_WIFI_NETWORK_KEY1 = "TESTKEY1"
@RunWith(AndroidJUnit4::class)
class NetworkPolicyTest {
@Test
fun testTemplateBackupRestore() {
assertPolicyBackupRestore(createTestPolicyForTemplate(
- NetworkTemplate.buildTemplateWifi(TEST_SSID1)))
+ NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1)))
assertPolicyBackupRestore(createTestPolicyForTemplate(
NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1)))
assertPolicyBackupRestore(createTestPolicyForTemplate(
@@ -53,4 +59,26 @@
val restored = NetworkPolicy.getNetworkPolicyFromBackup(stream)
assertEquals(policy, restored)
}
-}
\ No newline at end of file
+
+ @Test
+ fun testIsTemplatePersistable() {
+ listOf(MATCH_MOBILE, MATCH_WIFI).forEach {
+ // Verify wildcard templates cannot be persistable.
+ assertFalse(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build()))
+
+ // Verify mobile/wifi templates can be persistable if the Subscriber Id is supplied.
+ assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it)
+ .setSubscriberIds(setOf(TEST_IMSI1)).build()))
+ }
+
+ // Verify bluetooth and ethernet templates can be persistable without any other
+ // field is supplied.
+ listOf(MATCH_BLUETOOTH, MATCH_ETHERNET).forEach {
+ assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build()))
+ }
+
+ // Verify wifi template can be persistable if the Wifi Network Key is supplied.
+ assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(MATCH_WIFI)
+ .setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1)).build()))
+ }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 60f4a5a..b7e8c8c 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1172,7 +1172,8 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
public int getLastAudibleStreamVolume(int streamType) {
final IAudioService service = getService();
try {
@@ -6791,56 +6792,63 @@
/**
* Returns a list of audio formats that corresponds to encoding formats
- * supported on offload path for A2DP and LE audio playback.
+ * supported on offload path for A2DP playback.
*
- * @param deviceType Indicates the target device type {@link AudioSystem.DeviceType}
* @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
- * supported for offload A2DP playback or a list of {@link BluetoothLeAudioCodecConfig}
- * objects containing encoding formats supported for offload LE Audio playback
+ * supported for offload A2DP playback
* @hide
*/
- public List<?> getHwOffloadFormatsSupportedForBluetoothMedia(
- @AudioSystem.DeviceType int deviceType) {
- ArrayList<Integer> formatsList = new ArrayList<Integer>();
- ArrayList<BluetoothCodecConfig> a2dpCodecConfigList = new ArrayList<BluetoothCodecConfig>();
- ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList =
- new ArrayList<BluetoothLeAudioCodecConfig>();
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
+ ArrayList<Integer> formatsList = new ArrayList<>();
+ ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
- if (deviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
- && deviceType != AudioSystem.DEVICE_OUT_BLE_HEADSET) {
- throw new IllegalArgumentException(
- "Illegal devicetype for the getHwOffloadFormatsSupportedForBluetoothMedia");
- }
-
- int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(deviceType,
- formatsList);
+ int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
if (status != AudioManager.SUCCESS) {
- Log.e(TAG, "getHwOffloadFormatsSupportedForBluetoothMedia for deviceType "
- + deviceType + " failed:" + status);
- return a2dpCodecConfigList;
+ Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
+ return codecConfigList;
}
- if (deviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
- for (Integer format : formatsList) {
- int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
- if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
- a2dpCodecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
- }
+ for (Integer format : formatsList) {
+ int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
+ if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+ codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
}
- return a2dpCodecConfigList;
- } else if (deviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) {
- for (Integer format : formatsList) {
- int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
- if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
- leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
- .setCodecType(btLeAudioCodec)
- .build());
- }
- }
+ }
+ return codecConfigList;
+ }
+
+ /**
+ * Returns a list of audio formats that corresponds to encoding formats
+ * supported on offload path for Le audio playback.
+ *
+ * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+ * supported for offload Le Audio playback
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+ ArrayList<Integer> formatsList = new ArrayList<>();
+ ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
+
+ int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
+ AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
+ if (status != AudioManager.SUCCESS) {
+ Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
return leAudioCodecConfigList;
}
- Log.e(TAG, "Input deviceType " + deviceType + " doesn't support.");
- return a2dpCodecConfigList;
+
+ for (Integer format : formatsList) {
+ int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
+ if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
+ leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
+ .setCodecType(btLeAudioCodec)
+ .build());
+ }
+ }
+ return leAudioCodecConfigList;
}
// Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index 875c6f5..7749564 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -31,35 +31,33 @@
/**
* JetPlayer provides access to JET content playback and control.
- *
- * <p>Please refer to the JET Creator User Manual for a presentation of the JET interactive
- * music concept and how to use the JetCreator tool to create content to be player by JetPlayer.
- *
+ *
+ * <p>Please refer to the
+ * <a href="https://developer.android.com/guide/topics/media/jet/jetcreator_manual">JET Creator User
+ * Manual</a> for a presentation of the JET interactive music concept and how to use the JetCreator
+ * tool to create content to be player by JetPlayer.
+ *
* <p>Use of the JetPlayer class is based around the playback of a number of JET segments
* sequentially added to a playback FIFO queue. The rendering of the MIDI content stored in each
* segment can be dynamically affected by two mechanisms:
* <ul>
- * <li>tracks in a segment can be muted or unmuted at any moment, individually or through
- * a mask (to change the mute state of multiple tracks at once)</li>
- * <li>parts of tracks in a segment can be played at predefined points in the segment, in order
- * to maintain synchronization with the other tracks in the segment. This is achieved through
- * the notion of "clips", which can be triggered at any time, but that will play only at the
- * right time, as authored in the corresponding JET file.</li>
+ * <li>Tracks in a segment can be muted or unmuted at any moment, individually or through a mask
+ * (to change the mute state of multiple tracks at once).
+ * <li>Parts of tracks in a segment can be played at predefined points in the segment, in order to
+ * maintain synchronization with the other tracks in the segment. This is achieved through the
+ * notion of "clips", which can be triggered at any time, but that will play only at the right
+ * time, as authored in the corresponding JET file.
* </ul>
- * As a result of the rendering and playback of the JET segments, the user of the JetPlayer instance
- * can receive notifications from the JET engine relative to:
- * <ul>
- * <li>the playback state,</li>
- * <li>the number of segments left to play in the queue,</li>
- * <li>application controller events (CC80-83) to mark points in the MIDI segments.</li>
- * </ul>
- * Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
- * </p>
*
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about how to use JetPlayer, read the
- * <a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a> developer guide.</p></div>
+ * <p>As a result of the rendering and playback of the JET segments, the user of the JetPlayer
+ * instance can receive notifications from the JET engine relative to:
+ * <ul>
+ * <li>Playback state
+ * <li>Number of segments left to play in the queue
+ * <li>Application controller events (CC80-83) to mark points in the MIDI segments
+ * </ul>
+ *
+ * <p>Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
*/
public class JetPlayer
{
@@ -140,7 +138,7 @@
//------------------------
/**
* Factory method for the JetPlayer class.
- * @return the singleton JetPlayer instance
+ * @return the singleton JetPlayer instance.
*/
public static JetPlayer getJetPlayer() {
if (singletonRef == null) {
@@ -203,7 +201,8 @@
// Getters
//------------------------
/**
- * Returns the maximum number of simultaneous MIDI tracks supported by JetPlayer
+ * Gets the maximum number of simultaneous MIDI tracks supported by JetPlayer.
+ * @return the maximum number of simultaneous MIDI tracks supported by JetPlayer.
*/
public static int getMaxTracks() {
return JetPlayer.MAXTRACKS;
@@ -459,10 +458,9 @@
//------------------------
/**
* Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
- * playback engine.
- * Notifications will be received in the same thread as the one in which the JetPlayer
- * instance was created.
- * @param listener
+ * playback engine. Notifications are received in the same thread as the one in which the
+ * JetPlayer instance was created.
+ * @param listener the listener that will be notified when a JET event is generated.
*/
public void setEventListener(OnJetEventListener listener) {
setEventListener(listener, null);
@@ -470,10 +468,9 @@
/**
* Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
- * playback engine.
- * Use this method to receive JET events in the Handler associated with another
- * thread than the one in which you created the JetPlayer instance.
- * @param listener
+ * playback engine. Use this method to receive JET events in the Handler associated with
+ * another thread than the one in which you created the JetPlayer instance.
+ * @param listener the listener that will be notified when a JET event is generated.
* @param handler the Handler that will receive the event notification messages.
*/
public void setEventListener(OnJetEventListener listener, Handler handler) {
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index dcd4dce..ec56d61 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -16,8 +16,11 @@
package android.media;
-import android.media.AudioManager;
+import android.content.Context;
import android.media.SoundPool;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
/**
@@ -104,6 +107,26 @@
private static final int STATE_LOADING_PLAY_REQUESTED = 2;
private static final int STATE_LOADED = 3;
+ /**
+ * <p>Returns true if the application must play the shutter sound in accordance
+ * to certain regional restrictions. </p>
+ *
+ * <p>If this method returns true, applications are strongly recommended to use
+ * MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures
+ * images or video to storage or sends them over the network.</p>
+ */
+ public static boolean mustPlayShutterSound() {
+ boolean result = false;
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService audioService = IAudioService.Stub.asInterface(b);
+ try {
+ result = audioService.isCameraSoundForced();
+ } catch (RemoteException e) {
+ Log.e(TAG, "audio service is unavailable for queries, defaulting to false");
+ }
+ return result;
+ }
+
private class SoundState {
public final int name;
public int id;
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index d8d1ba13..a0827ac 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -45,6 +45,8 @@
TvInputInfo getTvInputInfo(in String inputId, int userId);
void updateTvInputInfo(in TvInputInfo inputInfo, int userId);
int getTvInputState(in String inputId, int userId);
+ List<String> getAvailableExtensionInterfaceNames(in String inputId, int userId);
+ IBinder getExtensionInterface(in String inputId, in String name, int userId);
List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
index 8ccf13a..64a23a2 100755
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -26,18 +26,21 @@
* Top-level interface to a TV input component (implemented in a Service).
* @hide
*/
-oneway interface ITvInputService {
- void registerCallback(in ITvInputServiceCallback callback);
- void unregisterCallback(in ITvInputServiceCallback callback);
- void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
+interface ITvInputService {
+ oneway void registerCallback(in ITvInputServiceCallback callback);
+ oneway void unregisterCallback(in ITvInputServiceCallback callback);
+ oneway void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
in String inputId, in String sessionId);
- void createRecordingSession(in ITvInputSessionCallback callback, in String inputId,
+ oneway void createRecordingSession(in ITvInputSessionCallback callback, in String inputId,
in String sessionId);
+ List<String> getAvailableExtensionInterfaceNames();
+ IBinder getExtensionInterface(in String name);
+ String getExtensionInterfacePermission(in String name);
// For hardware TvInputService
- void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
- void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
- void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
- void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
- void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
+ oneway void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
+ oneway void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
+ oneway void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
+ oneway void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
+ oneway void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
}
diff --git a/media/java/android/media/tv/OWNERS b/media/java/android/media/tv/OWNERS
index 8bccc9a..33acd0d 100644
--- a/media/java/android/media/tv/OWNERS
+++ b/media/java/android/media/tv/OWNERS
@@ -1,5 +1,6 @@
nchalko@google.com
quxiangfang@google.com
+shubang@google.com
# For android remote service
per-file ITvRemoteServiceInput.aidl = file:/media/lib/tvremote/OWNERS
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 34e4609..efd9d10 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1390,6 +1390,57 @@
}
/**
+ * Returns available extension interfaces of a given hardware TV input. This can be used to
+ * provide domain-specific features that are only known between certain hardware TV inputs
+ * and their clients.
+ *
+ * @param inputId The ID of the TV input.
+ * @return a non-null list of extension interface names available to the caller. An empty
+ * list indicates the given TV input is not found, or the given TV input is not a
+ * hardware TV input, or the given TV input doesn't support any extension
+ * interfaces, or the caller doesn't hold the required permission for the extension
+ * interfaces supported by the given TV input.
+ * @see #getExtensionInterface
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public List<String> getAvailableExtensionInterfaceNames(@NonNull String inputId) {
+ Preconditions.checkNotNull(inputId);
+ try {
+ return mService.getAvailableExtensionInterfaceNames(inputId, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns an extension interface of a given hardware TV input. This can be used to provide
+ * domain-specific features that are only known between certain hardware TV inputs and
+ * their clients.
+ *
+ * @param inputId The ID of the TV input.
+ * @param name The extension interface name.
+ * @return an {@link IBinder} for the given extension interface, {@code null} if the given TV
+ * input is not found, or if the given TV input is not a hardware TV input, or if the
+ * given TV input doesn't support the given extension interface, or if the caller
+ * doesn't hold the required permission for the given extension interface.
+ * @see #getAvailableExtensionInterfaceNames
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public IBinder getExtensionInterface(@NonNull String inputId, @NonNull String name) {
+ Preconditions.checkNotNull(inputId);
+ Preconditions.checkNotNull(name);
+ try {
+ return mService.getExtensionInterface(inputId, name, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Registers a {@link TvInputCallback}.
*
* @param callback A callback used to monitor status of the TV inputs.
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 77fb2b2..4a429fb 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -201,6 +201,21 @@
}
@Override
+ public List<String> getAvailableExtensionInterfaceNames() {
+ return TvInputService.this.getAvailableExtensionInterfaceNames();
+ }
+
+ @Override
+ public IBinder getExtensionInterface(String name) {
+ return TvInputService.this.getExtensionInterface(name);
+ }
+
+ @Override
+ public String getExtensionInterfacePermission(String name) {
+ return TvInputService.this.getExtensionInterfacePermission(name);
+ }
+
+ @Override
public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
@@ -253,6 +268,67 @@
}
/**
+ * Returns available extension interfaces. This can be used to provide domain-specific
+ * features that are only known between certain hardware TV inputs and their clients.
+ *
+ * <p>Note that this service-level extension interface mechanism is only for hardware
+ * TV inputs that are bound even when sessions are not created.
+ *
+ * @return a non-null list of available extension interface names. An empty list
+ * indicates the TV input doesn't support any extension interfaces.
+ * @see #getExtensionInterface
+ * @see #getExtensionInterfacePermission
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public List<String> getAvailableExtensionInterfaceNames() {
+ return new ArrayList<>();
+ }
+
+ /**
+ * Returns an extension interface. This can be used to provide domain-specific features
+ * that are only known between certain hardware TV inputs and their clients.
+ *
+ * <p>Note that this service-level extension interface mechanism is only for hardware
+ * TV inputs that are bound even when sessions are not created.
+ *
+ * @param name The extension interface name.
+ * @return an {@link IBinder} for the given extension interface, {@code null} if the TV input
+ * doesn't support the given extension interface.
+ * @see #getAvailableExtensionInterfaceNames
+ * @see #getExtensionInterfacePermission
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public IBinder getExtensionInterface(@NonNull String name) {
+ return null;
+ }
+
+ /**
+ * Returns a permission for the given extension interface. This can be used to provide
+ * domain-specific features that are only known between certain hardware TV inputs and their
+ * clients.
+ *
+ * <p>Note that this service-level extension interface mechanism is only for hardware
+ * TV inputs that are bound even when sessions are not created.
+ *
+ * @param name The extension interface name.
+ * @return a name of the permission being checked for the given extension interface,
+ * {@code null} if there is no required permission, or if the TV input doesn't
+ * support the given extension interface.
+ * @see #getAvailableExtensionInterfaceNames
+ * @see #getExtensionInterface
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public String getExtensionInterfacePermission(@NonNull String name) {
+ return null;
+ }
+
+ /**
* Returns a concrete implementation of {@link Session}.
*
* <p>May return {@code null} if this TV input service fails to create a session for some
diff --git a/omapi/aidl/Android.bp b/omapi/aidl/Android.bp
index 2b81200..d80317b 100644
--- a/omapi/aidl/Android.bp
+++ b/omapi/aidl/Android.bp
@@ -28,8 +28,5 @@
rust: {
enabled: true,
},
- ndk: {
- separate_platform_variant: false,
- },
},
}
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
index 216a4a0..f684a4d 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
@@ -24,13 +24,15 @@
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.RemoteException;
-import android.util.IntArray;
import android.util.Log;
+import com.android.net.module.util.CollectionUtils;
+
import dalvik.system.CloseGuard;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
/**
* Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects
@@ -568,7 +570,7 @@
// the filtering logic below can be removed.
int[] uids = mSession.getRelevantUids();
// Filtering of uids with empty history.
- IntArray filteredUids = new IntArray(uids.length);
+ final ArrayList<Integer> filteredUids = new ArrayList<>();
for (int uid : uids) {
try {
NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid,
@@ -581,7 +583,7 @@
Log.w(TAG, "Error while getting history of uid " + uid, e);
}
}
- mUids = filteredUids.toArray();
+ mUids = CollectionUtils.toIntArray(filteredUids);
mUidOrUidIndex = -1;
stepHistory();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index ca83309..a316b8a 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -47,7 +47,6 @@
import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.DataUnit;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -119,7 +118,7 @@
* is reached.
* @hide
*/
- public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2);
+ public static final long MIN_THRESHOLD_BYTES = 2 * 1_048_576L; // 2MiB
private final Context mContext;
private final INetworkStatsService mService;
@@ -139,6 +138,7 @@
mContext = context;
mService = service;
setPollOnOpen(true);
+ setAugmentWithSubscriptionPlan(true);
}
/** @hide */
@@ -170,16 +170,44 @@
}
}
- /** @hide */
- public Bucket querySummaryForDevice(NetworkTemplate template,
- long startTime, long endTime) throws SecurityException, RemoteException {
- Bucket bucket = null;
- NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
- mService);
- bucket = stats.getDeviceSummaryForNetwork();
-
- stats.close();
- return bucket;
+ /**
+ * Query network usage statistics summaries.
+ *
+ * Result is summarised data usage for the whole
+ * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
+ * roaming. This means the bucket's start and end timestamp will be the same as the
+ * 'startTime' and 'endTime' arguments. State is going to be
+ * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
+ * tag {@link NetworkStats.Bucket#TAG_NONE},
+ * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+ * metered {@link NetworkStats.Bucket#METERED_ALL},
+ * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ *
+ * @param template Template used to match networks. See {@link NetworkTemplate}.
+ * @param startTime Start of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Bucket Summarised data usage.
+ *
+ * @hide
+ */
+ @NonNull
+ @WorkerThread
+ // @SystemApi(client = MODULE_LIBRARIES)
+ public Bucket querySummaryForDevice(@NonNull NetworkTemplate template,
+ long startTime, long endTime) {
+ try {
+ NetworkStats stats =
+ new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+ Bucket bucket = stats.getDeviceSummaryForNetwork();
+ stats.close();
+ return bucket;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null; // To make the compiler happy.
}
/**
@@ -323,14 +351,37 @@
return querySummary(template, startTime, endTime);
}
- /** @hide */
- public NetworkStats querySummary(NetworkTemplate template, long startTime,
- long endTime) throws SecurityException, RemoteException {
- NetworkStats result;
- result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
- result.startSummaryEnumeration();
-
- return result;
+ /**
+ * Query network usage statistics summaries.
+ *
+ * The results will only include traffic made by UIDs belonging to the calling user profile.
+ * The results are aggregated over time, so that all buckets will have the same start and
+ * end timestamps as the passed arguments. Not aggregated over state, uid, default network,
+ * metered, or roaming.
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ *
+ * @param template Template used to match networks. See {@link NetworkTemplate}.
+ * @param startTime Start of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Statistics which is described above.
+ * @hide
+ */
+ @Nullable
+ // @SystemApi(client = MODULE_LIBRARIES)
+ @WorkerThread
+ public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime,
+ long endTime) throws SecurityException {
+ try {
+ NetworkStats result =
+ new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+ result.startSummaryEnumeration();
+ return result;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null; // To make the compiler happy.
}
/**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 7cd63ef..ece54df 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -16,7 +16,9 @@
package android.net;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -32,6 +34,7 @@
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
/**
* A class representing the IP configuration of the Ethernet network.
@@ -315,4 +318,83 @@
}
return new TetheredInterfaceRequest(mService, cbInternal);
}
+
+ private static final class InternalNetworkManagementListener
+ extends IInternalNetworkManagementListener.Stub {
+ @NonNull
+ private final Executor mExecutor;
+ @NonNull
+ private final BiConsumer<Network, InternalNetworkManagementException> mListener;
+
+ InternalNetworkManagementListener(
+ @NonNull final Executor executor,
+ @NonNull final BiConsumer<Network, InternalNetworkManagementException> listener) {
+ Objects.requireNonNull(executor, "Pass a non-null executor");
+ Objects.requireNonNull(listener, "Pass a non-null listener");
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onComplete(
+ @Nullable final Network network,
+ @Nullable final InternalNetworkManagementException e) {
+ mExecutor.execute(() -> mListener.accept(network, e));
+ }
+ }
+
+ private InternalNetworkManagementListener getInternalNetworkManagementListener(
+ @Nullable final Executor executor,
+ @Nullable final BiConsumer<Network, InternalNetworkManagementException> listener) {
+ if (null != listener) {
+ Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+ }
+ final InternalNetworkManagementListener proxy;
+ if (null == listener) {
+ proxy = null;
+ } else {
+ proxy = new InternalNetworkManagementListener(executor, listener);
+ }
+ return proxy;
+ }
+
+ private void updateConfiguration(
+ @NonNull String iface,
+ @NonNull InternalNetworkUpdateRequest request,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+ final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+ executor, listener);
+ try {
+ mService.updateConfiguration(iface, request, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void connectNetwork(
+ @NonNull String iface,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+ final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+ executor, listener);
+ try {
+ mService.connectNetwork(iface, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void disconnectNetwork(
+ @NonNull String iface,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+ final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+ executor, listener);
+ try {
+ mService.disconnectNetwork(iface, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
index e058e5a..e688bea 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
@@ -18,6 +18,8 @@
import android.net.IpConfiguration;
import android.net.IEthernetServiceListener;
+import android.net.IInternalNetworkManagementListener;
+import android.net.InternalNetworkUpdateRequest;
import android.net.ITetheredInterfaceCallback;
/**
@@ -36,4 +38,8 @@
void setIncludeTestInterfaces(boolean include);
void requestTetheredInterface(in ITetheredInterfaceCallback callback);
void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
+ void updateConfiguration(String iface, in InternalNetworkUpdateRequest request,
+ in IInternalNetworkManagementListener listener);
+ void connectNetwork(String iface, in IInternalNetworkManagementListener listener);
+ void disconnectNetwork(String iface, in IInternalNetworkManagementListener listener);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
index 8376299..0d15dff 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
@@ -17,8 +17,6 @@
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.NonNull;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -46,6 +44,7 @@
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
+import java.util.Objects;
/**
* This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
@@ -86,6 +85,7 @@
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final int DIRECTION_FWD = 2;
/**
@@ -988,7 +988,7 @@
*/
public IpSecManager(Context ctx, IIpSecService service) {
mContext = ctx;
- mService = checkNotNull(service, "missing service");
+ mService = Objects.requireNonNull(service, "missing service");
}
private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
index b48c1fd..36199a0 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
@@ -33,7 +33,6 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
@@ -41,6 +40,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
+import java.util.Objects;
/**
* This class represents a transform, which roughly corresponds to an IPsec Security Association.
@@ -255,7 +255,7 @@
@NonNull
public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
- Preconditions.checkNotNull(algo);
+ Objects.requireNonNull(algo);
mConfig.setEncryption(algo);
return this;
}
@@ -270,7 +270,7 @@
@NonNull
public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
- Preconditions.checkNotNull(algo);
+ Objects.requireNonNull(algo);
mConfig.setAuthentication(algo);
return this;
}
@@ -290,7 +290,7 @@
*/
@NonNull
public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
- Preconditions.checkNotNull(algo);
+ Objects.requireNonNull(algo);
mConfig.setAuthenticatedEncryption(algo);
return this;
}
@@ -311,7 +311,7 @@
@NonNull
public IpSecTransform.Builder setIpv4Encapsulation(
@NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
- Preconditions.checkNotNull(localSocket);
+ Objects.requireNonNull(localSocket);
mConfig.setEncapType(ENCAP_ESPINUDP);
if (localSocket.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid UdpEncapsulationSocket");
@@ -348,8 +348,8 @@
@NonNull IpSecManager.SecurityParameterIndex spi)
throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException {
- Preconditions.checkNotNull(sourceAddress);
- Preconditions.checkNotNull(spi);
+ Objects.requireNonNull(sourceAddress);
+ Objects.requireNonNull(spi);
if (spi.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid SecurityParameterIndex");
}
@@ -387,8 +387,8 @@
@NonNull IpSecManager.SecurityParameterIndex spi)
throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException {
- Preconditions.checkNotNull(sourceAddress);
- Preconditions.checkNotNull(spi);
+ Objects.requireNonNull(sourceAddress);
+ Objects.requireNonNull(spi);
if (spi.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid SecurityParameterIndex");
}
@@ -404,7 +404,7 @@
* @param context current context
*/
public Builder(@NonNull Context context) {
- Preconditions.checkNotNull(context);
+ Objects.requireNonNull(context);
mContext = context;
mConfig = new IpSecConfig();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
index eb8f43e..8f1115e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
@@ -21,7 +21,6 @@
import android.annotation.Nullable;
import android.content.Context;
import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
import android.service.NetworkIdentityProto;
import android.telephony.Annotation.NetworkType;
import android.util.proto.ProtoOutputStream;
@@ -228,11 +227,11 @@
final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
if (legacyType == TYPE_WIFI) {
- networkId = snapshot.getNetworkCapabilities().getSsid();
- if (networkId == null) {
- final WifiManager wifi = context.getSystemService(WifiManager.class);
- final WifiInfo info = wifi.getConnectionInfo();
- networkId = info != null ? info.getSSID() : null;
+ final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
+ .getTransportInfo();
+ if (transportInfo instanceof WifiInfo) {
+ final WifiInfo info = (WifiInfo) transportInfo;
+ networkId = info != null ? info.getCurrentNetworkKey() : null;
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index c7ffc19..181a594 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -16,7 +16,7 @@
package android.net;
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
+import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -31,7 +31,7 @@
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.CollectionUtils;
import libcore.util.EmptyArray;
@@ -1185,7 +1185,7 @@
* @hide
*/
public void removeUids(int[] uids) {
- filter(e -> !ArrayUtils.contains(uids, e.uid));
+ filter(e -> !CollectionUtils.contains(uids, e.uid));
}
/**
@@ -1218,7 +1218,7 @@
filter(e -> (limitUid == UID_ALL || limitUid == e.uid)
&& (limitTag == TAG_ALL || limitTag == e.tag)
&& (limitIfaces == INTERFACES_ALL
- || ArrayUtils.contains(limitIfaces, e.iface)));
+ || CollectionUtils.contains(limitIfaces, e.iface)));
}
/**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
index 3885a9e..b64fbdb 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
@@ -17,6 +17,7 @@
package android.net;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING;
@@ -24,7 +25,7 @@
import android.Manifest;
import android.annotation.IntDef;
import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -32,8 +33,6 @@
import android.os.UserHandle;
import android.telephony.TelephonyManager;
-import com.android.server.LocalServices;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -108,9 +107,8 @@
/** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
public static @NetworkStatsAccess.Level int checkAccessLevel(
- Context context, int callingUid, String callingPackage) {
- final DevicePolicyManagerInternal dpmi = LocalServices.getService(
- DevicePolicyManagerInternal.class);
+ Context context, int callingPid, int callingUid, String callingPackage) {
+ final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class);
final TelephonyManager tm = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
boolean hasCarrierPrivileges;
@@ -123,10 +121,15 @@
Binder.restoreCallingIdentity(token);
}
- final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid);
+ final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage);
final int appId = UserHandle.getAppId(callingUid);
+
+ final boolean isNetworkStack = context.checkPermission(
+ android.Manifest.permission.NETWORK_STACK, callingPid, callingUid)
+ == PERMISSION_GRANTED;
+
if (hasCarrierPrivileges || isDeviceOwner
- || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) {
+ || appId == Process.SYSTEM_UID || isNetworkStack) {
// Carrier-privileged apps and device owners, and the system (including the
// network stack) can access data usage for all apps on the device.
return NetworkStatsAccess.Level.DEVICE;
@@ -139,8 +142,8 @@
}
//TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
- boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid)
- || dpmi.isActiveDeviceOwner(callingUid));
+ boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage)
+ || mDpm.isDeviceOwnerApp(callingPackage));
if (isProfileOwner) {
// Apps with the AppOps permission, profile owners, and apps with the privileged
// permission can access data usage for all apps in this user/profile.
@@ -157,6 +160,8 @@
*/
public static boolean isAccessibleToUser(int uid, int callerUid,
@NetworkStatsAccess.Level int accessLevel) {
+ final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+ final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier();
switch (accessLevel) {
case NetworkStatsAccess.Level.DEVICE:
// Device-level access - can access usage for any uid.
@@ -167,13 +172,13 @@
// anonymized uids
return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
|| uid == UID_TETHERING || uid == UID_ALL
- || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ || userId == callerUserId;
case NetworkStatsAccess.Level.USER:
// User-level access - can access usage for any app running in the same user, along
// with some special uids (system, removed, or tethering).
return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
|| uid == UID_TETHERING
- || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ || userId == callerUserId;
case NetworkStatsAccess.Level.DEFAULT:
default:
// Default access level - can only access one's own usage.
@@ -187,8 +192,8 @@
AppOpsManager appOps = (AppOpsManager) context.getSystemService(
Context.APP_OPS_SERVICE);
- final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS,
- callingUid, callingPackage);
+ final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS,
+ callingUid, callingPackage, null /* attributionTag */, null /* message */);
if (mode == AppOpsManager.MODE_DEFAULT) {
// The default behavior here is to check if PackageManager has given the app
// permission.
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
index 0d3b9ed..7935d28 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
@@ -30,7 +30,7 @@
import static android.net.TrafficStats.UID_REMOVED;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
+import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.os.Binder;
import android.service.NetworkStatsCollectionKeyProto;
@@ -40,21 +40,17 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
-import android.util.IntArray;
-import android.util.MathUtils;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
import android.util.Range;
-import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastDataInput;
import com.android.internal.util.FastDataOutput;
import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
-
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import libcore.io.IoUtils;
@@ -196,11 +192,11 @@
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel,
final int callerUid) {
- IntArray uids = new IntArray();
+ final ArrayList<Integer> uids = new ArrayList<>();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) {
- int j = uids.binarySearch(key.uid);
+ int j = Collections.binarySearch(uids, new Integer(key.uid));
if (j < 0) {
j = ~j;
@@ -208,7 +204,7 @@
}
}
}
- return uids.toArray();
+ return CollectionUtils.toIntArray(uids);
}
/**
@@ -225,7 +221,8 @@
// 180 days of history should be enough for anyone; if we end up needing
// more, we'll dynamically grow the history object.
- final int bucketEstimate = (int) MathUtils.constrain(((end - start) / mBucketDuration), 0,
+ final int bucketEstimate = (int) NetworkStatsUtils.constrain(
+ ((end - start) / mBucketDuration), 0,
(180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration);
final NetworkStatsHistory combined = new NetworkStatsHistory(
mBucketDuration, bucketEstimate, fields);
@@ -316,7 +313,7 @@
final long deltaTotal = combined.getTotalBytes() - beforeTotal;
if (deltaTotal != 0) {
- Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
+ Log.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
}
// Finally we can slice data as originally requested
@@ -489,11 +486,11 @@
private void write(DataOutput out) throws IOException {
// cluster key lists grouped by ident
- final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
+ final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = new HashMap<>();
for (Key key : mStats.keySet()) {
ArrayList<Key> keys = keysByIdent.get(key.ident);
if (keys == null) {
- keys = Lists.newArrayList();
+ keys = new ArrayList<>();
keysByIdent.put(key.ident, keys);
}
keys.add(key);
@@ -640,12 +637,12 @@
* {@link TrafficStats#UID_REMOVED}.
*/
public void removeUids(int[] uids) {
- final ArrayList<Key> knownKeys = Lists.newArrayList();
+ final ArrayList<Key> knownKeys = new ArrayList<>();
knownKeys.addAll(mStats.keySet());
// migrate all UID stats into special "removed" bucket
for (Key key : knownKeys) {
- if (ArrayUtils.contains(uids, key.uid)) {
+ if (CollectionUtils.contains(uids, key.uid)) {
// only migrate combined TAG_NONE history
if (key.tag == TAG_NONE) {
final NetworkStatsHistory uidHistory = mStats.get(key);
@@ -672,7 +669,7 @@
}
private ArrayList<Key> getSortedKeys() {
- final ArrayList<Key> keys = Lists.newArrayList();
+ final ArrayList<Key> keys = new ArrayList<>();
keys.addAll(mStats.keySet());
Collections.sort(keys);
return keys;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
index a875e1a..428bc6d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
@@ -28,8 +28,7 @@
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
-import static com.android.internal.util.ArrayUtils.total;
+import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
@@ -37,10 +36,11 @@
import android.os.Parcelable;
import android.service.NetworkStatsHistoryBucketProto;
import android.service.NetworkStatsHistoryProto;
-import android.util.MathUtils;
+import android.util.IndentingPrintWriter;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import libcore.util.EmptyArray;
@@ -174,7 +174,7 @@
txPackets = new long[bucketStart.length];
operations = new long[bucketStart.length];
bucketCount = bucketStart.length;
- totalBytes = total(rxBytes) + total(txBytes);
+ totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
break;
}
case VERSION_ADD_PACKETS:
@@ -189,7 +189,7 @@
txPackets = readVarLongArray(in);
operations = readVarLongArray(in);
bucketCount = bucketStart.length;
- totalBytes = total(rxBytes) + total(txBytes);
+ totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
break;
}
default: {
@@ -267,7 +267,7 @@
} else {
index -= 1;
}
- return MathUtils.constrain(index, 0, bucketCount - 1);
+ return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
}
/**
@@ -281,7 +281,7 @@
} else {
index += 1;
}
- return MathUtils.constrain(index, 0, bucketCount - 1);
+ return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
}
/**
@@ -349,6 +349,9 @@
// create any buckets needed by this range
ensureBuckets(start, end);
+ // Return fast if there is still no entry. This would typically happen when the start,
+ // end or duration are not valid values, e.g. start > end, negative duration value, etc.
+ if (bucketCount == 0) return;
// distribute data usage into buckets
long duration = end - start;
@@ -560,6 +563,9 @@
entry.txPackets = txPackets != null ? 0 : UNKNOWN;
entry.operations = operations != null ? 0 : UNKNOWN;
+ // Return fast if there is no entry.
+ if (bucketCount == 0) return entry;
+
final int startIndex = getIndexAfter(end);
for (int i = startIndex; i >= 0; i--) {
final long curStart = bucketStart[i];
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
index cb5a025..659ad06 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
@@ -35,7 +35,6 @@
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.wifi.WifiInfo.sanitizeSsid;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -47,17 +46,23 @@
import android.telephony.Annotation.NetworkType;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.ArraySet;
-import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* Predicate used to match {@link NetworkIdentity}, usually when collecting
@@ -110,29 +115,18 @@
*/
public static final int MATCH_CARRIER = 10;
+ // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL.
/** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "SUBSCRIBER_ID_MATCH_RULE_" }, value = {
- SUBSCRIBER_ID_MATCH_RULE_EXACT,
- SUBSCRIBER_ID_MATCH_RULE_ALL
- })
- public @interface SubscriberIdMatchRule{}
- /**
- * Value of the match rule of the subscriberId to match networks with specific subscriberId.
- */
- public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0;
- /**
- * Value of the match rule of the subscriberId to match networks with any subscriberId which
- * includes null and non-null.
- */
- public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1;
+ public static final String WIFI_NETWORKID_ALL = null;
/**
- * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that
+ * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that
* should be fixed), so it's not possible to want to match null vs
- * non-null. Therefore it's fine to use null as a sentinel for Network ID.
+ * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key.
+ *
+ * @hide
*/
- public static final String WIFI_NETWORKID_ALL = null;
+ public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL;
/**
* Include all network types when filtering. This is meant to merge in with the
@@ -219,13 +213,16 @@
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
@NetworkType int ratType, int metered) {
if (TextUtils.isEmpty(subscriberId)) {
- return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */,
+ null /* matchSubscriberIds */,
+ new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
- return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
+ return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId },
+ new String[0] /* matchWifiNetworkKeys */,
metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -241,7 +238,7 @@
/**
* Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
- * regardless of SSID.
+ * regardless of key of the wifi network.
*
* @hide
*/
@@ -261,31 +258,41 @@
/**
* Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
- * given SSID.
+ * given key of the wifi network.
*
+ * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+ * to know details about the key.
* @hide
*/
- public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
- Objects.requireNonNull(networkId);
+ public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) {
+ Objects.requireNonNull(wifiNetworkKey);
return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
new String[] { null } /* matchSubscriberIds */,
- networkId, METERED_ALL, ROAMING_ALL,
+ new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_ALL);
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL);
}
/**
- * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
- * and IMSI.
+ * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given
+ * key of the wifi network and IMSI.
*
- * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID.
+ * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless
+ * of key of the wifi network.
+ *
+ * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+ * to know details about the key.
+ * @param subscriberId the IMSI associated to this wifi network.
+ *
+ * @hide
*/
- public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
+ public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey,
@Nullable String subscriberId) {
return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
- networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ wifiNetworkKey != null
+ ? new String[] { wifiNetworkKey } : new String[0],
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -327,9 +334,11 @@
public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
Objects.requireNonNull(subscriberId);
return new NetworkTemplate(MATCH_CARRIER, subscriberId,
- new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL,
+ new String[] { subscriberId },
+ new String[0] /* matchWifiNetworkKeys */,
+ METERED_YES, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
private final int mMatchRule;
@@ -345,7 +354,8 @@
*/
private final String[] mMatchSubscriberIds;
- private final String mNetworkId;
+ @NonNull
+ private final String[] mMatchWifiNetworkKeys;
// Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
private final int mMetered;
@@ -361,14 +371,14 @@
// Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}.
private final int mOemManaged;
- private void checkValidSubscriberIdMatchRule() {
- switch (mMatchRule) {
+ private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) {
+ switch (matchRule) {
case MATCH_MOBILE:
case MATCH_CARRIER:
// MOBILE and CARRIER templates must always specify a subscriber ID.
- if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
- throw new IllegalArgumentException("Invalid SubscriberIdMatchRule"
- + "on match rule: " + getMatchRuleName(mMatchRule));
+ if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) {
+ throw new IllegalArgumentException("Invalid SubscriberIdMatchRule "
+ + "on match rule: " + getMatchRuleName(matchRule));
}
return;
default:
@@ -379,49 +389,53 @@
/** @hide */
// TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
@UnsupportedAppUsage
- public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
- this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
+ public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) {
+ this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey);
}
/** @hide */
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String networkId) {
+ String wifiNetworkKey) {
// Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
// to metered networks. It is now possible to match mobile with any meteredness, but
// in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
//constructor passes METERED_YES for these types.
- this(matchRule, subscriberId, matchSubscriberIds, networkId,
+ this(matchRule, subscriberId, matchSubscriberIds,
+ wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
(matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
: METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/** @hide */
// TODO: Remove it after updating all of the caller.
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String networkId, int metered, int roaming, int defaultNetwork, int subType,
+ String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int subType,
int oemManaged) {
- this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
- defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ this(matchRule, subscriberId, matchSubscriberIds,
+ wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
+ metered, roaming, defaultNetwork, subType, oemManaged,
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/** @hide */
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String networkId, int metered, int roaming, int defaultNetwork, int subType,
- int oemManaged, int subscriberIdMatchRule) {
+ String[] matchWifiNetworkKeys, int metered, int roaming,
+ int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) {
+ Objects.requireNonNull(matchWifiNetworkKeys);
mMatchRule = matchRule;
mSubscriberId = subscriberId;
// TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
// mSubscriberId is null
mMatchSubscriberIds = matchSubscriberIds;
- mNetworkId = networkId;
+ mMatchWifiNetworkKeys = matchWifiNetworkKeys;
mMetered = metered;
mRoaming = roaming;
mDefaultNetwork = defaultNetwork;
mSubType = subType;
mOemManaged = oemManaged;
mSubscriberIdMatchRule = subscriberIdMatchRule;
- checkValidSubscriberIdMatchRule();
+ checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule);
if (!isKnownMatchRule(matchRule)) {
throw new IllegalArgumentException("Unknown network template rule " + matchRule
+ " will not match any identity.");
@@ -432,7 +446,7 @@
mMatchRule = in.readInt();
mSubscriberId = in.readString();
mMatchSubscriberIds = in.createStringArray();
- mNetworkId = in.readString();
+ mMatchWifiNetworkKeys = in.createStringArray();
mMetered = in.readInt();
mRoaming = in.readInt();
mDefaultNetwork = in.readInt();
@@ -446,7 +460,7 @@
dest.writeInt(mMatchRule);
dest.writeString(mSubscriberId);
dest.writeStringArray(mMatchSubscriberIds);
- dest.writeString(mNetworkId);
+ dest.writeStringArray(mMatchWifiNetworkKeys);
dest.writeInt(mMetered);
dest.writeInt(mRoaming);
dest.writeInt(mDefaultNetwork);
@@ -472,9 +486,7 @@
builder.append(", matchSubscriberIds=").append(
Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
}
- if (mNetworkId != null) {
- builder.append(", networkId=").append(mNetworkId);
- }
+ builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys));
if (mMetered != METERED_ALL) {
builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
}
@@ -498,8 +510,8 @@
@Override
public int hashCode() {
- return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
- mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
+ return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys),
+ mMetered, mRoaming, mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
}
@Override
@@ -508,22 +520,22 @@
final NetworkTemplate other = (NetworkTemplate) obj;
return mMatchRule == other.mMatchRule
&& Objects.equals(mSubscriberId, other.mSubscriberId)
- && Objects.equals(mNetworkId, other.mNetworkId)
&& mMetered == other.mMetered
&& mRoaming == other.mRoaming
&& mDefaultNetwork == other.mDefaultNetwork
&& mSubType == other.mSubType
&& mOemManaged == other.mOemManaged
- && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
+ && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule
+ && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys);
}
return false;
}
- private String subscriberIdMatchRuleToString(int rule) {
+ private static String subscriberIdMatchRuleToString(int rule) {
switch (rule) {
- case SUBSCRIBER_ID_MATCH_RULE_EXACT:
+ case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT:
return "EXACT_MATCH";
- case SUBSCRIBER_ID_MATCH_RULE_ALL:
+ case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL:
return "ALL";
default:
return "Unknown rule " + rule;
@@ -542,35 +554,20 @@
}
/**
- * Check if the template can be persisted into disk.
- *
- * @hide
- */
- // TODO: Move to the NetworkPolicy.
- public boolean isPersistable() {
- switch (mMatchRule) {
- case MATCH_MOBILE_WILDCARD:
- case MATCH_WIFI_WILDCARD:
- return false;
- case MATCH_CARRIER:
- return mSubscriberId != null;
- case MATCH_WIFI:
- if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
- && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
- return false;
- }
- return true;
- default:
- return true;
- }
- }
-
- /**
* Get match rule of the template. See {@code MATCH_*}.
*/
@UnsupportedAppUsage
public int getMatchRule() {
- return mMatchRule;
+ // Wildcard rules are not exposed. For external callers, convert wildcard rules to
+ // exposed rules before returning.
+ switch (mMatchRule) {
+ case MATCH_MOBILE_WILDCARD:
+ return MATCH_MOBILE;
+ case MATCH_WIFI_WILDCARD:
+ return MATCH_WIFI;
+ default:
+ return mMatchRule;
+ }
}
/**
@@ -582,15 +579,35 @@
return mSubscriberId;
}
- public String getNetworkId() {
- return mNetworkId;
+ /**
+ * Get set of subscriber Ids of the template.
+ */
+ @NonNull
+ public Set<String> getSubscriberIds() {
+ return new ArraySet<>(Arrays.asList(mMatchSubscriberIds));
}
/**
- * Get Subscriber Id Match Rule of the template.
+ * Get Wifi Network Key of the template. See {@link WifiInfo#getCurrentNetworkKey()}.
*/
- public int getSubscriberIdMatchRule() {
- return mSubscriberIdMatchRule;
+ @Nullable
+ public String getWifiNetworkKey() {
+ return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) ? null : mMatchWifiNetworkKeys[0];
+ }
+
+ /**
+ * Get set of Wifi Network Keys of the template.
+ */
+ @Nullable
+ public Set<String> getWifiNetworkKeys() {
+ return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys));
+ }
+
+ /** @hide */
+ // TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}.
+ @Nullable
+ public String getNetworkId() {
+ return getWifiNetworkKey();
}
/**
@@ -602,6 +619,38 @@
}
/**
+ * Get roaming filter of the template.
+ */
+ @NetworkStats.Roaming
+ public int getRoaming() {
+ return mRoaming;
+ }
+
+ /**
+ * Get the default network status filter of the template.
+ */
+ @NetworkStats.DefaultNetwork
+ public int getDefaultNetworkStatus() {
+ return mDefaultNetwork;
+ }
+
+ /**
+ * Get the Radio Access Technology(RAT) type filter of the template.
+ */
+ public int getRatType() {
+ return mSubType;
+ }
+
+ /**
+ * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or
+ * {@code android.net.NetworkIdentity#OEM_*}.
+ */
+ @OemManaged
+ public int getOemManaged() {
+ return mOemManaged;
+ }
+
+ /**
* Test if given {@link NetworkIdentity} matches this template.
*
* @hide
@@ -674,29 +723,34 @@
* @hide
*/
public boolean matchesSubscriberId(@Nullable String subscriberId) {
- return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL
- || ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+ return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+ || CollectionUtils.contains(mMatchSubscriberIds, subscriberId);
}
/**
- * Check if network with matching SSID. Returns true when the SSID matches, or when
- * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}.
+ * Check if network matches key of the wifi network.
+ * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is
+ * empty.
+ *
+ * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+ * to know details about the key.
*/
- private boolean matchesWifiNetworkId(@Nullable String networkId) {
- return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL)
- || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
+ private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) {
+ Objects.requireNonNull(wifiNetworkKey);
+ return CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
+ || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey);
}
/**
- * Check if mobile network with matching IMSI.
+ * Check if mobile network matches IMSI.
*/
private boolean matchesMobile(NetworkIdentity ident) {
if (ident.mType == TYPE_WIMAX) {
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
- return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
- && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
+ return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds)
+ && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
}
}
@@ -786,7 +840,7 @@
switch (ident.mType) {
case TYPE_WIFI:
return matchesSubscriberId(ident.mSubscriberId)
- && matchesWifiNetworkId(ident.mNetworkId);
+ && matchesWifiNetworkKey(ident.mNetworkId);
default:
return false;
}
@@ -807,8 +861,8 @@
*/
private boolean matchesCarrier(NetworkIdentity ident) {
return ident.mSubscriberId != null
- && !ArrayUtils.isEmpty(mMatchSubscriberIds)
- && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
+ && !CollectionUtils.isEmpty(mMatchSubscriberIds)
+ && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
}
private boolean matchesMobileWildcard(NetworkIdentity ident) {
@@ -925,11 +979,13 @@
if (template.mSubscriberId == null) return template;
for (String[] merged : mergedList) {
- if (ArrayUtils.contains(merged, template.mSubscriberId)) {
+ if (CollectionUtils.contains(merged, template.mSubscriberId)) {
// Requested template subscriber is part of the merge group; return
// a template that matches all merged subscribers.
+ final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys;
return new NetworkTemplate(template.mMatchRule, merged[0], merged,
- template.mNetworkId);
+ CollectionUtils.isEmpty(matchWifiNetworkKeys)
+ ? null : matchWifiNetworkKeys[0]);
}
}
@@ -948,4 +1004,206 @@
return new NetworkTemplate[size];
}
};
+
+ /**
+ * Builder class for NetworkTemplate.
+ */
+ public static final class Builder {
+ private final int mMatchRule;
+ // Use a SortedSet to provide a deterministic order when fetching the first one.
+ @NonNull
+ private final SortedSet<String> mMatchSubscriberIds =
+ new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder()));
+ @NonNull
+ private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>();
+
+ // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
+ private int mMetered;
+ private int mRoaming;
+ private int mDefaultNetwork;
+ private int mRatType;
+
+ // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}.
+ private int mOemManaged;
+
+ /**
+ * Creates a new Builder with given match rule to construct NetworkTemplate objects.
+ *
+ * @param matchRule the match rule of the template, see {@code MATCH_*}.
+ */
+ public Builder(@TemplateMatchRule final int matchRule) {
+ assertRequestableMatchRule(matchRule);
+ // Initialize members with default values.
+ mMatchRule = matchRule;
+ mMetered = METERED_ALL;
+ mRoaming = ROAMING_ALL;
+ mDefaultNetwork = DEFAULT_NETWORK_ALL;
+ mRatType = NETWORK_TYPE_ALL;
+ mOemManaged = OEM_MANAGED_ALL;
+ }
+
+ /**
+ * Set the Subscriber Ids. Calling this function with an empty set represents
+ * the intention of matching any Subscriber Ids.
+ *
+ * @param subscriberIds the list of Subscriber Ids.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setSubscriberIds(@NonNull Set<String> subscriberIds) {
+ Objects.requireNonNull(subscriberIds);
+ mMatchSubscriberIds.clear();
+ mMatchSubscriberIds.addAll(subscriberIds);
+ return this;
+ }
+
+ /**
+ * Set the Wifi Network Keys. Calling this function with an empty set represents
+ * the intention of matching any Wifi Network Key.
+ *
+ * @param wifiNetworkKeys the list of Wifi Network Key,
+ * see {@link WifiInfo#getCurrentNetworkKey()}.
+ * Or an empty list to match all networks.
+ * Note that {@code getCurrentNetworkKey()} might get null key
+ * when wifi disconnects. However, the caller should never invoke
+ * this function with a null Wifi Network Key since such statistics
+ * never exists.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) {
+ Objects.requireNonNull(wifiNetworkKeys);
+ for (String key : wifiNetworkKeys) {
+ if (key == null) {
+ throw new IllegalArgumentException("Null is not a valid key");
+ }
+ }
+ mMatchWifiNetworkKeys.clear();
+ mMatchWifiNetworkKeys.addAll(wifiNetworkKeys);
+ return this;
+ }
+
+ /**
+ * Set the meteredness filter.
+ *
+ * @param metered the meteredness filter.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setMeteredness(@NetworkStats.Meteredness int metered) {
+ mMetered = metered;
+ return this;
+ }
+
+ /**
+ * Set the roaming filter.
+ *
+ * @param roaming the roaming filter.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setRoaming(@NetworkStats.Roaming int roaming) {
+ mRoaming = roaming;
+ return this;
+ }
+
+ /**
+ * Set the default network status filter.
+ *
+ * @param defaultNetwork the default network status filter.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) {
+ mDefaultNetwork = defaultNetwork;
+ return this;
+ }
+
+ /**
+ * Set the Radio Access Technology(RAT) type filter.
+ *
+ * @param ratType the Radio Access Technology(RAT) type filter. Use
+ * {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
+ * See {@code TelephonyManager.NETWORK_TYPE_*}.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setRatType(@NetworkType int ratType) {
+ // Input will be validated with the match rule when building the template.
+ mRatType = ratType;
+ return this;
+ }
+
+ /**
+ * Set the OEM managed filter.
+ *
+ * @param oemManaged the match rule to match different type of OEM managed network or
+ * unmanaged networks. See {@code OEM_MANAGED_*}.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setOemManaged(@OemManaged int oemManaged) {
+ mOemManaged = oemManaged;
+ return this;
+ }
+
+ /**
+ * Check whether the match rule is requestable.
+ *
+ * @param matchRule the target match rule to be checked.
+ */
+ private static void assertRequestableMatchRule(final int matchRule) {
+ if (!isKnownMatchRule(matchRule)
+ || matchRule == MATCH_PROXY
+ || matchRule == MATCH_MOBILE_WILDCARD
+ || matchRule == MATCH_WIFI_WILDCARD) {
+ throw new IllegalArgumentException("Invalid match rule: "
+ + getMatchRuleName(matchRule));
+ }
+ }
+
+ private void assertRequestableParameters() {
+ validateWifiNetworkKeys();
+ // TODO: Check all the input are legitimate.
+ }
+
+ private void validateWifiNetworkKeys() {
+ if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) {
+ throw new IllegalArgumentException("Trying to build non wifi match rule: "
+ + mMatchRule + " with wifi network keys");
+ }
+ }
+
+ /**
+ * For backward compatibility, deduce match rule to a wildcard match rule
+ * if the Subscriber Ids are empty.
+ */
+ private int getWildcardDeducedMatchRule() {
+ if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) {
+ return MATCH_MOBILE_WILDCARD;
+ } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty()
+ && mMatchWifiNetworkKeys.isEmpty()) {
+ return MATCH_WIFI_WILDCARD;
+ }
+ return mMatchRule;
+ }
+
+ /**
+ * Builds the instance of the NetworkTemplate.
+ *
+ * @return the built instance of NetworkTemplate.
+ */
+ @NonNull
+ public NetworkTemplate build() {
+ assertRequestableParameters();
+ final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty()
+ ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+ : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ return new NetworkTemplate(getWildcardDeducedMatchRule(),
+ mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(),
+ mMatchSubscriberIds.toArray(new String[0]),
+ mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming,
+ mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule);
+ }
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index fa65061..d8feb88 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -29,7 +29,6 @@
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.util.DataUnit;
import com.android.server.NetworkManagementSocketTagger;
@@ -59,19 +58,19 @@
*/
public final static int UNSUPPORTED = -1;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long KB_IN_BYTES = 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long TB_IN_BYTES = GB_IN_BYTES * 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long PB_IN_BYTES = TB_IN_BYTES * 1024;
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
index e6433db..bb123a3 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
@@ -24,19 +24,19 @@
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.INetd;
import android.net.NetworkStats;
import android.net.UnderlyingNetworkInfo;
-import android.net.util.NetdService;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
+import com.android.net.module.util.CollectionUtils;
import libcore.io.IoUtils;
@@ -70,7 +70,7 @@
private final boolean mUseBpfStats;
- private INetd mNetdService;
+ private final INetd mNetd;
/**
* Guards persistent data access in this class
@@ -158,12 +158,12 @@
NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces);
}
- public NetworkStatsFactory() {
- this(new File("/proc/"), true);
+ public NetworkStatsFactory(@NonNull INetd netd) {
+ this(new File("/proc/"), true, netd);
}
@VisibleForTesting
- public NetworkStatsFactory(File procRoot, boolean useBpfStats) {
+ public NetworkStatsFactory(File procRoot, boolean useBpfStats, @NonNull INetd netd) {
mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
@@ -172,6 +172,7 @@
mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
}
+ mNetd = netd;
}
public NetworkStats readBpfNetworkStatsDev() throws IOException {
@@ -298,10 +299,7 @@
// Ask netd to do a active map stats swap. When the binder call successfully returns,
// the system server should be able to safely read and clean the inactive map
// without race problem.
- if (mNetdService == null) {
- mNetdService = NetdService.getInstance();
- }
- mNetdService.trafficSwapActiveStatsMap();
+ mNetd.trafficSwapActiveStatsMap();
}
/**
@@ -434,7 +432,7 @@
entry.txBytes = reader.nextLong();
entry.txPackets = reader.nextLong();
- if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
+ if ((limitIfaces == null || CollectionUtils.contains(limitIfaces, entry.iface))
&& (limitUid == UID_ALL || limitUid == entry.uid)
&& (limitTag == TAG_ALL || limitTag == entry.tag)) {
stats.insertEntry(entry);
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
index 1a0866d..b57a4f9 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
@@ -18,8 +18,6 @@
import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES;
-import static com.android.internal.util.Preconditions.checkArgument;
-
import android.app.usage.NetworkStatsManager;
import android.net.DataUsageRequest;
import android.net.NetworkIdentitySet;
@@ -38,7 +36,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
-import android.util.Slog;
+import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -83,7 +81,7 @@
RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid,
accessLevel);
- if (LOGV) Slog.v(TAG, "Registering observer for " + request);
+ if (LOGV) Log.v(TAG, "Registering observer for " + request);
getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo));
return request;
}
@@ -116,7 +114,7 @@
if (mHandler == null) {
synchronized (this) {
if (mHandler == null) {
- if (LOGV) Slog.v(TAG, "Creating handler");
+ if (LOGV) Log.v(TAG, "Creating handler");
mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback);
}
}
@@ -172,15 +170,15 @@
RequestInfo requestInfo;
requestInfo = mDataUsageRequests.get(request.requestId);
if (requestInfo == null) {
- if (LOGV) Slog.v(TAG, "Trying to unregister unknown request " + request);
+ if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request);
return;
}
if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) {
- Slog.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
+ Log.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
return;
}
- if (LOGV) Slog.v(TAG, "Unregistering " + request);
+ if (LOGV) Log.v(TAG, "Unregistering " + request);
mDataUsageRequests.remove(request.requestId);
requestInfo.unlinkDeathRecipient();
requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
@@ -201,7 +199,7 @@
// Cap the minimum threshold to a safe default to avoid too many callbacks
long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes);
if (thresholdInBytes < request.thresholdInBytes) {
- Slog.w(TAG, "Threshold was too low for " + request
+ Log.w(TAG, "Threshold was too low for " + request
+ ". Overriding to a safer default of " + thresholdInBytes + " bytes");
}
return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(),
@@ -216,7 +214,10 @@
accessLevel);
} else {
// Safety check in case a new access level is added and we forgot to update this
- checkArgument(accessLevel >= NetworkStatsAccess.Level.DEVICESUMMARY);
+ if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
+ throw new IllegalArgumentException(
+ "accessLevel " + accessLevel + " is less than DEVICESUMMARY.");
+ }
return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid,
accessLevel);
}
@@ -255,8 +256,9 @@
@Override
public void binderDied() {
- if (LOGV) Slog.v(TAG, "RequestInfo binderDied("
- + mRequest + ", " + mBinder + ")");
+ if (LOGV) {
+ Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mBinder + ")");
+ }
mStatsObserver.unregister(mRequest, Process.SYSTEM_UID);
callCallback(NetworkStatsManager.CALLBACK_RELEASED);
}
@@ -299,13 +301,13 @@
msg.setData(bundle);
try {
if (LOGV) {
- Slog.v(TAG, "sending notification " + callbackTypeToName(callbackType)
+ Log.v(TAG, "sending notification " + callbackTypeToName(callbackType)
+ " for " + mRequest);
}
mMessenger.send(msg);
} catch (RemoteException e) {
// May occur naturally in the race of binder death.
- Slog.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
+ Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
}
}
@@ -341,7 +343,7 @@
protected boolean checkStats() {
long bytesSoFar = getTotalBytesForNetwork(mRequest.template);
if (LOGV) {
- Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+ Log.v(TAG, bytesSoFar + " bytes so far since notification for "
+ mRequest.template);
}
if (bytesSoFar > mRequest.thresholdInBytes) {
@@ -416,7 +418,7 @@
return history.getTotalBytes();
} catch (SecurityException e) {
if (LOGV) {
- Slog.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
+ Log.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
+ uid);
}
return 0;
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
index 5e27c77..c371f08 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
@@ -32,15 +32,12 @@
import android.os.Binder;
import android.os.DropBoxManager;
import android.service.NetworkStatsRecorderProto;
+import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
-
-import com.google.android.collect.Sets;
+import com.android.net.module.util.NetworkStatsUtils;
import libcore.io.IoUtils;
@@ -132,8 +129,8 @@
}
public void setPersistThreshold(long thresholdBytes) {
- if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
- mPersistThresholdBytes = MathUtils.constrain(
+ if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes);
+ mPersistThresholdBytes = NetworkStatsUtils.constrain(
thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
}
@@ -185,7 +182,7 @@
}
private NetworkStatsCollection loadLocked(long start, long end) {
- if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
+ if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie);
final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
try {
mRotator.readMatching(res, start, end);
@@ -207,7 +204,7 @@
*/
public void recordSnapshotLocked(NetworkStats snapshot,
Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
- final HashSet<String> unknownIfaces = Sets.newHashSet();
+ final HashSet<String> unknownIfaces = new HashSet<>();
// skip recording when snapshot missing
if (snapshot == null) return;
@@ -272,7 +269,7 @@
mLastSnapshot = snapshot;
if (LOGV && unknownIfaces.size() > 0) {
- Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
+ Log.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
}
}
@@ -296,7 +293,7 @@
public void forcePersistLocked(long currentTimeMillis) {
Objects.requireNonNull(mRotator, "missing FileRotator");
if (mPending.isDirty()) {
- if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
+ if (LOGD) Log.d(TAG, "forcePersistLocked() writing for " + mCookie);
try {
mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
mRotator.maybeRotate(currentTimeMillis);
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 2beca73..ef84ce0 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -25,7 +25,6 @@
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
-import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.IFACE_VT;
@@ -90,6 +89,7 @@
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.DataUsageRequest;
+import android.net.INetd;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
@@ -141,28 +141,29 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.BinderUtils;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
+import com.android.net.module.util.PermissionUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.Clock;
import java.time.ZoneOffset;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -410,10 +411,11 @@
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock =
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
+ final INetd netd = INetd.Stub.asInterface(
+ (IBinder) context.getSystemService(Context.NETD_SERVICE));
final NetworkStatsService service = new NetworkStatsService(context, networkManager,
alarmManager, wakeLock, getDefaultClock(),
- new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(),
+ new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(netd),
new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(),
new Dependencies());
service.registerLocalService();
@@ -646,7 +648,7 @@
try {
mNetworkManager.setGlobalAlert(mGlobalAlertBytes);
} catch (IllegalStateException e) {
- Slog.w(TAG, "problem registering for global alert: " + e);
+ Log.w(TAG, "problem registering for global alert: " + e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
@@ -655,8 +657,6 @@
@Override
public INetworkStatsSession openSession() {
- // NOTE: if callers want to get non-augmented data, they should go
- // through the public API
return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null);
}
@@ -766,7 +766,7 @@
return stats;
} catch (NullPointerException e) {
// TODO: Track down and fix the cause of this crash and remove this catch block.
- Slog.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
+ Log.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
throw e;
}
}
@@ -811,7 +811,7 @@
private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
return NetworkStatsAccess.checkAccessLevel(
- mContext, Binder.getCallingUid(), callingPackage);
+ mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
}
/**
@@ -823,7 +823,7 @@
SubscriptionPlan plan = null;
if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
&& mSettings.getAugmentEnabled()) {
- if (LOGD) Slog.d(TAG, "Resolving plan for " + template);
+ if (LOGD) Log.d(TAG, "Resolving plan for " + template);
final long token = Binder.clearCallingIdentity();
try {
plan = LocalServices.getService(NetworkPolicyManagerInternal.class)
@@ -831,7 +831,7 @@
} finally {
Binder.restoreCallingIdentity(token);
}
- if (LOGD) Slog.d(TAG, "Resolved to plan " + plan);
+ if (LOGD) Log.d(TAG, "Resolved to plan " + plan);
}
return plan;
}
@@ -876,8 +876,6 @@
private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
assertSystemReady();
- // NOTE: if callers want to get non-augmented data, they should go
- // through the public API
return internalGetSummaryForNetwork(template,
NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end,
NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
@@ -936,7 +934,7 @@
@Override
public String[] getMobileIfaces() {
// TODO (b/192758557): Remove debug log.
- if (ArrayUtils.contains(mMobileIfaces, null)) {
+ if (CollectionUtils.contains(mMobileIfaces, null)) {
throw new NullPointerException(
"null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
}
@@ -985,7 +983,7 @@
@NonNull NetworkStateSnapshot[] networkStates,
@Nullable String activeIface,
@NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) {
- checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final long token = Binder.clearCallingIdentity();
try {
@@ -1014,9 +1012,10 @@
private void advisePersistThreshold(long thresholdBytes) {
// clamp threshold into safe range
- mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
+ mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes,
+ 128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
if (LOGV) {
- Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
+ Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
+ mPersistThreshold);
}
@@ -1200,13 +1199,13 @@
// On background handler thread, and USER_REMOVED is protected
// broadcast.
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId == -1) return;
+ final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
+ if (userHandle == null) return;
synchronized (mStatsLock) {
mWakeLock.acquire();
try {
- removeUserLocked(userId);
+ removeUserLocked(userHandle);
} finally {
mWakeLock.release();
}
@@ -1231,7 +1230,7 @@
@Override
public void limitReached(String limitName, String iface) {
// only someone like NMS should be calling us
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
// kick off background poll to collect network stats unless there is already
@@ -1279,7 +1278,7 @@
private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks,
@NonNull NetworkStateSnapshot[] snapshots) {
if (!mSystemReady) return;
- if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()");
+ if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()");
// take one last stats snapshot before updating iface mapping. this
// isn't perfect, since the kernel may already be counting traffic from
@@ -1303,7 +1302,8 @@
final int displayTransport =
getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes());
final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport);
- final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork());
+ final boolean isDefault = CollectionUtils.contains(
+ mDefaultNetworks, snapshot.getNetwork());
final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
: getSubTypeForStateSnapshot(snapshot);
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -1386,7 +1386,7 @@
mMobileIfaces = mobileIfaces.toArray(new String[0]);
// TODO (b/192758557): Remove debug log.
- if (ArrayUtils.contains(mMobileIfaces, null)) {
+ if (CollectionUtils.contains(mMobileIfaces, null)) {
throw new NullPointerException(
"null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
}
@@ -1401,7 +1401,7 @@
if (spec instanceof TelephonyNetworkSpecifier) {
return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
} else {
- Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
+ Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
return INVALID_SUBSCRIPTION_ID;
}
}
@@ -1485,7 +1485,7 @@
try {
recordSnapshotLocked(currentTime);
} catch (IllegalStateException e) {
- Slog.w(TAG, "problem reading network stats: " + e);
+ Log.w(TAG, "problem reading network stats: " + e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
@@ -1510,7 +1510,7 @@
@GuardedBy("mStatsLock")
private void performPollLocked(int flags) {
if (!mSystemReady) return;
- if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
+ if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked");
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
@@ -1632,7 +1632,7 @@
*/
@GuardedBy("mStatsLock")
private void removeUidsLocked(int... uids) {
- if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
+ if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
// Perform one last poll before removing
performPollLocked(FLAG_PERSIST_ALL);
@@ -1650,20 +1650,20 @@
* Clean up {@link #mUidRecorder} after user is removed.
*/
@GuardedBy("mStatsLock")
- private void removeUserLocked(int userId) {
- if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
+ private void removeUserLocked(@NonNull UserHandle userHandle) {
+ if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle);
// Build list of UIDs that we should clean up
- int[] uids = new int[0];
+ final ArrayList<Integer> uids = new ArrayList<>();
final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
PackageManager.MATCH_ANY_USER
| PackageManager.MATCH_DISABLED_COMPONENTS);
for (ApplicationInfo app : apps) {
- final int uid = UserHandle.getUid(userId, app.uid);
- uids = ArrayUtils.appendInt(uids, uid);
+ final int uid = userHandle.getUid(app.uid);
+ uids.add(uid);
}
- removeUidsLocked(uids);
+ removeUidsLocked(CollectionUtils.toIntArray(uids));
}
private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal {
@@ -1706,7 +1706,7 @@
public void setStatsProviderWarningAndLimitAsync(
@NonNull String iface, long warning, long limit) {
if (LOGV) {
- Slog.v(TAG, "setStatsProviderWarningAndLimitAsync("
+ Log.v(TAG, "setStatsProviderWarningAndLimitAsync("
+ iface + "," + warning + "," + limit + ")");
}
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
@@ -1716,7 +1716,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
+ if (!PermissionUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
long duration = DateUtils.DAY_IN_MILLIS;
final HashSet<String> argSet = new HashSet<String>();
@@ -1777,15 +1777,15 @@
pw.println("Configs:");
pw.increaseIndent();
- pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
+ pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
pw.println();
pw.decreaseIndent();
pw.println("Active interfaces:");
pw.increaseIndent();
for (int i = 0; i < mActiveIfaces.size(); i++) {
- pw.printPair("iface", mActiveIfaces.keyAt(i));
- pw.printPair("ident", mActiveIfaces.valueAt(i));
+ pw.print("iface", mActiveIfaces.keyAt(i));
+ pw.print("ident", mActiveIfaces.valueAt(i));
pw.println();
}
pw.decreaseIndent();
@@ -1793,8 +1793,8 @@
pw.println("Active UID interfaces:");
pw.increaseIndent();
for (int i = 0; i < mActiveUidIfaces.size(); i++) {
- pw.printPair("iface", mActiveUidIfaces.keyAt(i));
- pw.printPair("ident", mActiveUidIfaces.valueAt(i));
+ pw.print("iface", mActiveUidIfaces.keyAt(i));
+ pw.print("ident", mActiveUidIfaces.valueAt(i));
pw.println();
}
pw.decreaseIndent();
@@ -1867,7 +1867,7 @@
@GuardedBy("mStatsLock")
private void dumpProtoLocked(FileDescriptor fd) {
- final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd));
// TODO Right now it writes all history. Should it limit to the "since-boot" log?
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 5646c75..93d0ae7 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -33,7 +33,7 @@
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.CollectionUtils;
+import com.android.net.module.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
@@ -99,18 +99,19 @@
// prevent binder call to telephony when querying RAT. Keep listener registration with empty
// IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported
// with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
- final List<Pair<Integer, String>> filteredNewSubs =
- CollectionUtils.mapNotNull(newSubs, subId -> {
- final String subscriberId = mTeleManager.getSubscriberId(subId);
- return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId);
- });
+ final List<Pair<Integer, String>> filteredNewSubs = new ArrayList<>();
+ for (final int subId : newSubs) {
+ final String subscriberId = mTeleManager.getSubscriberId(subId);
+ if (!TextUtils.isEmpty(subscriberId)) {
+ filteredNewSubs.add(new Pair(subId, subscriberId));
+ }
+ }
for (final Pair<Integer, String> sub : filteredNewSubs) {
// Fully match listener with subId and IMSI, since in some rare cases, IMSI might be
// suddenly change regardless of subId, such as switch IMSI feature in modem side.
// If that happens, register new listener with new IMSI and remove old one later.
- if (CollectionUtils.find(mRatListeners,
- it -> it.equalsKey(sub.first, sub.second)) != null) {
+ if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) {
continue;
}
@@ -126,8 +127,8 @@
for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
// If there is no subId and IMSI matched the listener, removes it.
- if (CollectionUtils.find(filteredNewSubs,
- it -> listener.equalsKey(it.first, it.second)) == null) {
+ if (!CollectionUtils.any(filteredNewSubs,
+ it -> listener.equalsKey(it.first, it.second))) {
handleRemoveRatTypeListener(listener);
}
}
@@ -148,9 +149,10 @@
* @return collapsed RatType for the given subscriberId
*/
public int getRatTypeForSubscriberId(@NonNull String subscriberId) {
- final RatTypeListener match = CollectionUtils.find(mRatListeners,
+ final int index = CollectionUtils.indexOf(mRatListeners,
it -> TextUtils.equals(subscriberId, it.mSubscriberId));
- return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType
+ : TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 36d9cf8..cc56a21 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -68,7 +68,7 @@
}
for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
- if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+ if (entry.getValue().equals(BluetoothUuid.CAP)) {
return entry.getKey();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 3347920..5e2f310 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -338,7 +338,7 @@
.getGroupUuidMapByDevice(cachedDevice.getDevice());
if (groupIdMap != null) {
for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
- if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+ if (entry.getValue().equals(BluetoothUuid.CAP)) {
cachedDevice.setGroupId(entry.getKey());
break;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 18c38c5..011ca0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -32,7 +32,6 @@
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -172,7 +171,7 @@
return bucket.getRxBytes() + bucket.getTxBytes();
}
Log.w(TAG, "Failed to get data usage, no entry data");
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.w(TAG, "Failed to get data usage, remote call failed");
}
return -1L;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
index 787dc55..42e7100 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
@@ -18,7 +18,6 @@
import android.app.usage.NetworkStats;
import android.content.Context;
-import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
@@ -54,7 +53,7 @@
.setTotalUsage(total);
mData.add(builder.build());
}
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.e(TAG, "Exception querying network detail.", e);
}
}
@@ -85,7 +84,7 @@
if (bucket != null) {
usage = bucket.getRxBytes() + bucket.getTxBytes();
}
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.e(TAG, "Exception querying network detail.", e);
}
data.add(new NetworkCycleData.Builder()
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
index ed093629..54d5c3d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
@@ -20,7 +20,6 @@
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.NetworkTemplate;
-import android.os.RemoteException;
import android.util.Log;
import androidx.loader.content.AsyncTaskLoader;
@@ -55,7 +54,7 @@
public NetworkStats loadInBackground() {
try {
return mNetworkStatsManager.querySummary(mNetworkTemplate, mStart, mEnd);
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.e(TAG, "Exception querying network detail.", e);
return null;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 268603f..200e902 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1348,7 +1348,6 @@
Settings.Global.CONNECTIVITY_CHANGE_DELAY,
Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
Settings.Global.CAPTIVE_PORTAL_SERVER,
- Settings.Global.NSD_ON,
Settings.Global.SET_INSTALL_LOCATION,
Settings.Global.DEFAULT_INSTALL_LOCATION,
Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index f145f50..63c874a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1115,10 +1115,6 @@
p.end(notificationToken);
dumpSetting(s, p,
- Settings.Global.NSD_ON,
- GlobalSettingsProto.NSD_ON);
-
- dumpSetting(s, p,
Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
GlobalSettingsProto.NR_NSA_TRACKING_SCREEN_OFF_MODE);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 883c4a1..10dafd9 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -394,7 +394,6 @@
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
Settings.Global.NOTIFICATION_FEEDBACK_ENABLED,
Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
- Settings.Global.NSD_ON,
Settings.Global.NTP_SERVER,
Settings.Global.NTP_TIMEOUT,
Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9de1c5e..8dc18c0 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -251,6 +251,8 @@
<uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" />
<!-- For handling silent audio recordings -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
+ <!-- For asking AudioManager audio information -->
+ <uses-permission android:name="android.permission.QUERY_AUDIO_STATE"/>
<!-- to read and change hvac values in a car -->
<uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 918635d..c88e95f 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -323,6 +323,46 @@
</FrameLayout>
</LinearLayout>
+ <LinearLayout
+ android:id="@+id/wifi_scan_notify_layout"
+ style="@style/InternetDialog.Network"
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:paddingBottom="4dp"
+ android:clickable="false"
+ android:focusable="false">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="56dp"
+ android:gravity="start|top"
+ android:orientation="horizontal"
+ android:paddingEnd="12dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="4dp">
+ <ImageView
+ android:src="@drawable/ic_info_outline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tint="?android:attr/textColorTertiary"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/wifi_scan_notify_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:clickable="true"/>
+ </LinearLayout>
+ </LinearLayout>
+
<FrameLayout
android:id="@+id/done_layout"
android:layout_width="67dp"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7aacb70..4ad4fa9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3033,4 +3033,6 @@
<string name="see_all_networks">See all</string>
<!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] -->
<string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string>
+ <!-- Message to describe "Wi-Fi scan always available feature" when Wi-Fi is off and Wi-Fi scanning is on. [CHAR LIMIT=NONE] -->
+ <string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. You can change this in Wi\u2011Fi scanning settings. <annotation id="link">Change</annotation></string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java
index d8e80fe..0d7551f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java
@@ -30,7 +30,7 @@
/**
* A span that turns the text wrapped by annotation tag into the clickable link text.
*/
-class AnnotationLinkSpan extends ClickableSpan {
+public class AnnotationLinkSpan extends ClickableSpan {
private final Optional<View.OnClickListener> mClickListener;
private AnnotationLinkSpan(View.OnClickListener listener) {
@@ -50,7 +50,7 @@
* @param linkInfos used to attach the click action into the corresponding span
* @return the text attached with the span
*/
- static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) {
+ public static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) {
final SpannableString msg = new SpannableString(text);
final Annotation[] spans =
msg.getSpans(/* queryStart= */ 0, msg.length(), Annotation.class);
@@ -78,12 +78,12 @@
/**
* Data class to store the annotation and the click action.
*/
- static class LinkInfo {
- static final String DEFAULT_ANNOTATION = "link";
+ public static class LinkInfo {
+ public static final String DEFAULT_ANNOTATION = "link";
private final Optional<String> mAnnotation;
private final Optional<View.OnClickListener> mListener;
- LinkInfo(@NonNull String annotation, View.OnClickListener listener) {
+ public LinkInfo(@NonNull String annotation, View.OnClickListener listener) {
mAnnotation = Optional.of(annotation);
mListener = Optional.ofNullable(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index dc54e1b..dae357e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -36,6 +36,7 @@
import android.telephony.TelephonyManager;
import android.text.Html;
import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -63,6 +64,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -110,6 +112,8 @@
private LinearLayout mTurnWifiOnLayout;
private LinearLayout mEthernetLayout;
private TextView mWifiToggleTitleText;
+ private LinearLayout mWifiScanNotifyLayout;
+ private TextView mWifiScanNotifyText;
private LinearLayout mSeeAllLayout;
private RecyclerView mWifiRecyclerView;
private ImageView mConnectedWifiIcon;
@@ -220,6 +224,8 @@
mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
+ mWifiScanNotifyLayout = mDialogView.requireViewById(R.id.wifi_scan_notify_layout);
+ mWifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text);
mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title);
@@ -313,8 +319,10 @@
showProgressBar();
final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
+ final boolean isWifiScanEnabled = mWifiManager.isScanAlwaysAvailable();
updateWifiToggle(isWifiEnabled, isDeviceLocked);
updateConnectedWifi(isWifiEnabled, isDeviceLocked);
+ updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked);
final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0)
? View.GONE : View.VISIBLE;
@@ -411,6 +419,24 @@
mContext.getColor(R.color.connected_network_primary_color));
}
+ @MainThread
+ private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled,
+ boolean isDeviceLocked) {
+ if (isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) {
+ mWifiScanNotifyLayout.setVisibility(View.GONE);
+ return;
+ }
+ if (TextUtils.isEmpty(mWifiScanNotifyText.getText())) {
+ final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo(
+ AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
+ v -> mInternetDialogController.launchWifiScanningSetting());
+ mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify(
+ getContext().getText(R.string.wifi_scan_notify_message), linkInfo));
+ mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ mWifiScanNotifyLayout.setVisibility(View.VISIBLE);
+ }
+
void onClickConnectedWifi() {
if (mConnectedWifiEntry == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index aaba5ef..276c0be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -103,6 +103,8 @@
private static final String TAG = "InternetDialogController";
private static final String ACTION_NETWORK_PROVIDER_SETTINGS =
"android.settings.NETWORK_PROVIDER_SETTINGS";
+ private static final String ACTION_WIFI_SCANNING_SETTINGS =
+ "android.settings.WIFI_SCANNING_SETTINGS";
private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
public static final int NO_CELL_DATA_TYPE_ICON = 0;
@@ -603,6 +605,13 @@
}
}
+ void launchWifiScanningSetting() {
+ mCallback.dismissDialog();
+ final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
+ }
+
void connectCarrierNetwork() {
final MergedCarrierEntry mergedCarrierEntry =
mAccessPointController.getMergedCarrierEntry();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index c42b64a..7cea430 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -19,6 +19,7 @@
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
+import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.filters.SmallTest;
@@ -73,6 +74,7 @@
private LinearLayout mConnectedWifi;
private RecyclerView mWifiList;
private LinearLayout mSeeAll;
+ private LinearLayout mWifiScanNotify;
@Before
public void setUp() {
@@ -104,6 +106,7 @@
mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
+ mWifiScanNotify = mDialogView.requireViewById(R.id.wifi_scan_notify_layout);
}
@After
@@ -264,6 +267,50 @@
}
@Test
+ public void updateDialog_wifiOn_hideWifiScanNotify() {
+ // The preconditions WiFi ON and Internet WiFi are already in setUp()
+
+ mInternetDialog.updateDialog();
+
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() {
+ when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
+
+ mInternetDialog.updateDialog();
+
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() {
+ when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
+ when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
+
+ mInternetDialog.updateDialog();
+
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() {
+ when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
+ when(mInternetDialogController.isDeviceLocked()).thenReturn(false);
+
+ mInternetDialog.updateDialog();
+
+ assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE);
+ TextView wifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text);
+ assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0);
+ assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull();
+ }
+
+ @Test
public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() {
mSeeAll.performClick();
diff --git a/services/Android.bp b/services/Android.bp
index e11b044..841edc7 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -221,19 +221,13 @@
},
dists: [
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system-server/api",
dest: "android-non-updatable.txt",
tag: ".api.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk"],
dir: "apistubs/android/system-server/api",
dest: "android-non-updatable-removed.txt",
tag: ".removed-api.txt",
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1dda14c..7a4f1de 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -154,6 +154,7 @@
"android.hardware.oemlock-V1.0-java",
"android.hardware.configstore-V1.1-java",
"android.hardware.contexthub-V1.0-java",
+ "android.hardware.ir-V1-java",
"android.hardware.rebootescrow-V1-java",
"android.hardware.soundtrigger-V2.3-java",
"android.hardware.power.stats-V1-java",
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 8860a81..c8b4f11 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -46,6 +46,7 @@
import android.bluetooth.IBluetoothManagerCallback;
import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
+import android.bluetooth.IBluetoothLeCallControl;
import android.content.ActivityNotFoundException;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
@@ -1328,11 +1329,15 @@
+ bluetoothProfile);
}
- if (bluetoothProfile != BluetoothProfile.HEADSET) {
+ Intent intent;
+ if (bluetoothProfile == BluetoothProfile.HEADSET) {
+ intent = new Intent(IBluetoothHeadset.class.getName());
+ } else if (bluetoothProfile== BluetoothProfile.LE_CALL_CONTROL) {
+ intent = new Intent(IBluetoothLeCallControl.class.getName());
+ } else {
return false;
}
- Intent intent = new Intent(IBluetoothHeadset.class.getName());
psc = new ProfileServiceConnections(intent);
if (!psc.bindService()) {
return false;
@@ -1850,6 +1855,10 @@
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
+ if (isBle == 0) {
+ persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
+ }
+
// Use service interface to get the exact state
try {
mBluetoothLock.readLock().lock();
@@ -1863,7 +1872,6 @@
} else {
Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
mBluetooth.onLeServiceUp(mContext.getAttributionSource());
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
}
break;
case BluetoothAdapter.STATE_BLE_TURNING_ON:
diff --git a/services/core/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
index 2ed6c77..c4e84a4 100644
--- a/services/core/java/com/android/server/ConsumerIrService.java
+++ b/services/core/java/com/android/server/ConsumerIrService.java
@@ -19,17 +19,19 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.IConsumerIrService;
+import android.hardware.ir.ConsumerIrFreqRange;
+import android.hardware.ir.IConsumerIr;
import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Slog;
-import java.lang.RuntimeException;
-
public class ConsumerIrService extends IConsumerIrService.Stub {
private static final String TAG = "ConsumerIrService";
private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
- private static native boolean halOpen();
+ private static native boolean getHidlHalService();
private static native int halTransmit(int carrierFrequency, int[] pattern);
private static native int[] halGetCarrierFrequencies();
@@ -37,6 +39,7 @@
private final PowerManager.WakeLock mWakeLock;
private final boolean mHasNativeHal;
private final Object mHalLock = new Object();
+ private IConsumerIr mAidlService = null;
ConsumerIrService(Context context) {
mContext = context;
@@ -45,7 +48,8 @@
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(true);
- mHasNativeHal = halOpen();
+ mHasNativeHal = getHalService();
+
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) {
if (!mHasNativeHal) {
throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!");
@@ -60,6 +64,19 @@
return mHasNativeHal;
}
+ private boolean getHalService() {
+ // Attempt to get the AIDL HAL service first
+ final String fqName = IConsumerIr.DESCRIPTOR + "/default";
+ mAidlService = IConsumerIr.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(fqName));
+ if (mAidlService != null) {
+ return true;
+ }
+
+ // Fall back to the HIDL HAL service
+ return getHidlHalService();
+ }
+
private void throwIfNoIrEmitter() {
if (!mHasNativeHal) {
throw new UnsupportedOperationException("IR emitter not available");
@@ -91,10 +108,18 @@
// Right now there is no mechanism to ensure fair queing of IR requests
synchronized (mHalLock) {
- int err = halTransmit(carrierFrequency, pattern);
+ if (mAidlService != null) {
+ try {
+ mAidlService.transmit(carrierFrequency, pattern);
+ } catch (RemoteException ignore) {
+ Slog.e(TAG, "Error transmitting frequency: " + carrierFrequency);
+ }
+ } else {
+ int err = halTransmit(carrierFrequency, pattern);
- if (err < 0) {
- Slog.e(TAG, "Error transmitting: " + err);
+ if (err < 0) {
+ Slog.e(TAG, "Error transmitting: " + err);
+ }
}
}
}
@@ -109,7 +134,24 @@
throwIfNoIrEmitter();
synchronized(mHalLock) {
- return halGetCarrierFrequencies();
+ if (mAidlService != null) {
+ try {
+ ConsumerIrFreqRange[] output = mAidlService.getCarrierFreqs();
+ if (output.length <= 0) {
+ Slog.e(TAG, "Error getting carrier frequencies.");
+ }
+ int[] result = new int[output.length * 2];
+ for (int i = 0; i < output.length; i++) {
+ result[i * 2] = output[i].minHz;
+ result[i * 2 + 1] = output[i].maxHz;
+ }
+ return result;
+ } catch (RemoteException ignore) {
+ return null;
+ }
+ } else {
+ return halGetCarrierFrequencies();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index ff480d1..794b149 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2872,29 +2872,18 @@
void setAttachingSchedGroupLSP(ProcessRecord app) {
int initialSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
final ProcessStateRecord state = app.mState;
- // If the process has been marked as foreground via Zygote.START_FLAG_USE_TOP_APP_PRIORITY,
- // then verify that the top priority is actually is applied.
+ // If the process has been marked as foreground, it is starting as the top app (with
+ // Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread.
if (state.hasForegroundActivities()) {
- String fallbackReason = null;
try {
// The priority must be the same as how does {@link #applyOomAdjLSP} set for
// {@link ProcessList.SCHED_GROUP_TOP_APP}. We don't check render thread because it
// is not ready when attaching.
- if (Process.getProcessGroup(app.getPid()) == THREAD_GROUP_TOP_APP) {
- app.getWindowProcessController().onTopProcChanged();
- setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
- } else {
- fallbackReason = "not expected top priority";
- }
- } catch (Exception e) {
- fallbackReason = e.toString();
- }
- if (fallbackReason == null) {
+ app.getWindowProcessController().onTopProcChanged();
+ setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
initialSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
- } else {
- // The real scheduling group will depend on if there is any component of the process
- // did something during attaching.
- Slog.w(TAG, "Fallback pre-set sched group to default: " + fallbackReason);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to pre-set top priority to " + app + " " + e);
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.md b/services/core/java/com/android/server/am/OomAdjuster.md
index eda511a..febc37b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.md
+++ b/services/core/java/com/android/server/am/OomAdjuster.md
@@ -59,6 +59,7 @@
* The next two factors are either it was the previous process with visible UI to the user, or it's a backup agent.
* And then it goes to the massive searches against the service connections and the content providers, each of the clients will be evaluated, and the Oom Adj score could get updated according to its clients' scores. However there are a bunch of service binding flags which could impact the result:
* Below table captures the results with given various service binding states:
+
| Conditon #1 | Condition #2 | Condition #3 | Condition #4 | Result |
|---------------------------------|------------------------------------------------------------|----------------------------------------------|---------------------------------------------------|--------------------------|
| `BIND_WAIVE_PRIORITY` not set | `BIND_ALLOW_OOM_MANAGEMENT` set | Shown UI && Not Home | | Use the app's own Adj |
@@ -83,6 +84,7 @@
| | | `BIND_NOT_FOREGROUND` not set | `BIND_IMPORTANT` is set | Sched = top app bound |
| | | | `BIND_IMPORTANT` is NOT set | Sched = default |
* Below table captures the results with given various content provider binding states:
+
| Conditon #1 | Condition #2 | Condition #3 | Result |
|---------------------------------|------------------------------------------------------------|----------------------------------------------|--------------------------|
| Client's process state >= cached| | | Client ProcState = empty |
@@ -95,6 +97,7 @@
| Still within retain time | Adj > previous app Adj | | adj = previuos app adj |
| | Process state > last activity | | ProcState = last activity|
* Some additional tweaks after the above ones:
+
| Conditon #1 | Condition #2 | Condition #3 | Result |
|---------------------------------|------------------------------------------------------------|----------------------------------------------|------------------------------------|
| Process state >= cached empty | Has client activities | | ProcState = cached activity client |
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index df5d60c..e00c8a3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3193,6 +3193,13 @@
}
}
+ private void enforceQueryStatePermission() {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.QUERY_AUDIO_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Missing QUERY_AUDIO_STATE permissions");
+ }
+ }
+
private void enforceQueryStateOrModifyRoutingPermission() {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
!= PackageManager.PERMISSION_GRANTED
@@ -4094,6 +4101,7 @@
/** Get last audible volume before stream was muted. */
public int getLastAudibleStreamVolume(int streamType) {
+ enforceQueryStatePermission();
ensureValidStreamType(streamType);
int device = getDeviceForStream(streamType);
return (mStreamStates[streamType].getIndex(device) + 5) / 10;
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b94cea4..55d0728 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -783,7 +783,7 @@
// the same time if we still have a public client.
while (clientIterator.hasNext()) {
PlayMonitorClient pmc = clientIterator.next();
- if (pcdb.equals(pmc.mDispatcherCb)) {
+ if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) {
pmc.release();
clientIterator.remove();
} else {
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index a56a8ea..72e900b 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -25,9 +25,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
-import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -77,6 +75,8 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -224,12 +224,13 @@
"Can't get TelephonyManager for subId %d", subId));
}
- subscriberId = tele.getSubscriberId();
- mNetworkTemplate = new NetworkTemplate(
- NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
- null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ subscriberId = Objects.requireNonNull(tele.getSubscriberId(),
+ "Null subscriber Id for subId " + subId);
+ mNetworkTemplate = new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
+ .setSubscriberIds(Set.of(subscriberId))
+ .setMeteredness(NetworkStats.METERED_YES)
+ .setDefaultNetworkStatus(NetworkStats.DEFAULT_NETWORK_NO)
+ .build();
mUsageCallback = new UsageCallback() {
@Override
public void onThresholdReached(int networkType, String subscriberId) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bf4ef48..2c666b5 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1446,7 +1446,10 @@
// parameters. If that fails, disconnect.
if (oldConfig != null
&& updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
- // Keep mNetworkAgent unchanged
+ // Update underlying networks if it is changed.
+ if (!Arrays.equals(oldConfig.underlyingNetworks, config.underlyingNetworks)) {
+ setUnderlyingNetworks(config.underlyingNetworks);
+ }
} else {
// Initialize the state for a new agent, while keeping the old one connected
// in case this new connection fails.
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 5de5fd3..2ca057d 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -255,6 +255,7 @@
import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import com.android.net.module.util.PermissionUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -2024,7 +2025,7 @@
for (final NetworkStateSnapshot snapshot : snapshots) {
mNetIdToSubId.put(snapshot.getNetwork().getNetId(), parseSubId(snapshot));
- // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
+ // Policies matched by NPMS only match by subscriber ID or by network ID. Thus subtype
// in the object created here is never used and its value doesn't matter, so use
// NETWORK_TYPE_UNKNOWN.
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -2388,7 +2389,8 @@
templateMeteredness = readIntAttribute(in, ATTR_TEMPLATE_METERED);
} else {
- subscriberIdMatchRule = NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ subscriberIdMatchRule =
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
if (templateType == MATCH_MOBILE) {
Log.d(TAG, "Update template match rule from mobile to carrier and"
+ " force to metered");
@@ -2451,12 +2453,20 @@
} else {
inferred = false;
}
- final NetworkTemplate template = new NetworkTemplate(templateType,
- subscriberId, new String[] { subscriberId },
- networkId, templateMeteredness, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
- NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
- if (template.isPersistable()) {
+ final NetworkTemplate.Builder builder =
+ new NetworkTemplate.Builder(templateType)
+ .setMeteredness(templateMeteredness);
+ if (subscriberIdMatchRule
+ == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT) {
+ final ArraySet<String> ids = new ArraySet<>();
+ ids.add(subscriberId);
+ builder.setSubscriberIds(ids);
+ }
+ if (networkId != null) {
+ builder.setWifiNetworkKeys(Set.of(networkId));
+ }
+ final NetworkTemplate template = builder.build();
+ if (NetworkPolicy.isTemplatePersistable(template)) {
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule,
warningBytes, limitBytes, lastWarningSnooze,
lastLimitSnooze, metered, inferred));
@@ -2605,35 +2615,39 @@
* into {@link WifiConfiguration}.
*/
private void upgradeWifiMeteredOverride() {
- final ArrayMap<String, Boolean> wifiNetworkIds = new ArrayMap<>();
+ final ArrayMap<String, Boolean> wifiNetworkKeys = new ArrayMap<>();
synchronized (mNetworkPoliciesSecondLock) {
for (int i = 0; i < mNetworkPolicy.size();) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
&& !policy.inferred) {
mNetworkPolicy.removeAt(i);
- wifiNetworkIds.put(policy.template.getNetworkId(), policy.metered);
+ final Set<String> keys = policy.template.getWifiNetworkKeys();
+ wifiNetworkKeys.put(keys.isEmpty() ? null : keys.iterator().next(),
+ policy.metered);
} else {
i++;
}
}
}
- if (wifiNetworkIds.isEmpty()) {
+ if (wifiNetworkKeys.isEmpty()) {
return;
}
final WifiManager wm = mContext.getSystemService(WifiManager.class);
final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
for (int i = 0; i < configs.size(); ++i) {
final WifiConfiguration config = configs.get(i);
- final String networkId = resolveNetworkId(config);
- final Boolean metered = wifiNetworkIds.get(networkId);
- if (metered != null) {
- Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
- config.meteredOverride = metered
- ? WifiConfiguration.METERED_OVERRIDE_METERED
- : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
- wm.updateNetwork(config);
+ for (String key : config.getAllPersistableNetworkKeys()) {
+ final Boolean metered = wifiNetworkKeys.get(key);
+ if (metered != null) {
+ Slog.d(TAG, "Found network " + key + "; upgrading metered hint");
+ config.meteredOverride = metered
+ ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ wm.updateNetwork(config);
+ break;
+ }
}
}
@@ -2663,7 +2677,7 @@
for (int i = 0; i < mNetworkPolicy.size(); i++) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
final NetworkTemplate template = policy.template;
- if (!template.isPersistable()) continue;
+ if (!NetworkPolicy.isTemplatePersistable(template)) continue;
out.startTag(null, TAG_NETWORK_POLICY);
writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
@@ -2671,11 +2685,13 @@
if (subscriberId != null) {
out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
}
- writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE,
- template.getSubscriberIdMatchRule());
- final String networkId = template.getNetworkId();
- if (networkId != null) {
- out.attribute(null, ATTR_NETWORK_ID, networkId);
+ final int subscriberIdMatchRule = template.getSubscriberIds().isEmpty()
+ ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+ : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE, subscriberIdMatchRule);
+ if (!template.getWifiNetworkKeys().isEmpty()) {
+ out.attribute(null, ATTR_NETWORK_ID,
+ template.getWifiNetworkKeys().iterator().next());
}
writeIntAttribute(out, ATTR_TEMPLATE_METERED,
template.getMeteredness());
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 4a913e4e..cecbeed 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -124,16 +124,10 @@
}
// Vendor mac permissions.
- // The filename has been renamed from nonplat_mac_permissions to
- // vendor_mac_permissions. Either of them should exist.
final File vendorMacPermission = new File(
Environment.getVendorDirectory(), "/etc/selinux/vendor_mac_permissions.xml");
if (vendorMacPermission.exists()) {
sMacPermissions.add(vendorMacPermission);
- } else {
- // For backward compatibility.
- sMacPermissions.add(new File(Environment.getVendorDirectory(),
- "/etc/selinux/nonplat_mac_permissions.xml"));
}
// ODM mac permissions (optional).
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 08a7215..97c168d 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -1255,9 +1255,7 @@
info.diskImagePath = ai.modulePath;
info.versionCode = ai.versionCode;
info.versionName = ai.versionName;
- info.hasBootClassPathJars = ai.hasBootClassPathJars;
- info.hasDex2OatBootClassPathJars = ai.hasDex2OatBootClassPathJars;
- info.hasSystemServerClassPathJars = ai.hasSystemServerClassPathJars;
+ info.hasClassPathJars = ai.hasClassPathJars;
return info;
}
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 46cb720..186b2b5 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -435,7 +435,8 @@
|| !pm.isGranted(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
pkg, UserHandle.of(userId))
|| !pm.isGranted(Manifest.permission.READ_PHONE_STATE, pkg,
- UserHandle.of(userId))) {
+ UserHandle.of(userId))
+ || pm.isSysComponentOrPersistentPlatformSignedPrivApp(pkg)) {
continue;
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 2f54f30..cb3d00a 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -89,6 +89,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
@@ -1173,6 +1174,91 @@
}
@Override
+ public List<String> getAvailableExtensionInterfaceNames(String inputId, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+ userId, "getAvailableExtensionInterfaceNames");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ITvInputService service = null;
+ synchronized (mLock) {
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+ TvInputState inputState = userState.inputMap.get(inputId);
+ if (inputState != null) {
+ ServiceState serviceState =
+ userState.serviceStateMap.get(inputState.info.getComponent());
+ if (serviceState != null && serviceState.isHardware
+ && serviceState.service != null) {
+ service = serviceState.service;
+ }
+ }
+ }
+ try {
+ if (service != null) {
+ List<String> interfaces = new ArrayList<>();
+ for (final String name : CollectionUtils.emptyIfNull(
+ service.getAvailableExtensionInterfaceNames())) {
+ String permission = service.getExtensionInterfacePermission(name);
+ if (permission == null
+ || mContext.checkPermission(permission, callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED) {
+ interfaces.add(name);
+ }
+ }
+ return interfaces;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in getAvailableExtensionInterfaceNames "
+ + "or getExtensionInterfacePermission", e);
+ }
+ return new ArrayList<>();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public IBinder getExtensionInterface(String inputId, String name, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+ userId, "getExtensionInterface");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ITvInputService service = null;
+ synchronized (mLock) {
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+ TvInputState inputState = userState.inputMap.get(inputId);
+ if (inputState != null) {
+ ServiceState serviceState =
+ userState.serviceStateMap.get(inputState.info.getComponent());
+ if (serviceState != null && serviceState.isHardware
+ && serviceState.service != null) {
+ service = serviceState.service;
+ }
+ }
+ }
+ try {
+ if (service != null) {
+ String permission = service.getExtensionInterfacePermission(name);
+ if (permission == null
+ || mContext.checkPermission(permission, callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return service.getExtensionInterface(name);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in getExtensionInterfacePermission "
+ + "or getExtensionInterface", e);
+ }
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId) {
if (mContext.checkCallingPermission(
android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS)
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index d0457b0..1108c77 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1498,11 +1498,15 @@
statusBarBottom);
}
- sTmpRect.set(windowFrames.mFrame);
- sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
- sTmpRect.top = windowFrames.mFrame.top; // Ignore top display cutout inset
- sTmpRect.bottom = statusBarBottom; // Use collapsed status bar size
- contentFrame.set(sTmpRect);
+ final InsetsState state = displayFrames.mInsetsState;
+ sTmpRect.set(displayFrames.mDisplayCutoutSafe);
+ // The status bar content can extend into regular display cutout insets but not
+ // waterfall insets.
+ sTmpRect.top = Math.max(state.getDisplayCutout().getWaterfallInsets().top, 0);
+
+ contentFrame.set(windowFrames.mFrame);
+ contentFrame.intersect(sTmpRect);
+ contentFrame.bottom = statusBarBottom; // Use collapsed status bar size
}
private int layoutNavigationBar(DisplayFrames displayFrames, Rect contentFrame) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index bd688a6..52da4b8 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2125,6 +2125,9 @@
final Task rootTask;
if (singleActivity) {
rootTask = task;
+
+ // Apply the last recents animation leash transform to the task entering PIP
+ rootTask.maybeApplyLastRecentsAnimationTransaction();
} else {
// In the case of multiple activities, we will create a new task for it and then
// move the PIP activity into the task. Note that we explicitly defer the task
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cae4f22..dca0bac 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2787,7 +2787,15 @@
if (inOutConfig.smallestScreenWidthDp
== Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
- if (WindowConfiguration.isFloating(windowingMode)) {
+ // When entering to or exiting from Pip, the PipTaskOrganizer will set the
+ // windowing mode of the activity in the task to WINDOWING_MODE_FULLSCREEN and
+ // temporarily set the bounds of the task to fullscreen size for transitioning.
+ // It will get the wrong value if the calculation is based on this temporary
+ // fullscreen bounds.
+ // We should just inherit the value from parent for this temporary state.
+ final boolean inPipTransition = windowingMode == WINDOWING_MODE_PINNED
+ && !mTmpFullBounds.isEmpty() && mTmpFullBounds.equals(parentBounds);
+ if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) {
// For floating tasks, calculate the smallest width from the bounds of the task
inOutConfig.smallestScreenWidthDp = (int) (
Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 2ca348b..63daa35 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -34,7 +34,7 @@
static sp<IConsumerIr> mHal;
-static jboolean halOpen(JNIEnv* /* env */, jobject /* obj */) {
+static jboolean getHidlHalService(JNIEnv * /* env */, jobject /* obj */) {
// TODO(b/31632518)
mHal = IConsumerIr::getService();
return mHal != nullptr;
@@ -84,9 +84,9 @@
}
static const JNINativeMethod method_table[] = {
- { "halOpen", "()Z", (void *)halOpen },
- { "halTransmit", "(I[I)I", (void *)halTransmit },
- { "halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
+ {"getHidlHalService", "()Z", (void *)getHidlHalService},
+ {"halTransmit", "(I[I)I", (void *)halTransmit},
+ {"halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
};
int register_android_server_ConsumerIrService(JNIEnv *env) {
diff --git a/services/proguard.flags b/services/proguard.flags
index 30dd6cf..5d01d3e 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -1,11 +1,21 @@
# TODO(b/196084106): Refine and optimize this configuration. Note that this
# configuration is only used when `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA=true`.
-keep,allowoptimization,allowaccessmodification class ** {
- *;
+ !synthetic *;
}
# Various classes subclassed in ethernet-service (avoid marking final).
-keep public class android.net.** { *; }
# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing).
--keep public class com.android.server.utils.Slogf { *; }
\ No newline at end of file
+-keep public class com.android.server.utils.Slogf { *; }
+
+# Allows making private and protected methods/fields public as part of
+# optimization. This enables inlining of trivial getter/setter methods.
+-allowaccessmodification
+
+# Disallow accessmodification for soundtrigger classes. Logging via reflective
+# public member traversal can cause infinite loops. See b/210901706.
+-keep,allowoptimization class com.android.server.soundtrigger_middleware.** {
+ !synthetic *;
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 70641c2..b811e28 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -129,6 +129,7 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
+import android.net.wifi.WifiInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.INetworkManagementService;
@@ -226,13 +227,13 @@
private static final long TEST_START = 1194220800000L;
private static final String TEST_IFACE = "test0";
- private static final String TEST_SSID = "AndroidAP";
+ private static final String TEST_WIFI_NETWORK_KEY = "TestWifiNetworkKey";
private static final String TEST_IMSI = "310210";
private static final int TEST_SUB_ID = 42;
private static final Network TEST_NETWORK = mock(Network.class, CALLS_REAL_METHODS);
- private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
+ private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_WIFI_NETWORK_KEY);
private static NetworkTemplate sTemplateCarrierMetered =
buildTemplateCarrierMetered(TEST_IMSI);
@@ -1986,9 +1987,8 @@
assertEquals("Unexpected template match rule in network policies",
NetworkTemplate.MATCH_CARRIER,
actualPolicy.template.getMatchRule());
- assertEquals("Unexpected subscriberId match rule in network policies",
- NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT,
- actualPolicy.template.getSubscriberIdMatchRule());
+ assertTrue("Unexpected subscriberIds size in network policies",
+ actualPolicy.template.getSubscriberIds().size() > 0);
assertEquals("Unexpected template meteredness in network policies",
METERED_YES, actualPolicy.template.getMeteredness());
}
@@ -2003,9 +2003,8 @@
assertEquals("Unexpected template match rule in network policies",
NetworkTemplate.MATCH_WIFI,
actualPolicy.template.getMatchRule());
- assertEquals("Unexpected subscriberId match rule in network policies",
- NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_ALL,
- actualPolicy.template.getSubscriberIdMatchRule());
+ assertEquals("Unexpected subscriberIds size in network policies",
+ actualPolicy.template.getSubscriberIds().size(), 0);
assertEquals("Unexpected template meteredness in network policies",
METERED_NO, actualPolicy.template.getMeteredness());
}
@@ -2098,10 +2097,13 @@
}
private static NetworkStateSnapshot buildWifi() {
+ WifiInfo mockWifiInfo = mock(WifiInfo.class);
+ when(mockWifiInfo.makeCopy(anyLong())).thenReturn(mockWifiInfo);
+ when(mockWifiInfo.getCurrentNetworkKey()).thenReturn(TEST_WIFI_NETWORK_KEY);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_WIFI).setSsid(TEST_SSID).build();
+ .addTransportType(TRANSPORT_WIFI).setTransportInfo(mockWifiInfo).build();
return new NetworkStateSnapshot(TEST_NETWORK, networkCapabilities, prop,
null /*subscriberId*/, TYPE_WIFI);
}
diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
index e2d62f8..6d9b3210 100644
--- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java
+++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
@@ -17,7 +17,6 @@
package com.google.android.mms.util;
-import android.app.ActivityManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -25,49 +24,15 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
-import android.os.Build;
import android.util.Log;
-import android.widget.Toast;
public final class SqliteWrapper {
private static final String TAG = "SqliteWrapper";
- private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
- = "unable to open database file";
private SqliteWrapper() {
// Forbidden being instantiated.
}
- // FIXME: It looks like outInfo.lowMemory does not work well as we expected.
- // after run command: adb shell fillup -p 100, outInfo.lowMemory is still false.
- private static boolean isLowMemory(Context context) {
- if (null == context) {
- return false;
- }
-
- ActivityManager am = (ActivityManager)
- context.getSystemService(Context.ACTIVITY_SERVICE);
- ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
- am.getMemoryInfo(outInfo);
-
- return outInfo.lowMemory;
- }
-
- // FIXME: need to optimize this method.
- private static boolean isLowMemory(SQLiteException e) {
- return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE);
- }
-
- @UnsupportedAppUsage
- public static void checkSQLiteException(Context context, SQLiteException e) {
- if (isLowMemory(e)) {
- Toast.makeText(context, com.android.internal.R.string.low_memory,
- Toast.LENGTH_SHORT).show();
- } else {
- throw e;
- }
- }
-
@UnsupportedAppUsage
public static Cursor query(Context context, ContentResolver resolver, Uri uri,
String[] projection, String selection, String[] selectionArgs, String sortOrder) {
@@ -75,21 +40,10 @@
return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when query: ", e);
- checkSQLiteException(context, e);
return null;
}
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static boolean requery(Context context, Cursor cursor) {
- try {
- return cursor.requery();
- } catch (SQLiteException e) {
- Log.e(TAG, "Catch a SQLiteException when requery: ", e);
- checkSQLiteException(context, e);
- return false;
- }
- }
@UnsupportedAppUsage
public static int update(Context context, ContentResolver resolver, Uri uri,
ContentValues values, String where, String[] selectionArgs) {
@@ -97,7 +51,6 @@
return resolver.update(uri, values, where, selectionArgs);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when update: ", e);
- checkSQLiteException(context, e);
return -1;
}
}
@@ -109,7 +62,6 @@
return resolver.delete(uri, where, selectionArgs);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when delete: ", e);
- checkSQLiteException(context, e);
return -1;
}
}
@@ -121,7 +73,6 @@
return resolver.insert(uri, values);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when insert: ", e);
- checkSQLiteException(context, e);
return null;
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 95b9fda..5851ee1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -964,6 +964,21 @@
= "carrier_use_ims_first_for_emergency_bool";
/**
+ * When {@code true}, the determination of whether to place a call as an emergency call will be
+ * based on the known {@link android.telephony.emergency.EmergencyNumber}s for the SIM on which
+ * the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers
+ * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789,
+ * it will not be treated as an emergency call in this case.
+ * When {@code false}, the determination is based on the emergency numbers from all device SIMs,
+ * regardless of which SIM the call is being placed on. If Sim A has the emergency numbers
+ * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789,
+ * the call will be dialed as an emergency number, but with an unspecified routing.
+ * @hide
+ */
+ public static final String KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL =
+ "use_only_dialed_sim_ecc_list_bool";
+
+ /**
* When IMS instant lettering is available for a carrier (see
* {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters
* which may not be contained in messages. Should be specified as a regular expression suitable
@@ -5339,6 +5354,7 @@
sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true);
+ sDefaults.putBoolean(KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL, false);
sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, "");
sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, "");
sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING, "");
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index e8633dd..947dc01 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -600,7 +600,7 @@
/** @hide */
public static int convertRssnrUnitFromTenDbToDB(int rssnr) {
- return rssnr / 10;
+ return (int) Math.floor((float) rssnr / 10);
}
/** @hide */
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 63a7acf..d6d6775 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -222,6 +222,11 @@
private boolean mAreUiccApplicationsEnabled = true;
/**
+ * The port index of the Uicc card.
+ */
+ private final int mPortIndex;
+
+ /**
* Public copy constructor.
* @hide
*/
@@ -274,6 +279,22 @@
int carrierId, int profileClass, int subType, @Nullable String groupOwner,
@Nullable UiccAccessRule[] carrierConfigAccessRules,
boolean areUiccApplicationsEnabled) {
+ this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
+ roaming, icon, mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString,
+ cardId, isOpportunistic, groupUUID, isGroupDisabled, carrierId, profileClass,
+ subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, 0);
+ }
+ /**
+ * @hide
+ */
+ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
+ CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
+ Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
+ @Nullable UiccAccessRule[] nativeAccessRules, String cardString, int cardId,
+ boolean isOpportunistic, @Nullable String groupUUID, boolean isGroupDisabled,
+ int carrierId, int profileClass, int subType, @Nullable String groupOwner,
+ @Nullable UiccAccessRule[] carrierConfigAccessRules,
+ boolean areUiccApplicationsEnabled, int portIndex) {
this.mId = id;
this.mIccId = iccId;
this.mSimSlotIndex = simSlotIndex;
@@ -300,8 +321,8 @@
this.mGroupOwner = groupOwner;
this.mCarrierConfigAccessRules = carrierConfigAccessRules;
this.mAreUiccApplicationsEnabled = areUiccApplicationsEnabled;
+ this.mPortIndex = portIndex;
}
-
/**
* @return the subscription ID.
*/
@@ -737,6 +758,14 @@
public int getCardId() {
return this.mCardId;
}
+ /**
+ * Returns the port index of the SIM card which contains the subscription.
+ *
+ * @return the portIndex
+ */
+ public int getPortIndex() {
+ return this.mPortIndex;
+ }
/**
* Set whether the subscription's group is disabled.
@@ -783,6 +812,7 @@
UiccAccessRule[] nativeAccessRules = source.createTypedArray(UiccAccessRule.CREATOR);
String cardString = source.readString();
int cardId = source.readInt();
+ int portId = source.readInt();
boolean isOpportunistic = source.readBoolean();
String groupUUID = source.readString();
boolean isGroupDisabled = source.readBoolean();
@@ -800,7 +830,7 @@
carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null,
mcc, mnc, countryIso, isEmbedded, nativeAccessRules, cardString, cardId,
isOpportunistic, groupUUID, isGroupDisabled, carrierid, profileClass, subType,
- groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled);
+ groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, portId);
info.setAssociatedPlmns(ehplmns, hplmns);
return info;
}
@@ -830,6 +860,7 @@
dest.writeTypedArray(mNativeAccessRules, flags);
dest.writeString(mCardString);
dest.writeInt(mCardId);
+ dest.writeInt(mPortIndex);
dest.writeBoolean(mIsOpportunistic);
dest.writeString(mGroupUUID == null ? null : mGroupUUID.toString());
dest.writeBoolean(mIsGroupDisabled);
@@ -876,6 +907,7 @@
+ " mnc=" + mMnc + " countryIso=" + mCountryIso + " isEmbedded=" + mIsEmbedded
+ " nativeAccessRules=" + Arrays.toString(mNativeAccessRules)
+ " cardString=" + cardStringToPrint + " cardId=" + mCardId
+ + " portIndex=" + mPortIndex
+ " isOpportunistic=" + mIsOpportunistic + " groupUUID=" + mGroupUUID
+ " isGroupDisabled=" + mIsGroupDisabled
+ " profileClass=" + mProfileClass
@@ -892,7 +924,7 @@
return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, mCountryIso, mCardString,
mCardId, mDisplayName, mCarrierName, mNativeAccessRules, mIsGroupDisabled,
- mCarrierId, mProfileClass, mGroupOwner, mAreUiccApplicationsEnabled);
+ mCarrierId, mProfileClass, mGroupOwner, mAreUiccApplicationsEnabled, mPortIndex);
}
@Override
@@ -925,6 +957,7 @@
&& Objects.equals(mCountryIso, toCompare.mCountryIso)
&& Objects.equals(mCardString, toCompare.mCardString)
&& Objects.equals(mCardId, toCompare.mCardId)
+ && mPortIndex == toCompare.mPortIndex
&& Objects.equals(mGroupOwner, toCompare.mGroupOwner)
&& TextUtils.equals(mDisplayName, toCompare.mDisplayName)
&& TextUtils.equals(mCarrierName, toCompare.mCarrierName)
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 30cb8ca..fd9247c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -132,6 +132,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -145,6 +147,7 @@
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+
/**
* Provides access to information about the telephony services on
* the device. Applications can use the methods in this class to
@@ -3941,8 +3944,8 @@
* <p>
* If the caller has carrier priviliges on any active subscription, then they have permission to
* get simple information like the card ID ({@link UiccCardInfo#getCardId()}), whether the card
- * is an eUICC ({@link UiccCardInfo#isEuicc()}), and the slot index where the card is inserted
- * ({@link UiccCardInfo#getSlotIndex()}).
+ * is an eUICC ({@link UiccCardInfo#isEuicc()}), and the physical slot index where the card is
+ * inserted ({@link UiccCardInfo#getPhysicalSlotIndex()}.
* <p>
* To get private information such as the EID ({@link UiccCardInfo#getEid()}) or ICCID
* ({@link UiccCardInfo#getIccId()}), the caller must have carrier priviliges on that specific
@@ -3986,7 +3989,7 @@
if (telephony == null) {
return null;
}
- return telephony.getUiccSlotsInfo();
+ return telephony.getUiccSlotsInfo(mContext.getOpPackageName());
} catch (RemoteException e) {
return null;
}
@@ -4019,8 +4022,13 @@
* size should be same as {@link #getUiccSlotsInfo()}.
* @return boolean Return true if the switch succeeds, false if the switch fails.
* @hide
+ * @deprecated {@link #setSimSlotMapping(Collection, Executor, Consumer)}
*/
+ // TODO: once integrating the HAL changes we can convert int[] to List<UiccSlotMapping> and
+ // converge API's in ITelephony.aidl and PhoneInterfaceManager
+
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean switchSlots(int[] physicalSlots) {
try {
@@ -4035,6 +4043,109 @@
}
/**
+ * @param slotMapping Logical to physical slot and port mapping.
+ * @return {@code true} if slotMapping is valid.
+ * @return {@code false} if slotMapping is invalid.
+ *
+ * slotMapping is invalid if there are different entries (physical slot + port) mapping to the
+ * same logical slot or if there are same {physical slot + port} mapping to the different
+ * logical slot
+ * @hide
+ */
+ private static boolean isSlotMappingValid(@NonNull Collection<UiccSlotMapping> slotMapping) {
+ // Grouping the collection by logicalSlotIndex, finding different entries mapping to the
+ // same logical slot
+ Map<Integer, List<UiccSlotMapping>> slotMappingInfo = slotMapping.stream().collect(
+ Collectors.groupingBy(UiccSlotMapping::getLogicalSlotIndex));
+ for (Map.Entry<Integer, List<UiccSlotMapping>> entry : slotMappingInfo.entrySet()) {
+ List<UiccSlotMapping> logicalSlotMap = entry.getValue();
+ if (logicalSlotMap.size() > 1) {
+ // duplicate logicalSlotIndex found
+ return false;
+ }
+ }
+
+ // Grouping the collection by physical slot and port, finding same entries mapping to the
+ // different logical slot
+ Map<List<Integer>, List<UiccSlotMapping>> slotMapInfos = slotMapping.stream().collect(
+ Collectors.groupingBy(
+ slot -> Arrays.asList(slot.getPhysicalSlotIndex(), slot.getPortIndex())));
+ for (Map.Entry<List<Integer>, List<UiccSlotMapping>> entry : slotMapInfos.entrySet()) {
+ List<UiccSlotMapping> portAndPhysicalSlotList = entry.getValue();
+ if (portAndPhysicalSlotList.size() > 1) {
+ // duplicate pair of portIndex and physicalSlotIndex found
+ return false;
+ }
+ }
+ return true;
+ }
+ /**
+ * Maps the logical slots to physical slots and ports. Mapping is specified from
+ * {@link UiccSlotMapping} which consist of both physical slot index and port index.
+ * Logical slot is the slot that is seen by modem. Physical slot is the actual physical slot.
+ * Port index is the index (enumerated value) for the associated port available on the SIM.
+ * Each physical slot can have multiple ports if multi-enabled profile(MEP) is supported.
+ *
+ * Example: no. of logical slots 1 and physical slots 2 do not support MEP, each physical slot
+ * has one port:
+ * The only logical slot (index 0) can be mapped to first physical slot (value 0), port(index
+ * 0) or
+ * second physical slot(value 1), port (index 0), while the other physical slot remains unmapped
+ * and inactive.
+ * slotMapping[0] = UiccSlotMapping{0 //logical slot, 0 //physical slot//, 0 //port//}
+ * slotMapping[0] = UiccSlotMapping{1 // logical slot, 1 //physical slot//, 0 //port//}
+ *
+ * Example no. of logical slots 2 and physical slots 2 supports MEP with 2 ports available:
+ * Each logical slot must be mapped to a port (physical slot and port combination).
+ * First logical slot (index 0) can be mapped to physical slot 1 and the second logical slot
+ * can be mapped to either port from physical slot 2.
+ *
+ * slotMapping[0] = UiccSlotMapping{0, 0, 0} and slotMapping[1] = UiccSlotMapping{1, 0, 0} or
+ * slotMapping[0] = UiccSlotMapping{0, 0, 0} and slotMapping[1] = UiccSlotMapping{1, 1, 1}
+ *
+ * or the other way around, the second logical slot(index 1) can be mapped to physical slot 1
+ * and the first logical slot can be mapped to either port from physical slot 2.
+ *
+ * slotMapping[1] = UiccSlotMapping{0, 0, 0} and slotMapping[0] = UiccSlotMapping{1, 0, 0} or
+ * slotMapping[1] = UiccSlotMapping{0, 0, 0} and slotMapping[0] = UiccSlotMapping{1, 1, 1}
+ *
+ * another possible mapping is each logical slot maps to each port of physical slot 2 and there
+ * is no active logical modem mapped to physical slot 1.
+ *
+ * slotMapping[0] = UiccSlotMapping{1, 0, 0} and slotMapping[1] = UiccSlotMapping{1, 1, 1} or
+ * slotMapping[0] = UiccSlotMapping{1, 1, 1} and slotMapping[1] = UiccSlotMapping{1, 0, 0}
+ *
+ * @param slotMapping Logical to physical slot and port mapping.
+ * @throws IllegalStateException if telephony service is null or slot mapping was sent when the
+ * radio in middle of a silent restart or other invalid states to handle the command
+ * @throws IllegalArgumentException if the caller passes in an invalid collection of
+ * UiccSlotMapping like duplicate data, etc
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setSimSlotMapping(@NonNull Collection<UiccSlotMapping> slotMapping) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ if (isSlotMappingValid(slotMapping)) {
+ boolean result = telephony.setSimSlotMapping(new ArrayList(slotMapping));
+ if (!result) {
+ throw new IllegalStateException("setSimSlotMapping has failed");
+ }
+ } else {
+ throw new IllegalArgumentException("Duplicate UiccSlotMapping data found");
+ }
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Get the mapping from logical slots to physical slots. The key of the map is the logical slot
* id and the value is the physical slots id mapped to this logical slot id.
*
@@ -4051,7 +4162,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- int[] slotMappingArray = telephony.getSlotsMapping();
+ int[] slotMappingArray = telephony.getSlotsMapping(mContext.getOpPackageName());
for (int i = 0; i < slotMappingArray.length; i++) {
slotMapping.put(i, slotMappingArray[i]);
}
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index b4389203..7dfe450 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -20,21 +20,27 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
* The UiccCardInfo represents information about a currently inserted UICC or embedded eUICC.
*/
public final class UiccCardInfo implements Parcelable {
-
private final boolean mIsEuicc;
private final int mCardId;
private final String mEid;
private final String mIccId;
- private final int mSlotIndex;
+ private final int mPhysicalSlotIndex;
private final boolean mIsRemovable;
+ private final boolean mIsMultipleEnabledProfilesSupported;
+ private final List<UiccPortInfo> mPortList;
+ private boolean mIccIdAccessRestricted = false;
- public static final @android.annotation.NonNull Creator<UiccCardInfo> CREATOR = new Creator<UiccCardInfo>() {
+ public static final @NonNull Creator<UiccCardInfo> CREATOR = new Creator<UiccCardInfo>() {
@Override
public UiccCardInfo createFromParcel(Parcel in) {
return new UiccCardInfo(in);
@@ -47,22 +53,29 @@
};
private UiccCardInfo(Parcel in) {
- mIsEuicc = in.readByte() != 0;
+ mIsEuicc = in.readBoolean();
mCardId = in.readInt();
- mEid = in.readString();
- mIccId = in.readString();
- mSlotIndex = in.readInt();
- mIsRemovable = in.readByte() != 0;
+ mEid = in.readString8();
+ mIccId = in.readString8();
+ mPhysicalSlotIndex = in.readInt();
+ mIsRemovable = in.readBoolean();
+ mIsMultipleEnabledProfilesSupported = in.readBoolean();
+ mPortList = new ArrayList<UiccPortInfo>();
+ in.readTypedList(mPortList, UiccPortInfo.CREATOR);
+ mIccIdAccessRestricted = in.readBoolean();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeByte((byte) (mIsEuicc ? 1 : 0));
+ dest.writeBoolean(mIsEuicc);
dest.writeInt(mCardId);
- dest.writeString(mEid);
- dest.writeString(mIccId);
- dest.writeInt(mSlotIndex);
- dest.writeByte((byte) (mIsRemovable ? 1 : 0));
+ dest.writeString8(mEid);
+ dest.writeString8(mIccId);
+ dest.writeInt(mPhysicalSlotIndex);
+ dest.writeBoolean(mIsRemovable);
+ dest.writeBoolean(mIsMultipleEnabledProfilesSupported);
+ dest.writeTypedList(mPortList, flags);
+ dest.writeBoolean(mIccIdAccessRestricted);
}
@Override
@@ -71,20 +84,34 @@
}
/**
+ * Construct a UiccCardInfo.
+ *
+ * @param isEuicc is a flag to check is eUICC or not
+ * @param cardId is unique ID used to identify a UiccCard.
+ * @param eid is unique eUICC Identifier
+ * @param physicalSlotIndex is unique index referring to a physical SIM slot.
+ * @param isRemovable is a flag to check is removable or embedded
+ * @param isMultipleEnabledProfilesSupported is a flag to check is MEP enabled or not
+ * @param portList has the information regarding port, ICCID and its active status
+ *
* @hide
*/
- public UiccCardInfo(boolean isEuicc, int cardId, String eid, String iccId, int slotIndex,
- boolean isRemovable) {
+ public UiccCardInfo(boolean isEuicc, int cardId, String eid, int physicalSlotIndex,
+ boolean isRemovable, boolean isMultipleEnabledProfilesSupported,
+ @NonNull List<UiccPortInfo> portList) {
this.mIsEuicc = isEuicc;
this.mCardId = cardId;
this.mEid = eid;
- this.mIccId = iccId;
- this.mSlotIndex = slotIndex;
+ this.mIccId = null;
+ this.mPhysicalSlotIndex = physicalSlotIndex;
this.mIsRemovable = isRemovable;
+ this.mIsMultipleEnabledProfilesSupported = isMultipleEnabledProfilesSupported;
+ this.mPortList = portList;
}
/**
* Return whether the UICC is an eUICC.
+ *
* @return true if the UICC is an eUICC.
*/
public boolean isEuicc() {
@@ -119,40 +146,83 @@
* <p>
* Note that this field may be omitted if the caller does not have the correct permissions
* (see {@link TelephonyManager#getUiccCardsInfo()}).
+ *
+ * @deprecated with support for MEP(multiple enabled profile), a SIM card can have more than one
+ * ICCID active at the same time.Instead use {@link UiccPortInfo#getIccId()} to retrieve ICCID.
+ * To find {@link UiccPortInfo} use {@link UiccCardInfo#getPorts()}
+ *
+ * @throws UnsupportedOperationException if the calling app's target SDK is T and beyond.
*/
@Nullable
+ @Deprecated
public String getIccId() {
- return mIccId;
+ if (mIccIdAccessRestricted) {
+ throw new UnsupportedOperationException("getIccId from UiccPortInfo");
+ }
+ //always return ICCID from first port.
+ return getPorts().stream().findFirst().get().getIccId();
}
/**
* Gets the slot index for the slot that the UICC is currently inserted in.
+ *
+ * @deprecated use {@link #getPhysicalSlotIndex()}
*/
+ @Deprecated
public int getSlotIndex() {
- return mSlotIndex;
+ return mPhysicalSlotIndex;
}
/**
- * Returns a copy of the UiccCardinfo with the EID and ICCID set to null. These values are
- * generally private and require carrier privileges to view.
- *
- * @hide
+ * Gets the physical slot index for the slot that the UICC is currently inserted in.
*/
- @NonNull
- public UiccCardInfo getUnprivileged() {
- return new UiccCardInfo(mIsEuicc, mCardId, null, null, mSlotIndex, mIsRemovable);
+ public int getPhysicalSlotIndex() {
+ return mPhysicalSlotIndex;
}
/**
* Return whether the UICC or eUICC is removable.
* <p>
* UICCs are generally removable, but eUICCs may be removable or built in to the device.
+ *
* @return true if the UICC or eUICC is removable
*/
public boolean isRemovable() {
return mIsRemovable;
}
+ /*
+ * Whether the UICC card supports multiple enable profile(MEP)
+ * UICCs are generally MEP disabled, there can be only one active profile on the physical
+ * sim card.
+ *
+ * @return {@code true} if the eUICC is supporting multiple enabled profile(MEP).
+ */
+ public boolean isMultipleEnabledProfilesSupported() {
+ return mIsMultipleEnabledProfilesSupported;
+ }
+
+ /**
+ * Get information regarding port, ICCID and its active status.
+ *
+ * @return Collection of {@link UiccPortInfo}
+ */
+ public @NonNull Collection<UiccPortInfo> getPorts() {
+ return Collections.unmodifiableList(mPortList);
+ }
+
+ /**
+ * if the flag is set to {@code true} the calling app is not allowed to access deprecated
+ * {@link #getIccId()}
+ * @param iccIdAccessRestricted is the flag to check if app is allowed to access ICCID
+ *
+ * @hide
+ */
+ public void setIccIdAccessRestricted(boolean iccIdAccessRestricted) {
+ this.mIccIdAccessRestricted = iccIdAccessRestricted;
+ }
+
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -167,13 +237,16 @@
&& (mCardId == that.mCardId)
&& (Objects.equals(mEid, that.mEid))
&& (Objects.equals(mIccId, that.mIccId))
- && (mSlotIndex == that.mSlotIndex)
- && (mIsRemovable == that.mIsRemovable));
+ && (mPhysicalSlotIndex == that.mPhysicalSlotIndex)
+ && (mIsRemovable == that.mIsRemovable)
+ && (mIsMultipleEnabledProfilesSupported == that.mIsMultipleEnabledProfilesSupported)
+ && (Objects.equals(mPortList, that.mPortList)));
}
@Override
public int hashCode() {
- return Objects.hash(mIsEuicc, mCardId, mEid, mIccId, mSlotIndex, mIsRemovable);
+ return Objects.hash(mIsEuicc, mCardId, mEid, mIccId, mPhysicalSlotIndex, mIsRemovable,
+ mIsMultipleEnabledProfilesSupported, mPortList);
}
@Override
@@ -185,11 +258,17 @@
+ ", mEid="
+ mEid
+ ", mIccId="
- + mIccId
- + ", mSlotIndex="
- + mSlotIndex
+ + SubscriptionInfo.givePrintableIccid(mIccId)
+ + ", mPhysicalSlotIndex="
+ + mPhysicalSlotIndex
+ ", mIsRemovable="
+ mIsRemovable
+ + ", mIsMultipleEnabledProfilesSupported="
+ + mIsMultipleEnabledProfilesSupported
+ + ", mPortList="
+ + mPortList
+ + ", mIccIdAccessRestricted="
+ + mIccIdAccessRestricted
+ ")";
}
-}
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/UiccPortInfo.aidl b/telephony/java/android/telephony/UiccPortInfo.aidl
new file mode 100644
index 0000000..7fff4ba
--- /dev/null
+++ b/telephony/java/android/telephony/UiccPortInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable UiccPortInfo;
diff --git a/telephony/java/android/telephony/UiccPortInfo.java b/telephony/java/android/telephony/UiccPortInfo.java
new file mode 100644
index 0000000..d1838c0
--- /dev/null
+++ b/telephony/java/android/telephony/UiccPortInfo.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * UiccPortInfo class represents information about a single port contained on {@link UiccCardInfo}.
+ * Per GSMA SGP.22 V3.0, a port is a logical entity to which an active UICC profile can be bound on
+ * a UICC card. If UICC supports 2 ports, then the port index is numbered 0,1.
+ * Each port index is unique within an UICC, but not necessarily unique across UICC’s.
+ * For UICC's does not support MEP(Multi-enabled profile), just return the default port index 0.
+ */
+public final class UiccPortInfo implements Parcelable{
+ private final String mIccId;
+ private final int mPortIndex;
+ private final int mLogicalSlotIndex;
+ private final boolean mIsActive;
+
+ /**
+ * A redacted String if caller does not have permission to read ICCID.
+ */
+ public static final String ICCID_REDACTED = "FFFFFFFFFFFFFFFFFFFF";
+
+ public static final @NonNull Creator<UiccPortInfo> CREATOR =
+ new Creator<UiccPortInfo>() {
+ @Override
+ public UiccPortInfo createFromParcel(Parcel in) {
+ return new UiccPortInfo(in);
+ }
+ @Override
+ public UiccPortInfo[] newArray(int size) {
+ return new UiccPortInfo[size];
+ }
+ };
+
+ private UiccPortInfo(Parcel in) {
+ mIccId = in.readString8();
+ mPortIndex = in.readInt();
+ mLogicalSlotIndex = in.readInt();
+ mIsActive = in.readBoolean();
+ }
+
+ @Override
+ public void writeToParcel(@Nullable Parcel dest, int flags) {
+ dest.writeString8(mIccId);
+ dest.writeInt(mPortIndex);
+ dest.writeInt(mLogicalSlotIndex);
+ dest.writeBoolean(mIsActive);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Construct a UiccPortInfo.
+ *
+ * @param iccId The ICCID of the profile.
+ * @param portIndex The port index is an enumeration of the ports available on the UICC.
+ * @param logicalSlotIndex is unique index referring to a logical SIM slot.
+ * @param isActive is flag to check if port was tied to a modem stack.
+ *
+ * @hide
+ */
+ public UiccPortInfo(String iccId, int portIndex, int logicalSlotIndex, boolean isActive) {
+ this.mIccId = iccId;
+ this.mPortIndex = portIndex;
+ this.mLogicalSlotIndex = logicalSlotIndex;
+ this.mIsActive = isActive;
+ }
+
+ /**
+ * Get the ICCID of the profile associated with this port.
+ * If this port is not {@link #isActive()}, returns {@code null}.
+ * If the caller does not have access to the ICCID for this port, it will be redacted and
+ * {@link #ICCID_REDACTED} will be returned.
+ */
+ public @Nullable String getIccId() {
+ return mIccId;
+ }
+
+ /**
+ * The port index is an enumeration of the ports available on the UICC.
+ * Example: if eUICC1 supports 2 ports, then the port index is numbered 0,1.
+ * Each port index is unique within an UICC, but not necessarily unique across UICC’s.
+ * For UICC's does not support MEP(Multi-enabled profile), just return the default port index 0.
+ */
+ @IntRange(from = 0)
+ public int getPortIndex() {
+ return mPortIndex;
+ }
+
+ /**
+ * @return {@code true} if port was tied to a modem stack.
+ */
+ public boolean isActive() {
+ return mIsActive;
+ }
+
+ /**
+ * Gets logical slot index for the slot that the UICC is currently attached.
+ * Logical slot index or ID: unique index referring to a logical SIM slot.
+ * Logical slot IDs start at 0 and go up depending on the number of supported active slots on
+ * a device.
+ * For example, a dual-SIM device typically has slot 0 and slot 1.
+ * If a device has multiple physical slots but only supports one active slot,
+ * it will have only the logical slot ID 0.
+ *
+ * @return the logical slot index for UICC port, if there is no logical slot index it returns
+ * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX}
+ */
+ @IntRange(from = 0)
+ public int getLogicalSlotIndex() {
+ return mLogicalSlotIndex;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+
+ UiccPortInfo that = (UiccPortInfo) obj;
+ return (Objects.equals(mIccId, that.mIccId))
+ && (mPortIndex == that.mPortIndex)
+ && (mLogicalSlotIndex == that.mLogicalSlotIndex)
+ && (mIsActive == that.mIsActive);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIccId, mPortIndex, mLogicalSlotIndex, mIsActive);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "UiccPortInfo (isActive="
+ + mIsActive
+ + ", iccId="
+ + SubscriptionInfo.givePrintableIccid(mIccId)
+ + ", portIndex="
+ + mPortIndex
+ + ", mLogicalSlotIndex="
+ + mLogicalSlotIndex
+ + ")";
+ }
+}
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index a0e949a..2b1c8c8 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -24,6 +24,10 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -64,8 +68,10 @@
private final int mLogicalSlotIdx;
private final boolean mIsExtendedApduSupported;
private final boolean mIsRemovable;
+ private final List<UiccPortInfo> mPortList;
+ private boolean mLogicalSlotAccessRestricted = false;
- public static final @android.annotation.NonNull Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() {
+ public static final @NonNull Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() {
@Override
public UiccSlotInfo createFromParcel(Parcel in) {
return new UiccSlotInfo(in);
@@ -78,24 +84,29 @@
};
private UiccSlotInfo(Parcel in) {
- mIsActive = in.readByte() != 0;
- mIsEuicc = in.readByte() != 0;
- mCardId = in.readString();
+ mIsActive = in.readBoolean();
+ mIsEuicc = in.readBoolean();
+ mCardId = in.readString8();
mCardStateInfo = in.readInt();
mLogicalSlotIdx = in.readInt();
- mIsExtendedApduSupported = in.readByte() != 0;
- mIsRemovable = in.readByte() != 0;
+ mIsExtendedApduSupported = in.readBoolean();
+ mIsRemovable = in.readBoolean();
+ mPortList = new ArrayList<UiccPortInfo>();
+ in.readTypedList(mPortList, UiccPortInfo.CREATOR);
+ mLogicalSlotAccessRestricted = in.readBoolean();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeByte((byte) (mIsActive ? 1 : 0));
- dest.writeByte((byte) (mIsEuicc ? 1 : 0));
- dest.writeString(mCardId);
+ dest.writeBoolean(mIsActive);
+ dest.writeBoolean(mIsEuicc);
+ dest.writeString8(mCardId);
dest.writeInt(mCardStateInfo);
dest.writeInt(mLogicalSlotIdx);
- dest.writeByte((byte) (mIsExtendedApduSupported ? 1 : 0));
- dest.writeByte((byte) (mIsRemovable ? 1 : 0));
+ dest.writeBoolean(mIsExtendedApduSupported);
+ dest.writeBoolean(mIsRemovable);
+ dest.writeTypedList(mPortList, flags);
+ dest.writeBoolean(mLogicalSlotAccessRestricted);
}
@Override
@@ -117,25 +128,42 @@
this.mLogicalSlotIdx = logicalSlotIdx;
this.mIsExtendedApduSupported = isExtendedApduSupported;
this.mIsRemovable = false;
+ this.mPortList = null;
}
/**
+ * Construct a UiccSlotInfo.
* @hide
*/
- public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId,
- @CardStateInfo int cardStateInfo, int logicalSlotIdx, boolean isExtendedApduSupported,
- boolean isRemovable) {
- this.mIsActive = isActive;
+ public UiccSlotInfo(boolean isEuicc, String cardId,
+ @CardStateInfo int cardStateInfo, boolean isExtendedApduSupported,
+ boolean isRemovable, @NonNull List<UiccPortInfo> portList) {
+ this.mIsActive = portList.get(0).isActive();
this.mIsEuicc = isEuicc;
this.mCardId = cardId;
this.mCardStateInfo = cardStateInfo;
- this.mLogicalSlotIdx = logicalSlotIdx;
+ this.mLogicalSlotIdx = portList.get(0).getLogicalSlotIndex();
this.mIsExtendedApduSupported = isExtendedApduSupported;
this.mIsRemovable = isRemovable;
+ this.mPortList = portList;
}
+ /**
+ * @deprecated There is no longer isActive state for each slot because ports belonging
+ * to the physical slot could have different states
+ * we instead use {@link UiccPortInfo#isActive()}
+ * To get UiccPortInfo use {@link UiccSlotInfo#getPorts()}
+ *
+ * @return {@code true} if status is active.
+ * @throws UnsupportedOperationException if the calling app's target SDK is T and beyond.
+ */
+ @Deprecated
public boolean getIsActive() {
- return mIsActive;
+ if (mLogicalSlotAccessRestricted) {
+ throw new UnsupportedOperationException("get port status from UiccPortInfo");
+ }
+ //always return status from first port.
+ return getPorts().stream().findFirst().get().isActive();
}
public boolean getIsEuicc() {
@@ -159,8 +187,21 @@
return mCardStateInfo;
}
+ /**
+ * @deprecated There is no longer getLogicalSlotIndex
+ * There is no longer getLogicalSlotIdx as each port belonging to this physical slot could have
+ * different logical slot index. Use {@link UiccPortInfo#getLogicalSlotIndex()} instead
+ *
+ * @throws UnsupportedOperationException if the calling app's target SDK is T and beyond.
+ */
+ @Deprecated
public int getLogicalSlotIdx() {
- return mLogicalSlotIdx;
+ if (mLogicalSlotAccessRestricted) {
+ throw new UnsupportedOperationException("get logical slot index from UiccPortInfo");
+ }
+ //always return logical slot index from first port.
+ //portList always have at least one element.
+ return getPorts().stream().findFirst().get().getLogicalSlotIndex();
}
/**
@@ -170,16 +211,37 @@
return mIsExtendedApduSupported;
}
- /**
+ /**
* Return whether the UICC slot is for a removable UICC.
* <p>
* UICCs are generally removable, but eUICCs may be removable or built in to the device.
+ *
* @return true if the slot is for removable UICCs
*/
public boolean isRemovable() {
return mIsRemovable;
}
+ /**
+ * Get Information regarding port, iccid and its active status.
+ *
+ * @return Collection of {@link UiccPortInfo}
+ */
+ public @NonNull Collection<UiccPortInfo> getPorts() {
+ return Collections.unmodifiableList(mPortList);
+ }
+
+ /**
+ * Set the flag to check compatibility of the calling app's target SDK is T and beyond.
+ *
+ * @param logicalSlotAccessRestricted is the flag to check compatibility.
+ *
+ * @hide
+ */
+ public void setLogicalSlotAccessRestricted(boolean logicalSlotAccessRestricted) {
+ this.mLogicalSlotAccessRestricted = logicalSlotAccessRestricted;
+ }
+
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
@@ -196,20 +258,14 @@
&& (mCardStateInfo == that.mCardStateInfo)
&& (mLogicalSlotIdx == that.mLogicalSlotIdx)
&& (mIsExtendedApduSupported == that.mIsExtendedApduSupported)
- && (mIsRemovable == that.mIsRemovable);
+ && (mIsRemovable == that.mIsRemovable)
+ && (Objects.equals(mPortList, that.mPortList));
}
@Override
public int hashCode() {
- int result = 1;
- result = 31 * result + (mIsActive ? 1 : 0);
- result = 31 * result + (mIsEuicc ? 1 : 0);
- result = 31 * result + Objects.hashCode(mCardId);
- result = 31 * result + mCardStateInfo;
- result = 31 * result + mLogicalSlotIdx;
- result = 31 * result + (mIsExtendedApduSupported ? 1 : 0);
- result = 31 * result + (mIsRemovable ? 1 : 0);
- return result;
+ return Objects.hash(mIsActive, mIsEuicc, mCardId, mCardStateInfo, mLogicalSlotIdx,
+ mIsExtendedApduSupported, mIsRemovable, mPortList);
}
@NonNull
@@ -229,6 +285,10 @@
+ mIsExtendedApduSupported
+ ", mIsRemovable="
+ mIsRemovable
+ + ", mPortList="
+ + mPortList
+ + ", mLogicalSlotAccessRestricted="
+ + mLogicalSlotAccessRestricted
+ ")";
}
}
diff --git a/telephony/java/android/telephony/UiccSlotMapping.aidl b/telephony/java/android/telephony/UiccSlotMapping.aidl
new file mode 100644
index 0000000..3b19499
--- /dev/null
+++ b/telephony/java/android/telephony/UiccSlotMapping.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable UiccSlotMapping;
diff --git a/telephony/java/android/telephony/UiccSlotMapping.java b/telephony/java/android/telephony/UiccSlotMapping.java
new file mode 100644
index 0000000..87e7acd
--- /dev/null
+++ b/telephony/java/android/telephony/UiccSlotMapping.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * <p>Provides information for a SIM slot mapping, which establishes a unique mapping between a
+ * logical SIM slot and a physical SIM slot and port index. A logical SIM slot represents a
+ * potentially active SIM slot, where a physical SIM slot and port index represent a hardware SIM
+ * slot and port (capable of having an active profile) which can be mapped to a logical sim slot.
+ * <p>It contains the following parameters:
+ * <ul>
+ * <li>Port index: unique index referring to a port belonging to the physical SIM slot.
+ * If the SIM does not support multiple enabled profiles, the port index is default index 0.</li>
+ * <li>Physical slot index: unique index referring to a physical SIM slot. Physical slot IDs start
+ * at 0 and go up depending on the number of physical slots on the device.
+ * This differs from the number of logical slots a device has, which corresponds to the number of
+ * active slots a device is capable of using. For example, a device which switches between dual-SIM
+ * and single-SIM mode may always have two physical slots, but in single-SIM mode it will have only
+ * one logical slot.</li>
+ * <li>Logical slot index: unique index referring to a logical SIM slot, Logical slot IDs start at 0
+ * and go up depending on the number of supported active slots on a device.
+ * For example, a dual-SIM device typically has slot 0 and slot 1. If a device has multiple physical
+ * slots but only supports one active slot, it will have only the logical slot ID 0</li>
+ * </ul>
+ *
+ * <p> This configurations tells a specific logical slot is mapped to a port from an actual physical
+ * sim slot @see <a href="https://developer.android.com/guide/topics/connectivity/telecom/telephony-ids">the Android Developer Site</a>
+ * for more information.
+ * @hide
+ */
+@SystemApi
+public final class UiccSlotMapping implements Parcelable {
+ private final int mPortIndex;
+ private final int mPhysicalSlotIndex;
+ private final int mLogicalSlotIndex;
+
+ public static final @NonNull Creator<UiccSlotMapping> CREATOR =
+ new Creator<UiccSlotMapping>() {
+ @Override
+ public UiccSlotMapping createFromParcel(Parcel in) {
+ return new UiccSlotMapping(in);
+ }
+
+ @Override
+ public UiccSlotMapping[] newArray(int size) {
+ return new UiccSlotMapping[size];
+ }
+ };
+
+ private UiccSlotMapping(Parcel in) {
+ mPortIndex = in.readInt();
+ mPhysicalSlotIndex = in.readInt();
+ mLogicalSlotIndex = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(@Nullable Parcel dest, int flags) {
+ dest.writeInt(mPortIndex);
+ dest.writeInt(mPhysicalSlotIndex);
+ dest.writeInt(mLogicalSlotIndex);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ *
+ * @param portIndex The port index is an enumeration of the ports available on the UICC.
+ * @param physicalSlotIndex is unique index referring to a physical SIM slot.
+ * @param logicalSlotIndex is unique index referring to a logical SIM slot.
+ *
+ * @hide
+ */
+ public UiccSlotMapping(int portIndex, int physicalSlotIndex, int logicalSlotIndex) {
+ this.mPortIndex = portIndex;
+ this.mPhysicalSlotIndex = physicalSlotIndex;
+ this.mLogicalSlotIndex = logicalSlotIndex;
+ }
+
+ /**
+ * Port index is the unique index referring to a port belonging to the physical SIM slot.
+ * If the SIM does not support multiple enabled profiles, the port index is default index 0.
+ *
+ * @return port index.
+ */
+ @IntRange(from = 0)
+ public int getPortIndex() {
+ return mPortIndex;
+ }
+
+ /**
+ * Gets the physical slot index for the slot that the UICC is currently inserted in.
+ *
+ * @return physical slot index which is the index of actual physical UICC slot.
+ */
+ @IntRange(from = 0)
+ public int getPhysicalSlotIndex() {
+ return mPhysicalSlotIndex;
+ }
+
+ /**
+ * Gets logical slot index for the slot that the UICC is currently attached.
+ * Logical slot index is the unique index referring to a logical slot(logical modem stack).
+ *
+ * @return logical slot index;
+ */
+ @IntRange(from = 0)
+ public int getLogicalSlotIndex() {
+ return mLogicalSlotIndex;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+
+ UiccSlotMapping that = (UiccSlotMapping) obj;
+ return (mPortIndex == that.mPortIndex)
+ && (mPhysicalSlotIndex == that.mPhysicalSlotIndex)
+ && (mLogicalSlotIndex == that.mLogicalSlotIndex);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPortIndex, mPhysicalSlotIndex, mLogicalSlotIndex);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "UiccSlotMapping (mPortIndex="
+ + mPortIndex
+ + ", mPhysicalSlotIndex="
+ + mPhysicalSlotIndex
+ + ", mLogicalSlotIndex="
+ + mLogicalSlotIndex
+ + ")";
+ }
+}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 1ef04be..d6dce25 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -328,8 +328,6 @@
@SystemApi
public static final String TYPE_XCAP_STRING = "xcap";
-
-
/**
* APN type for Virtual SIM service.
*
@@ -506,27 +504,21 @@
private final int mRoamingProtocol;
private final int mMtuV4;
private final int mMtuV6;
-
private final boolean mCarrierEnabled;
-
- private final int mNetworkTypeBitmask;
-
+ private final @TelephonyManager.NetworkTypeBitMask int mNetworkTypeBitmask;
+ private final @TelephonyManager.NetworkTypeBitMask long mLingeringNetworkTypeBitmask;
private final int mProfileId;
-
private final boolean mPersistent;
private final int mMaxConns;
private final int mWaitTime;
private final int mMaxConnsTime;
-
private final int mMvnoType;
private final String mMvnoMatchData;
-
private final int mApnSetId;
-
private boolean mPermanentFailed = false;
private final int mCarrierId;
-
private final int mSkip464Xlat;
+ private final boolean mAlwaysOn;
/**
* Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
@@ -843,20 +835,37 @@
}
/**
- * Returns a bitmask describing the Radio Technologies(Network Types) which this APN may use.
+ * Returns a bitmask describing the Radio Technologies (Network Types) which this APN may use.
*
* NetworkType bitmask is calculated from NETWORK_TYPE defined in {@link TelephonyManager}.
*
* Examples of Network Types include {@link TelephonyManager#NETWORK_TYPE_UNKNOWN},
* {@link TelephonyManager#NETWORK_TYPE_GPRS}, {@link TelephonyManager#NETWORK_TYPE_EDGE}.
*
- * @return a bitmask describing the Radio Technologies(Network Types)
+ * @return a bitmask describing the Radio Technologies (Network Types) or 0 if it is undefined.
*/
public int getNetworkTypeBitmask() {
return mNetworkTypeBitmask;
}
/**
+ * Returns a bitmask describing the Radio Technologies (Network Types) that should not be torn
+ * down if it exists or brought up if it already exists for this APN.
+ *
+ * NetworkType bitmask is calculated from NETWORK_TYPE defined in {@link TelephonyManager}.
+ *
+ * Examples of Network Types include {@link TelephonyManager#NETWORK_TYPE_UNKNOWN},
+ * {@link TelephonyManager#NETWORK_TYPE_GPRS}, {@link TelephonyManager#NETWORK_TYPE_EDGE}.
+ *
+ * @return a bitmask describing the Radio Technologies (Network Types) that should linger
+ * or 0 if it is undefined.
+ * @hide
+ */
+ public @TelephonyManager.NetworkTypeBitMask long getLingeringNetworkTypeBitmask() {
+ return mLingeringNetworkTypeBitmask;
+ }
+
+ /**
* Returns the MVNO match type for this APN.
*
* @see Builder#setMvnoType(int)
@@ -888,6 +897,18 @@
return mSkip464Xlat;
}
+ /**
+ * Returns whether User Plane resources have to be activated during every transition from
+ * CM-IDLE mode to CM-CONNECTED state for this APN
+ * See 3GPP TS 23.501 section 5.6.13
+ *
+ * @return True if the PDU session for this APN should always be on and false otherwise
+ * @hide
+ */
+ public boolean isAlwaysOn() {
+ return mAlwaysOn;
+ }
+
private ApnSetting(Builder builder) {
this.mEntryName = builder.mEntryName;
this.mApnName = builder.mApnName;
@@ -912,6 +933,7 @@
this.mMtuV6 = builder.mMtuV6;
this.mCarrierEnabled = builder.mCarrierEnabled;
this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
+ this.mLingeringNetworkTypeBitmask = builder.mLingeringNetworkTypeBitmask;
this.mProfileId = builder.mProfileId;
this.mPersistent = builder.mModemCognitive;
this.mMaxConns = builder.mMaxConns;
@@ -922,6 +944,7 @@
this.mApnSetId = builder.mApnSetId;
this.mCarrierId = builder.mCarrierId;
this.mSkip464Xlat = builder.mSkip464Xlat;
+ this.mAlwaysOn = builder.mAlwaysOn;
}
/**
@@ -938,6 +961,10 @@
networkTypeBitmask =
ServiceState.convertBearerBitmaskToNetworkTypeBitmask(bearerBitmask);
}
+ int mtuV4 = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU_V4));
+ if (mtuV4 == -1) {
+ mtuV4 = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU));
+ }
return new Builder()
.setId(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)))
@@ -972,6 +999,8 @@
.setCarrierEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
Telephony.Carriers.CARRIER_ENABLED)) == 1)
.setNetworkTypeBitmask(networkTypeBitmask)
+ .setLingeringNetworkTypeBitmask(cursor.getInt(cursor.getColumnIndexOrThrow(
+ Carriers.LINGERING_NETWORK_TYPE_BITMASK)))
.setProfileId(cursor.getInt(
cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)))
.setModemCognitive(cursor.getInt(cursor.getColumnIndexOrThrow(
@@ -982,8 +1011,8 @@
cursor.getColumnIndexOrThrow(Telephony.Carriers.WAIT_TIME_RETRY)))
.setMaxConnsTime(cursor.getInt(cursor.getColumnIndexOrThrow(
Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS)))
- .setMtuV4(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)))
- .setMtuV6(UNSET_MTU) // TODO: Add corresponding support in telephony provider
+ .setMtuV4(mtuV4)
+ .setMtuV6(cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU_V6)))
.setMvnoType(getMvnoTypeIntFromString(
cursor.getString(cursor.getColumnIndexOrThrow(
Telephony.Carriers.MVNO_TYPE))))
@@ -994,6 +1023,7 @@
.setCarrierId(cursor.getInt(
cursor.getColumnIndexOrThrow(Telephony.Carriers.CARRIER_ID)))
.setSkip464Xlat(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.SKIP_464XLAT)))
+ .setAlwaysOn(cursor.getInt(cursor.getColumnIndexOrThrow(Carriers.ALWAYS_ON)) == 1)
.buildWithoutCheck();
}
@@ -1019,6 +1049,7 @@
.setRoamingProtocol(apn.mRoamingProtocol)
.setCarrierEnabled(apn.mCarrierEnabled)
.setNetworkTypeBitmask(apn.mNetworkTypeBitmask)
+ .setLingeringNetworkTypeBitmask(apn.mLingeringNetworkTypeBitmask)
.setProfileId(apn.mProfileId)
.setModemCognitive(apn.mPersistent)
.setMaxConns(apn.mMaxConns)
@@ -1031,6 +1062,7 @@
.setApnSetId(apn.mApnSetId)
.setCarrierId(apn.mCarrierId)
.setSkip464Xlat(apn.mSkip464Xlat)
+ .setAlwaysOn(apn.mAlwaysOn)
.buildWithoutCheck();
}
@@ -1069,9 +1101,11 @@
sb.append(", ").append(mMvnoMatchData);
sb.append(", ").append(mPermanentFailed);
sb.append(", ").append(mNetworkTypeBitmask);
+ sb.append(", ").append(mLingeringNetworkTypeBitmask);
sb.append(", ").append(mApnSetId);
sb.append(", ").append(mCarrierId);
sb.append(", ").append(mSkip464Xlat);
+ sb.append(", ").append(mAlwaysOn);
return sb.toString();
}
@@ -1136,8 +1170,9 @@
return Objects.hash(mApnName, mProxyAddress, mProxyPort, mMmsc, mMmsProxyAddress,
mMmsProxyPort, mUser, mPassword, mAuthType, mApnTypeBitmask, mId, mOperatorNumeric,
mProtocol, mRoamingProtocol, mMtuV4, mMtuV6, mCarrierEnabled, mNetworkTypeBitmask,
- mProfileId, mPersistent, mMaxConns, mWaitTime, mMaxConnsTime, mMvnoType,
- mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat);
+ mLingeringNetworkTypeBitmask, mProfileId, mPersistent, mMaxConns, mWaitTime,
+ mMaxConnsTime, mMvnoType, mMvnoMatchData, mApnSetId, mCarrierId, mSkip464Xlat,
+ mAlwaysOn);
}
@Override
@@ -1174,9 +1209,11 @@
&& Objects.equals(mMvnoType, other.mMvnoType)
&& Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
&& Objects.equals(mNetworkTypeBitmask, other.mNetworkTypeBitmask)
+ && Objects.equals(mLingeringNetworkTypeBitmask, other.mLingeringNetworkTypeBitmask)
&& Objects.equals(mApnSetId, other.mApnSetId)
&& Objects.equals(mCarrierId, other.mCarrierId)
- && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+ && Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
+ && Objects.equals(mAlwaysOn, other.mAlwaysOn);
}
/**
@@ -1210,6 +1247,7 @@
&& Objects.equals(mPassword, other.mPassword)
&& Objects.equals(mAuthType, other.mAuthType)
&& Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
+ && Objects.equals(mLingeringNetworkTypeBitmask, other.mLingeringNetworkTypeBitmask)
&& (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
&& (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
&& Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
@@ -1224,7 +1262,8 @@
&& Objects.equals(mMvnoMatchData, other.mMvnoMatchData)
&& Objects.equals(mApnSetId, other.mApnSetId)
&& Objects.equals(mCarrierId, other.mCarrierId)
- && Objects.equals(mSkip464Xlat, other.mSkip464Xlat);
+ && Objects.equals(mSkip464Xlat, other.mSkip464Xlat)
+ && Objects.equals(mAlwaysOn, other.mAlwaysOn);
}
/**
@@ -1304,9 +1343,13 @@
apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
apnValue.put(Telephony.Carriers.MVNO_TYPE, getMvnoTypeStringFromInt(mMvnoType));
apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
+ apnValue.put(Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK,
+ mLingeringNetworkTypeBitmask);
+ apnValue.put(Telephony.Carriers.MTU_V4, mMtuV4);
+ apnValue.put(Telephony.Carriers.MTU_V6, mMtuV6);
apnValue.put(Telephony.Carriers.CARRIER_ID, mCarrierId);
apnValue.put(Telephony.Carriers.SKIP_464XLAT, mSkip464Xlat);
-
+ apnValue.put(Telephony.Carriers.ALWAYS_ON, mAlwaysOn);
return apnValue;
}
@@ -1510,6 +1553,31 @@
return ServiceState.bitmaskHasTech(mNetworkTypeBitmask, networkType);
}
+ /**
+ * Check if this APN setting can support the given lingering network
+ *
+ * @param networkType The lingering network type
+ * @return {@code true} if this APN setting can support the given lingering network.
+ *
+ * @hide
+ */
+ public boolean canSupportLingeringNetworkType(@NetworkType int networkType) {
+ if (networkType == 0) {
+ return canSupportNetworkType(networkType);
+ }
+ // Do a special checking for GSM. In reality, GSM is a voice only network type and can never
+ // be used for data. We allow it here because in some DSDS corner cases, on the non-DDS
+ // sub, modem reports data rat unknown. In that case if voice is GSM and this APN supports
+ // GPRS or EDGE, this APN setting should be selected.
+ if (networkType == TelephonyManager.NETWORK_TYPE_GSM
+ && (mLingeringNetworkTypeBitmask & (TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
+ | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE)) != 0) {
+ return true;
+ }
+
+ return ServiceState.bitmaskHasTech((int) mLingeringNetworkTypeBitmask, networkType);
+ }
+
// Implement Parcelable.
@Override
/** @hide */
@@ -1537,6 +1605,7 @@
dest.writeInt(mRoamingProtocol);
dest.writeBoolean(mCarrierEnabled);
dest.writeInt(mNetworkTypeBitmask);
+ dest.writeLong(mLingeringNetworkTypeBitmask);
dest.writeInt(mProfileId);
dest.writeBoolean(mPersistent);
dest.writeInt(mMaxConns);
@@ -1549,6 +1618,7 @@
dest.writeInt(mApnSetId);
dest.writeInt(mCarrierId);
dest.writeInt(mSkip464Xlat);
+ dest.writeBoolean(mAlwaysOn);
}
private static ApnSetting readFromParcel(Parcel in) {
@@ -1570,6 +1640,7 @@
.setRoamingProtocol(in.readInt())
.setCarrierEnabled(in.readBoolean())
.setNetworkTypeBitmask(in.readInt())
+ .setLingeringNetworkTypeBitmask(in.readLong())
.setProfileId(in.readInt())
.setModemCognitive(in.readBoolean())
.setMaxConns(in.readInt())
@@ -1582,6 +1653,7 @@
.setApnSetId(in.readInt())
.setCarrierId(in.readInt())
.setSkip464Xlat(in.readInt())
+ .setAlwaysOn(in.readBoolean())
.buildWithoutCheck();
}
@@ -1649,7 +1721,8 @@
private int mRoamingProtocol = UNSPECIFIED_INT;
private int mMtuV4;
private int mMtuV6;
- private int mNetworkTypeBitmask;
+ private @TelephonyManager.NetworkTypeBitMask int mNetworkTypeBitmask;
+ private @TelephonyManager.NetworkTypeBitMask long mLingeringNetworkTypeBitmask;
private boolean mCarrierEnabled;
private int mProfileId;
private boolean mModemCognitive;
@@ -1661,6 +1734,7 @@
private int mApnSetId;
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
+ private boolean mAlwaysOn;
/**
* Default constructor for Builder.
@@ -2012,6 +2086,19 @@
}
/**
+ * Sets lingering Radio Technology (Network Type) for this APN.
+ *
+ * @param lingeringNetworkTypeBitmask the Radio Technology (Network Type) that should linger
+ * @hide
+ */
+ @NonNull
+ public Builder setLingeringNetworkTypeBitmask(@TelephonyManager.NetworkTypeBitMask
+ long lingeringNetworkTypeBitmask) {
+ this.mLingeringNetworkTypeBitmask = lingeringNetworkTypeBitmask;
+ return this;
+ }
+
+ /**
* Sets the MVNO match type for this APN.
*
* @param mvnoType the MVNO match type to set for this APN
@@ -2048,6 +2135,18 @@
}
/**
+ * Sets whether the PDU session brought up by this APN should always be on.
+ * See 3GPP TS 23.501 section 5.6.13
+ *
+ * @param alwaysOn the always on status to set for this APN
+ * @hide
+ */
+ public Builder setAlwaysOn(boolean alwaysOn) {
+ this.mAlwaysOn = alwaysOn;
+ return this;
+ }
+
+ /**
* Builds {@link ApnSetting} from this builder.
*
* @return {@code null} if {@link #setApnName(String)} or {@link #setEntryName(String)}
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 2f03475..892eb29 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -402,6 +402,21 @@
}
/**
+ * Notify the system that a given DataProfile was unthrottled.
+ *
+ * @param dataProfile DataProfile associated with an APN returned from the modem
+ */
+ public final void notifyDataProfileUnthrottled(@NonNull DataProfile dataProfile) {
+ synchronized (mApnUnthrottledCallbacks) {
+ for (IDataServiceCallback callback : mApnUnthrottledCallbacks) {
+ mHandler.obtainMessage(DATA_SERVICE_INDICATION_APN_UNTHROTTLED,
+ mSlotIndex, 0, new ApnUnthrottledIndication(dataProfile,
+ callback)).sendToTarget();
+ }
+ }
+ }
+
+ /**
* Called when the instance of data service is destroyed (e.g. got unbind or binder died)
* or when the data service provider is removed. The extended class should implement this
* method to perform cleanup works.
@@ -496,13 +511,20 @@
}
private static final class ApnUnthrottledIndication {
+ public final DataProfile dataProfile;
public final String apn;
public final IDataServiceCallback callback;
ApnUnthrottledIndication(String apn,
IDataServiceCallback callback) {
+ this.dataProfile = null;
this.apn = apn;
this.callback = callback;
}
+ ApnUnthrottledIndication(DataProfile dataProfile, IDataServiceCallback callback) {
+ this.dataProfile = dataProfile;
+ this.apn = null;
+ this.callback = callback;
+ }
}
private class DataServiceHandler extends Handler {
@@ -636,8 +658,13 @@
ApnUnthrottledIndication apnUnthrottledIndication =
(ApnUnthrottledIndication) message.obj;
try {
- apnUnthrottledIndication.callback
- .onApnUnthrottled(apnUnthrottledIndication.apn);
+ if (apnUnthrottledIndication.dataProfile != null) {
+ apnUnthrottledIndication.callback
+ .onDataProfileUnthrottled(apnUnthrottledIndication.dataProfile);
+ } else {
+ apnUnthrottledIndication.callback
+ .onApnUnthrottled(apnUnthrottledIndication.apn);
+ }
} catch (RemoteException e) {
loge("Failed to call onApnUnthrottled. " + e);
}
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index d082715..051d6c5 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -260,8 +260,8 @@
/**
* Unthrottles the APN on the current transport. There is no matching "APN throttle" method.
- * Instead, the APN is throttled for the time specified in
- * {@link DataCallResponse#getRetryDurationMillis}.
+ * Instead, the APN is throttled when {@link IDataService#setupDataCall} fails within
+ * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
* <p/>
* see: {@link DataCallResponse#getRetryDurationMillis}
*
@@ -279,4 +279,27 @@
Rlog.e(TAG, "onApnUnthrottled: callback is null!");
}
}
+
+ /**
+ * Unthrottles the DataProfile on the current transport.
+ * There is no matching "DataProfile throttle" method.
+ * Instead, the DataProfile is throttled when {@link IDataService#setupDataCall} fails within
+ * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
+ * <p/>
+ * see: {@link DataCallResponse#getRetryDurationMillis}
+ *
+ * @param dataProfile DataProfile containing the APN to be throttled
+ */
+ public void onDataProfileUnthrottled(final @NonNull DataProfile dataProfile) {
+ if (mCallback != null) {
+ try {
+ if (DBG) Rlog.d(TAG, "onDataProfileUnthrottled");
+ mCallback.onDataProfileUnthrottled(dataProfile);
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "onDataProfileUnthrottled: remote exception", e);
+ }
+ } else {
+ Rlog.e(TAG, "onDataProfileUnthrottled: callback is null!");
+ }
+ }
}
diff --git a/telephony/java/android/telephony/data/IDataServiceCallback.aidl b/telephony/java/android/telephony/data/IDataServiceCallback.aidl
index 9cc2fea..8205b5e 100644
--- a/telephony/java/android/telephony/data/IDataServiceCallback.aidl
+++ b/telephony/java/android/telephony/data/IDataServiceCallback.aidl
@@ -17,6 +17,7 @@
package android.telephony.data;
import android.telephony.data.DataCallResponse;
+import android.telephony.data.DataProfile;
/**
* The call back interface
@@ -33,4 +34,5 @@
void onHandoverStarted(int result);
void onHandoverCancelled(int result);
void onApnUnthrottled(in String apn);
+ void onDataProfileUnthrottled(in DataProfile dp);
}
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index e1aec0a..ab35d77 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -17,6 +17,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
@@ -24,6 +25,7 @@
import android.os.RemoteException;
import android.service.euicc.EuiccProfileInfo;
import android.telephony.TelephonyFrameworkInitializer;
+import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.internal.telephony.euicc.IAuthenticateServerCallback;
@@ -122,7 +124,6 @@
/** Result code indicating the caller is not the active LPA. */
public static final int RESULT_CALLER_NOT_ALLOWED = -3;
-
/**
* Callback to receive the result of an eUICC card API.
*
@@ -220,12 +221,48 @@
* @param refresh Whether sending the REFRESH command to modem.
* @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code.
+ *
+ * @deprecated instead use {@link #disableProfile(String, String, int, boolean, Executor,
+ * ResultCallback)}
*/
+ @Deprecated
public void disableProfile(String cardId, String iccid, boolean refresh,
@CallbackExecutor Executor executor, ResultCallback<Void> callback) {
try {
getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
- refresh, new IDisableProfileCallback.Stub() {
+ TelephonyManager.DEFAULT_PORT_INDEX, refresh,
+ new IDisableProfileCallback.Stub() {
+ @Override
+ public void onComplete(int resultCode) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling disableProfile", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ /**
+ * Disables the profile of the given ICCID.
+ *
+ * @param cardId The Id of the eUICC.
+ * @param iccid The iccid of the profile.
+ * @param portIndex the Port index is the unique index referring to a port.
+ * @param refresh Whether sending the REFRESH command to modem.
+ * @param executor The executor through which the callback should be invoked.
+ * @param callback The callback to get the result code.
+ */
+ public void disableProfile(@Nullable String cardId, @Nullable String iccid, int portIndex,
+ boolean refresh, @NonNull @CallbackExecutor Executor executor,
+ @NonNull ResultCallback<Void> callback) {
+ try {
+ getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
+ portIndex, refresh, new IDisableProfileCallback.Stub() {
@Override
public void onComplete(int resultCode) {
final long token = Binder.clearCallingIdentity();
@@ -251,12 +288,51 @@
* @param refresh Whether sending the REFRESH command to modem.
* @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code and the EuiccProfileInfo enabled.
+ *
+ * @deprecated instead use {@link #switchToProfile(String, String, int, boolean, Executor,
+ * ResultCallback)}
*/
+ @Deprecated
public void switchToProfile(String cardId, String iccid, boolean refresh,
@CallbackExecutor Executor executor, ResultCallback<EuiccProfileInfo> callback) {
try {
getIEuiccCardController().switchToProfile(mContext.getOpPackageName(), cardId, iccid,
- refresh, new ISwitchToProfileCallback.Stub() {
+ TelephonyManager.DEFAULT_PORT_INDEX, refresh,
+ new ISwitchToProfileCallback.Stub() {
+ @Override
+ public void onComplete(int resultCode, EuiccProfileInfo profile) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onComplete(resultCode, profile));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling switchToProfile", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Switches from the current profile to another profile. The current profile will be disabled
+ * and the specified profile will be enabled. Here portIndex specifies on which port the
+ * profile is to be enabled.
+ *
+ * @param cardId The Id of the eUICC.
+ * @param iccid The iccid of the profile to switch to.
+ * @param portIndex The Port index is the unique index referring to a port.
+ * @param refresh Whether sending the REFRESH command to modem.
+ * @param executor The executor through which the callback should be invoked.
+ * @param callback The callback to get the result code and the EuiccProfileInfo enabled.
+ */
+ public void switchToProfile(@Nullable String cardId, @Nullable String iccid, int portIndex,
+ boolean refresh, @NonNull @CallbackExecutor Executor executor,
+ @NonNull ResultCallback<EuiccProfileInfo> callback) {
+ try {
+ getIEuiccCardController().switchToProfile(mContext.getOpPackageName(), cardId, iccid,
+ portIndex, refresh, new ISwitchToProfileCallback.Stub() {
@Override
public void onComplete(int resultCode, EuiccProfileInfo profile) {
final long token = Binder.clearCallingIdentity();
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 2edb564c..45022a6 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -1418,4 +1418,22 @@
.getEuiccControllerService()
.get());
}
+
+ /**
+ * Returns whether the passing portIndex is available.
+ * A port is available if it has no profiles enabled on it or calling app has carrier privilege
+ * over the profile installed on the selected port.
+ * Always returns false if the cardId is a physical card.
+ *
+ * @param portIndex is an enumeration of the ports available on the UICC.
+ * @return {@code true} if port is available
+ */
+ public boolean isSimPortAvailable(int portIndex) {
+ try {
+ return getIEuiccController().isSimPortAvailable(mCardId, portIndex,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5577888..167aa07 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -77,6 +77,7 @@
import android.telephony.UiccCardInfo;
import android.telephony.UiccSlotInfo;
+import android.telephony.UiccSlotMapping;
/**
* Interface used to interact with the phone. Mostly this is used by the
@@ -1742,17 +1743,35 @@
* @return UiccSlotInfo array.
* @hide
*/
- UiccSlotInfo[] getUiccSlotsInfo();
+ UiccSlotInfo[] getUiccSlotsInfo(String callingPackage);
/**
* Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive.
* @param physicalSlots Index i in the array representing physical slot for phone i. The array
* size should be same as getPhoneCount().
+ * @deprecated Use {@link #setSimSlotMapping(in List<UiccSlotMapping> slotMapping)} instead.
* @return boolean Return true if the switch succeeds, false if the switch fails.
*/
boolean switchSlots(in int[] physicalSlots);
/**
+ * Maps the logical slots to the SlotPortMapping which consist of both physical slot index and
+ * port index. Logical slot is the slot that is seen by modem. Physical slot is the actual
+ * physical slot. Port index is the index (enumerated value) for the associated port available
+ * on the SIM. Each physical slot can have multiple ports which enables multi-enabled profile
+ * (MEP). If eUICC physical slot supports 2 ports, then the port index is numbered 0,1 and if
+ * eUICC2 supports 4 ports then the port index is numbered 0,1,2,3. Each portId is unique within
+ * a UICC physical slot but not necessarily unique across UICC’s. SEP(Single enabled profile)
+ * eUICC and non-eUICC will only have port Index 0.
+ *
+ * Logical slots that are already mapped to the requested SlotPortMapping are not impacted.
+ * @param slotMapping Index i in the list representing slot mapping for phone i.
+ *
+ * @return {@code true} if the switch succeeds, {@code false} if the switch fails.
+ */
+ boolean setSimSlotMapping(in List<UiccSlotMapping> slotMapping);
+
+ /**
* Returns whether mobile data roaming is enabled on the subscription with id {@code subId}.
*
* @param subId the subscription id
@@ -2130,7 +2149,7 @@
/**
* Get the mapping from logical slots to physical slots.
*/
- int[] getSlotsMapping();
+ int[] getSlotsMapping(String callingPackage);
/**
* Get the IRadio HAL Version encoded as 100 * MAJOR_VERSION + MINOR_VERSION or -1 if unknown
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 3a99f0e0..f650246 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -171,6 +171,8 @@
public static final String SLOT_KEY = "slot";
+ public static final String PORT_KEY = "port";
+
// FIXME: This is used to pass a subId via intents, we need to look at its usage, which is
// FIXME: extensive, and see if this should be an array of all active subId's or ...?
/**
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 866fd2c..ba95841 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -530,6 +530,8 @@
int RIL_REQUEST_GET_SLICING_CONFIG = 224;
int RIL_REQUEST_ENABLE_VONR = 225;
int RIL_REQUEST_IS_VONR_ENABLED = 226;
+ int RIL_REQUEST_SET_USAGE_SETTING = 227;
+ int RIL_REQUEST_GET_USAGE_SETTING = 228;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
index e33f44c..c717c09 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
@@ -45,10 +45,10 @@
in IGetAllProfilesCallback callback);
oneway void getProfile(String callingPackage, String cardId, String iccid,
in IGetProfileCallback callback);
- oneway void disableProfile(String callingPackage, String cardId, String iccid, boolean refresh,
- in IDisableProfileCallback callback);
- oneway void switchToProfile(String callingPackage, String cardId, String iccid, boolean refresh,
- in ISwitchToProfileCallback callback);
+ oneway void disableProfile(String callingPackage, String cardId, String iccid, int portIndex,
+ boolean refresh, in IDisableProfileCallback callback);
+ oneway void switchToProfile(String callingPackage, String cardId, String iccid, int portIndex,
+ boolean refresh, in ISwitchToProfileCallback callback);
oneway void setNickname(String callingPackage, String cardId, String iccid, String nickname,
in ISetNicknameCallback callback);
oneway void deleteProfile(String callingPackage, String cardId, String iccid,
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 35e8a12..944ce348 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -51,4 +51,5 @@
void setSupportedCountries(boolean isSupported, in List<String> countriesList);
List<String> getSupportedCountries(boolean isSupported);
boolean isSupportedCountry(String countryIso);
+ boolean isSimPortAvailable(int cardId, int portIndex, String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 5b44dba..21c3f76 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -23,6 +23,7 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Build;
+import android.telephony.UiccPortInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.GsmAlphabet;
@@ -44,8 +45,7 @@
static final int FPLMN_BYTE_SIZE = 3;
// ICCID used for tests by some OEMs
- // TODO(b/159354974): Replace the constant here with UiccPortInfo.ICCID_REDACTED once ready
- private static final String TEST_ICCID = "FFFFFFFFFFFFFFFFFFFF";
+ public static final String TEST_ICCID = UiccPortInfo.ICCID_REDACTED;
// A table mapping from a number to a hex character for fast encoding hex strings.
private static final char[] HEX_CHARS = {
diff --git a/test-legacy/Android.mk b/test-legacy/Android.mk
index ce5e4cf..284008c 100644
--- a/test-legacy/Android.mk
+++ b/test-legacy/Android.mk
@@ -41,6 +41,6 @@
include $(BUILD_STATIC_JAVA_LIBRARY)
# Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.legacy.jar)
+$(call dist-for-goals,sdk,$(full_classes_jar):android.test.legacy.jar)
endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index f0ab63e..06200cd 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -449,8 +449,7 @@
// Query proper module name
result = getPackageManagerNative().getStagedApexInfo(TEST_APEX_PACKAGE_NAME);
assertThat(result.moduleName).isEqualTo(TEST_APEX_PACKAGE_NAME);
- assertThat(result.hasBootClassPathJars).isTrue();
- assertThat(result.hasSystemServerClassPathJars).isTrue();
+ assertThat(result.hasClassPathJars).isTrue();
InstallUtils.openPackageInstallerSession(sessionId).abandon();
}