Merge "Revert "Removed BluetoothDevice#prepareToEnterProcess""
diff --git a/ApiDocs.bp b/ApiDocs.bp
index c181646..a926ddc 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -192,6 +192,42 @@
},
}
+// This produces the same annotations.zip as framework-doc-stubs, but by using
+// outputs from individual modules instead of all the source code.
+genrule {
+ name: "sdk-annotations.zip",
+ srcs: [
+ ":android-non-updatable-doc-stubs{.annotations.zip}",
+
+ // Conscrypt and i18n currently do not enable annotations
+ // ":conscrypt.module.public.api{.public.annotations.zip}",
+ // ":i18n.module.public.api{.public.annotations.zip}",
+
+ // Modules that enable annotations below
+ ":android.net.ipsec.ike{.public.annotations.zip}",
+ ":art.module.public.api{.public.annotations.zip}",
+ ":framework-appsearch{.public.annotations.zip}",
+ ":framework-connectivity{.public.annotations.zip}",
+ ":framework-graphics{.public.annotations.zip}",
+ ":framework-media{.public.annotations.zip}",
+ ":framework-mediaprovider{.public.annotations.zip}",
+ ":framework-permission{.public.annotations.zip}",
+ ":framework-permission-s{.public.annotations.zip}",
+ ":framework-scheduling{.public.annotations.zip}",
+ ":framework-sdkextensions{.public.annotations.zip}",
+ ":framework-statsd{.public.annotations.zip}",
+ ":framework-tethering{.public.annotations.zip}",
+ ":framework-wifi{.public.annotations.zip}",
+ ],
+ out: ["annotations.zip"],
+ tools: [
+ "merge_annotation_zips",
+ "soong_zip",
+ ],
+ cmd: "$(location merge_annotation_zips) $(genDir)/out $(in) && " +
+ "$(location soong_zip) -o $(out) -C $(genDir)/out -D $(genDir)/out",
+}
+
/////////////////////////////////////////////////////////////////////
// API docs are created from the generated stub source files
// using droiddoc
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 591e8ba..4becc6b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1008,13 +1008,21 @@
}
@Override
- public void onUserUnlocked(@NonNull TargetUser user) {
+ public void onUserStarting(@NonNull TargetUser user) {
synchronized (mLock) {
- // Note that the user has started after its unlocked instead of when the user
- // actually starts because the storage won't be decrypted until unlock.
mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier());
}
- // Let's kick any outstanding jobs for this user.
+ // The user is starting but credential encrypted storage is still locked.
+ // Only direct-boot-aware jobs can safely run.
+ // Let's kick off any eligible jobs for this user.
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+
+ @Override
+ public void onUserUnlocked(@NonNull TargetUser user) {
+ // The user is fully unlocked and credential encrypted storage is now decrypted.
+ // Direct-boot-UNaware jobs can now safely run.
+ // Let's kick off any outstanding jobs for this user.
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
index f2e64ce..1a710a98b 100644
--- a/apex/media/Android.bp
+++ b/apex/media/Android.bp
@@ -28,8 +28,8 @@
sdk {
name: "media-module-sdk",
bootclasspath_fragments: ["com.android.media-bootclasspath-fragment"],
+ systemserverclasspath_fragments: ["com.android.media-systemserverclasspath-fragment"],
java_sdk_libs: [
"framework-media",
- "service-media-s",
],
}
diff --git a/api/Android.bp b/api/Android.bp
index 2d7b8bd..ed2247b 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -430,7 +430,7 @@
}
genrule {
- name: "services-system-server-current.txt",
+ name: "frameworks-base-api-system-server-current.txt",
srcs: [
":service-media-s{.system-server.api.txt}",
":service-permission{.system-server.api.txt}",
@@ -457,7 +457,7 @@
}
genrule {
- name: "services-system-server-removed.txt",
+ name: "frameworks-base-api-system-server-removed.txt",
srcs: [
":service-media-s{.system-server.removed-api.txt}",
":service-permission{.system-server.removed-api.txt}",
diff --git a/core/api/current.txt b/core/api/current.txt
index 738851b..b54a747 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -112,6 +112,7 @@
field public static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
field public static final String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
+ field public static final String NEARBY_WIFI_DEVICES = "android.permission.NEARBY_WIFI_DEVICES";
field public static final String NFC = "android.permission.NFC";
field public static final String NFC_PREFERRED_PAYMENT_INFO = "android.permission.NFC_PREFERRED_PAYMENT_INFO";
field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
@@ -25516,6 +25517,7 @@
field public static final String COLUMN_CONTENT_ID = "content_id";
field public static final String COLUMN_CONTENT_RATING = "content_rating";
field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final String COLUMN_EPISODE_TITLE = "episode_title";
field public static final String COLUMN_INTENT_URI = "intent_uri";
@@ -25546,6 +25548,7 @@
field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final String COLUMN_SPLIT_ID = "split_id";
field public static final String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
field public static final String COLUMN_TITLE = "title";
@@ -25708,6 +25711,7 @@
field public static final String COLUMN_CONTENT_ID = "content_id";
field public static final String COLUMN_CONTENT_RATING = "content_rating";
field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final String COLUMN_EPISODE_TITLE = "episode_title";
field public static final String COLUMN_INTENT_URI = "intent_uri";
@@ -25739,6 +25743,7 @@
field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final String COLUMN_SPLIT_ID = "split_id";
field public static final String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
field public static final String COLUMN_TITLE = "title";
@@ -31423,6 +31428,7 @@
method public int dataSize();
method public void enforceInterface(@NonNull String);
method public boolean hasFileDescriptors();
+ method public boolean hasFileDescriptors(int, int);
method public byte[] marshall();
method @NonNull public static android.os.Parcel obtain();
method @NonNull public static android.os.Parcel obtain(@NonNull android.os.IBinder);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b574d04..49df45a 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -311,6 +311,10 @@
package android.provider {
+ public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns {
+ method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public static java.util.Map<java.lang.String,java.util.List<android.content.ContentValues>> queryRawContactEntity(@NonNull android.content.ContentResolver, long);
+ }
+
public final class DeviceConfig {
field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
field public static final String NAMESPACE_APP_STANDBY = "app_standby";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4a732e5..9c6939e5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1935,6 +1935,22 @@
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
}
+ public final class BluetoothActivityEnergyInfo implements android.os.Parcelable {
+ method public int getBluetoothStackState();
+ method public long getControllerEnergyUsed();
+ method public long getControllerIdleTimeMillis();
+ method public long getControllerRxTimeMillis();
+ method public long getControllerTxTimeMillis();
+ method public long getTimeStamp();
+ method @NonNull public java.util.List<android.bluetooth.UidTraffic> getUidTraffic();
+ method public boolean isValid();
+ field public static final int BT_STACK_STATE_INVALID = 0; // 0x0
+ field public static final int BT_STACK_STATE_STATE_ACTIVE = 1; // 0x1
+ field public static final int BT_STACK_STATE_STATE_IDLE = 3; // 0x3
+ field public static final int BT_STACK_STATE_STATE_SCANNING = 2; // 0x2
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothActivityEnergyInfo> CREATOR;
+ }
+
public final class BluetoothAdapter {
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean disable(boolean);
@@ -2128,6 +2144,7 @@
field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
field @NonNull public static final android.os.ParcelUuid BASE_UUID;
field @NonNull public static final android.os.ParcelUuid BNEP;
+ field @NonNull public static final android.os.ParcelUuid CAP;
field @NonNull public static final android.os.ParcelUuid COORDINATED_SET;
field @NonNull public static final android.os.ParcelUuid DIP;
field @NonNull public static final android.os.ParcelUuid GENERIC_MEDIA_CONTROL;
@@ -2233,6 +2250,13 @@
method @NonNull public android.bluetooth.OobData.LeBuilder setRandomizerHash(@NonNull byte[]);
}
+ public final class UidTraffic implements java.lang.Cloneable android.os.Parcelable {
+ method public long getRxBytes();
+ method public long getTxBytes();
+ method public int getUid();
+ field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.UidTraffic> CREATOR;
+ }
+
}
package android.bluetooth.le {
@@ -9138,6 +9162,7 @@
field public static final String NAMESPACE_MEDIA = "media";
field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+ field public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
field public static final String NAMESPACE_OTA = "ota";
field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 5f2c456..e08a493 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -158,10 +158,7 @@
"android/util/LocalLog.java",
// This should be android.util.IndentingPrintWriter, but it's not available in all branches.
"com/android/internal/util/IndentingPrintWriter.java",
- "com/android/internal/util/IState.java",
"com/android/internal/util/MessageUtils.java",
- "com/android/internal/util/State.java",
- "com/android/internal/util/StateMachine.java",
"com/android/internal/util/WakeupMessage.java",
],
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d932a29..0b336f6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1292,6 +1292,9 @@
/** @hide */
public static final int OP_UWB_RANGING = AppProtoEnums.APP_OP_UWB_RANGING;
+ /** @hide */
+ public static final int OP_NEARBY_WIFI_DEVICES = AppProtoEnums.APP_OP_NEARBY_WIFI_DEVICES;
+
/**
* Activity recognition being accessed by an activity recognition source, which
* is a component that already has access since it is the one that detects
@@ -1312,7 +1315,7 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 116;
+ public static final int _NUM_OP = 117;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1731,6 +1734,8 @@
public static final String OPSTR_MANAGE_MEDIA = "android:manage_media";
/** @hide */
public static final String OPSTR_UWB_RANGING = "android:uwb_ranging";
+ /** @hide */
+ public static final String OPSTR_NEARBY_WIFI_DEVICES = "android:nearby_wifi_devices";
/**
* Activity recognition being accessed by an activity recognition source, which
@@ -1819,6 +1824,7 @@
OP_BLUETOOTH_CONNECT,
OP_BLUETOOTH_ADVERTISE,
OP_UWB_RANGING,
+ OP_NEARBY_WIFI_DEVICES,
// APPOP PERMISSIONS
OP_ACCESS_NOTIFICATIONS,
@@ -1963,6 +1969,7 @@
OP_ACTIVITY_RECOGNITION, // OP_ACTIVITY_RECOGNITION_SOURCE
OP_BLUETOOTH_ADVERTISE, // OP_BLUETOOTH_ADVERTISE
OP_RECORD_INCOMING_PHONE_AUDIO, // OP_RECORD_INCOMING_PHONE_AUDIO
+ OP_NEARBY_WIFI_DEVICES, // OP_NEARBY_WIFI_DEVICES
};
/**
@@ -2085,6 +2092,7 @@
OPSTR_ACTIVITY_RECOGNITION_SOURCE,
OPSTR_BLUETOOTH_ADVERTISE,
OPSTR_RECORD_INCOMING_PHONE_AUDIO,
+ OPSTR_NEARBY_WIFI_DEVICES,
};
/**
@@ -2208,6 +2216,7 @@
"ACTIVITY_RECOGNITION_SOURCE",
"BLUETOOTH_ADVERTISE",
"RECORD_INCOMING_PHONE_AUDIO",
+ "NEARBY_WIFI_DEVICES"
};
/**
@@ -2332,6 +2341,7 @@
null, // no permission for OP_ACTIVITY_RECOGNITION_SOURCE,
Manifest.permission.BLUETOOTH_ADVERTISE,
null, // no permission for OP_RECORD_INCOMING_PHONE_AUDIO,
+ Manifest.permission.NEARBY_WIFI_DEVICES,
};
/**
@@ -2456,6 +2466,7 @@
null, // ACTIVITY_RECOGNITION_SOURCE
null, // BLUETOOTH_ADVERTISE
null, // RECORD_INCOMING_PHONE_AUDIO
+ null, // NEARBY_WIFI_DEVICES
};
/**
@@ -2579,6 +2590,7 @@
null, // ACTIVITY_RECOGNITION_SOURCE
null, // BLUETOOTH_ADVERTISE
null, // RECORD_INCOMING_PHONE_AUDIO
+ null, // NEARBY_WIFI_DEVICES
};
/**
@@ -2701,6 +2713,7 @@
AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION_SOURCE
AppOpsManager.MODE_ALLOWED, // BLUETOOTH_ADVERTISE
AppOpsManager.MODE_ALLOWED, // RECORD_INCOMING_PHONE_AUDIO
+ AppOpsManager.MODE_ALLOWED, // NEARBY_WIFI_DEVICES
};
/**
@@ -2827,6 +2840,7 @@
false, // ACTIVITY_RECOGNITION_SOURCE
false, // BLUETOOTH_ADVERTISE
false, // RECORD_INCOMING_PHONE_AUDIO
+ false, // NEARBY_WIFI_DEVICES
};
/**
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index e0e9b62..4da51c1 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -28,6 +28,7 @@
per-file Service* = file:/services/core/java/com/android/server/am/OWNERS
per-file SystemServiceRegistry.java = file:/services/core/java/com/android/server/am/OWNERS
per-file *UserSwitchObserver* = file:/services/core/java/com/android/server/am/OWNERS
+per-file UiAutomation.java = file:/services/accessibility/OWNERS
# ActivityThread
per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
new file mode 100644
index 0000000..f560434
--- /dev/null
+++ b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
@@ -0,0 +1,4 @@
+rubinxu@google.com
+acjohnston@google.com
+pgrafov@google.com
+alexkershaw@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/core/java/android/app/admin/EnterprisePlatform_OWNERS b/core/java/android/app/admin/EnterprisePlatform_OWNERS
new file mode 100644
index 0000000..fb00fe5
--- /dev/null
+++ b/core/java/android/app/admin/EnterprisePlatform_OWNERS
@@ -0,0 +1,2 @@
+file:WorkDeviceExperience_OWNERS
+file:EnterprisePlatformSecurity_OWNERS
\ No newline at end of file
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
index 6acbef2..10a5f14 100644
--- a/core/java/android/app/admin/OWNERS
+++ b/core/java/android/app/admin/OWNERS
@@ -1,11 +1,5 @@
# Bug component: 142675
-# Android Enterprise team
-rubinxu@google.com
-sandness@google.com
-alexkershaw@google.com
-pgrafov@google.com
+file:EnterprisePlatform_OWNERS
-# Emeritus
-yamasani@google.com
-eranm@google.com
+yamasani@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/core/java/android/app/admin/WorkDeviceExperience_OWNERS b/core/java/android/app/admin/WorkDeviceExperience_OWNERS
new file mode 100644
index 0000000..dcacaa2
--- /dev/null
+++ b/core/java/android/app/admin/WorkDeviceExperience_OWNERS
@@ -0,0 +1,5 @@
+work-device-experience+reviews@google.com
+scottjonathan@google.com
+arangelov@google.com
+kholoudm@google.com
+alexkershaw@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file
diff --git a/core/java/android/app/time/OWNERS b/core/java/android/app/time/OWNERS
index 8f80897..ef357e5 100644
--- a/core/java/android/app/time/OWNERS
+++ b/core/java/android/app/time/OWNERS
@@ -1,3 +1,4 @@
# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# The app-facing APIs related to both time and time zone detection.
+include /services/core/java/com/android/server/timedetector/OWNERS
+include /services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/java/android/app/timedetector/OWNERS b/core/java/android/app/timedetector/OWNERS
index 941eed8..e9dbe4a 100644
--- a/core/java/android/app/timedetector/OWNERS
+++ b/core/java/android/app/timedetector/OWNERS
@@ -1,4 +1,3 @@
# Bug component: 847766
-mingaleev@google.com
-narayan@google.com
-nfuller@google.com
+# Internal APIs related to time detection. SDK APIs are in android.app.time.
+include /services/core/java/com/android/server/timedetector/OWNERS
diff --git a/core/java/android/app/timezone/OWNERS b/core/java/android/app/timezone/OWNERS
index 8f80897..04d78f2 100644
--- a/core/java/android/app/timezone/OWNERS
+++ b/core/java/android/app/timezone/OWNERS
@@ -1,3 +1,4 @@
-# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# Bug component: 24949
+# Internal APIs related to APK-based time zone rule updates.
+# Deprecated, deletion tracked by b/148144561
+include /services/core/java/com/android/server/timezone/OWNERS
diff --git a/core/java/android/app/timezonedetector/OWNERS b/core/java/android/app/timezonedetector/OWNERS
index 8f80897..fa03f1e 100644
--- a/core/java/android/app/timezonedetector/OWNERS
+++ b/core/java/android/app/timezonedetector/OWNERS
@@ -1,3 +1,3 @@
# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# Internal APIs related to time zone detection. SDK APIs are in android.app.time.
+include /services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
index df065bf..f371c6d 100644
--- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
+++ b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
@@ -16,18 +16,25 @@
package android.bluetooth;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
/**
* Record of energy and activity information from controller and
* underlying bt stack state.Timestamp the record with system
- * time
+ * time.
*
* @hide
*/
+@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
public final class BluetoothActivityEnergyInfo implements Parcelable {
private final long mTimestamp;
private int mBluetoothStackState;
@@ -35,13 +42,24 @@
private long mControllerRxTimeMs;
private long mControllerIdleTimeMs;
private long mControllerEnergyUsed;
- private UidTraffic[] mUidTraffic;
+ private List<UidTraffic> mUidTraffic;
+
+ /** @hide */
+ @IntDef(prefix = { "BT_STACK_STATE_" }, value = {
+ BT_STACK_STATE_INVALID,
+ BT_STACK_STATE_STATE_ACTIVE,
+ BT_STACK_STATE_STATE_SCANNING,
+ BT_STACK_STATE_STATE_IDLE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BluetoothStackState {}
public static final int BT_STACK_STATE_INVALID = 0;
public static final int BT_STACK_STATE_STATE_ACTIVE = 1;
public static final int BT_STACK_STATE_STATE_SCANNING = 2;
public static final int BT_STACK_STATE_STATE_IDLE = 3;
+ /** @hide */
public BluetoothActivityEnergyInfo(long timestamp, int stackState,
long txTime, long rxTime, long idleTime, long energyUsed) {
mTimestamp = timestamp;
@@ -52,17 +70,18 @@
mControllerEnergyUsed = energyUsed;
}
- @SuppressWarnings("unchecked")
- BluetoothActivityEnergyInfo(Parcel in) {
+ /** @hide */
+ private BluetoothActivityEnergyInfo(Parcel in) {
mTimestamp = in.readLong();
mBluetoothStackState = in.readInt();
mControllerTxTimeMs = in.readLong();
mControllerRxTimeMs = in.readLong();
mControllerIdleTimeMs = in.readLong();
mControllerEnergyUsed = in.readLong();
- mUidTraffic = in.createTypedArray(UidTraffic.CREATOR);
+ mUidTraffic = in.createTypedArrayList(UidTraffic.CREATOR);
}
+ /** @hide */
@Override
public String toString() {
return "BluetoothActivityEnergyInfo{"
@@ -72,11 +91,11 @@
+ " mControllerRxTimeMs=" + mControllerRxTimeMs
+ " mControllerIdleTimeMs=" + mControllerIdleTimeMs
+ " mControllerEnergyUsed=" + mControllerEnergyUsed
- + " mUidTraffic=" + Arrays.toString(mUidTraffic)
+ + " mUidTraffic=" + mUidTraffic
+ " }";
}
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
+ public static final @NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
new Parcelable.Creator<BluetoothActivityEnergyInfo>() {
public BluetoothActivityEnergyInfo createFromParcel(Parcel in) {
return new BluetoothActivityEnergyInfo(in);
@@ -87,9 +106,8 @@
}
};
-
+ /** @hide */
@Override
- @SuppressWarnings("unchecked")
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mTimestamp);
out.writeInt(mBluetoothStackState);
@@ -97,17 +115,21 @@
out.writeLong(mControllerRxTimeMs);
out.writeLong(mControllerIdleTimeMs);
out.writeLong(mControllerEnergyUsed);
- out.writeTypedArray(mUidTraffic, flags);
+ out.writeTypedList(mUidTraffic);
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
/**
- * @return bt stack reported state
+ * Get the Bluetooth stack state associated with the energy info.
+ *
+ * @return one of {@link #BluetoothStackState} states
*/
+ @BluetoothStackState
public int getBluetoothStackState() {
return mBluetoothStackState;
}
@@ -134,7 +156,7 @@
}
/**
- * product of current(mA), voltage(V) and time(ms)
+ * Get the product of current (mA), voltage (V), and time (ms).
*
* @return energy used
*/
@@ -143,22 +165,31 @@
}
/**
- * @return timestamp(real time elapsed in milliseconds since boot) of record creation.
+ * @return timestamp (real time elapsed in milliseconds since boot) of record creation
*/
public long getTimeStamp() {
return mTimestamp;
}
- public UidTraffic[] getUidTraffic() {
+ /**
+ * Get the {@link List} of each application {@link android.bluetooth.UidTraffic}.
+ *
+ * @return current {@link List} of {@link android.bluetooth.UidTraffic}
+ */
+ public @NonNull List<UidTraffic> getUidTraffic() {
+ if (mUidTraffic == null) {
+ return Collections.emptyList();
+ }
return mUidTraffic;
}
- public void setUidTraffic(UidTraffic[] traffic) {
+ /** @hide */
+ public void setUidTraffic(List<UidTraffic> traffic) {
mUidTraffic = traffic;
}
/**
- * @return if the record is valid
+ * @return true if the record is valid
*/
public boolean isValid() {
return ((mControllerTxTimeMs >= 0) && (mControllerRxTimeMs >= 0)
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 3b744a7..06ce053 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2099,7 +2099,7 @@
try {
return mManagerService.isBleScanAlwaysAvailable();
} catch (RemoteException e) {
- Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e);
+ Log.e(TAG, "remote exception when calling isBleScanAlwaysAvailable", e);
return false;
}
}
@@ -2307,7 +2307,7 @@
try {
return mManagerService.isHearingAidProfileSupported();
} catch (RemoteException e) {
- Log.e(TAG, "remote expection when calling isHearingAidProfileSupported", e);
+ Log.e(TAG, "remote exception when calling isHearingAidProfileSupported", e);
return false;
}
}
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 3ea865b..d7940eb 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -156,6 +156,12 @@
"android.bluetooth.action.LE_AUDIO_CONF_CHANGED";
/**
+ * Indicates unspecified audio content.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_UNSPECIFIED = 0x0001;
+
+ /**
* Indicates conversation between humans as, for example, in telephony or video calls.
* @hide
*/
@@ -168,6 +174,66 @@
public static final int CONTEXT_TYPE_MEDIA = 0x0004;
/**
+ * Indicates instructional audio as, for example, in navigation, traffic announcements
+ * or user guidance.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_INSTRUCTIONAL = 0x0008;
+
+ /**
+ * Indicates attention seeking audio as, for example, in beeps signalling arrival of a message
+ * or keyboard clicks.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_ATTENTION_SEEKING = 0x0010;
+
+ /**
+ * Indicates immediate alerts as, for example, in a low battery alarm, timer expiry or alarm
+ * clock.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_IMMEDIATE_ALERT = 0x0020;
+
+ /**
+ * Indicates man machine communication as, for example, with voice recognition or virtual
+ * assistant.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_MAN_MACHINE = 0x0040;
+
+ /**
+ * Indicates emergency alerts as, for example, with fire alarms or other urgent alerts.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_EMERGENCY_ALERT = 0x0080;
+
+ /**
+ * Indicates ringtone as in a call alert.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_RINGTONE = 0x0100;
+
+ /**
+ * Indicates audio associated with a television program and/or with metadata conforming to the
+ * Bluetooth Broadcast TV profile.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_TV = 0x0200;
+
+ /**
+ * Indicates audio associated with a low latency live audio stream.
+ *
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_LIVE = 0x0400;
+
+ /**
+ * Indicates audio associated with a video game stream.
+ * @hide
+ */
+ public static final int CONTEXT_TYPE_GAME = 0x0800;
+
+ /**
* This represents an invalid group ID.
*
* @hide
@@ -199,11 +265,8 @@
*
* <p>
* <ul>
- * <li> {@link #GROUP_STATUS_IDLE} </li>
- * <li> {@link #GROUP_STATUS_STREAMING} </li>
- * <li> {@link #GROUP_STATUS_SUSPENDED} </li>
- * <li> {@link #GROUP_STATUS_RECONFIGURED} </li>
- * <li> {@link #GROUP_STATUS_DESTROYED} </li>
+ * <li> {@link #GROUP_STATUS_ACTIVE} </li>
+ * <li> {@link #GROUP_STATUS_INACTIVE} </li>
* </ul>
* <p>
* @hide
@@ -241,6 +304,30 @@
private final BluetoothAdapter mAdapter;
private final AttributionSource mAttributionSource;
+ /**
+ * Indicating that group is Active ( Audio device is available )
+ * @hide
+ */
+ public static final int GROUP_STATUS_ACTIVE = IBluetoothLeAudio.GROUP_STATUS_ACTIVE;
+
+ /**
+ * Indicating that group is Inactive ( Audio device is not available )
+ * @hide
+ */
+ public static final int GROUP_STATUS_INACTIVE = IBluetoothLeAudio.GROUP_STATUS_INACTIVE;
+
+ /**
+ * Indicating that node has been added to the group.
+ * @hide
+ */
+ public static final int GROUP_NODE_ADDED = IBluetoothLeAudio.GROUP_NODE_ADDED;
+
+ /**
+ * Indicating that node has been removed from the group.
+ * @hide
+ */
+ public static final int GROUP_NODE_REMOVED = IBluetoothLeAudio.GROUP_NODE_REMOVED;
+
private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio",
IBluetoothLeAudio.class.getName()) {
@@ -433,7 +520,7 @@
* <p> This API returns false in scenarios like the profile on the
* device is not connected or Bluetooth is not turned on.
* When this API returns true, it is guaranteed that the
- * {@link #ACTION_LEAUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
+ * {@link #ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
* with the active device.
*
*
@@ -512,6 +599,85 @@
}
/**
+ * Set volume for the streaming devices
+ *
+ * @param volume volume to set
+ * @hide
+ */
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED})
+ public void setVolume(int volume) {
+ if (VDBG) log("setVolume(vol: " + volume + " )");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ service.setVolume(volume, mAttributionSource);
+ return;
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return;
+ }
+ }
+
+ /**
+ * Add device to the given group.
+ * @param group_id group ID the device is being added to
+ * @param device the active device
+ * @return true on success, otherwise false
+ * @hide
+ */
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED
+ })
+ public boolean groupAddNode(int group_id, @NonNull BluetoothDevice device) {
+ if (VDBG) log("groupAddNode()");
+ final IBluetoothLeAudio service = getService();
+ try {
+ if (service != null && mAdapter.isEnabled()) {
+ return service.groupAddNode(group_id, device, mAttributionSource);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Remove device from a given group.
+ * @param group_id group ID the device is being removed from
+ * @param device the active device
+ * @return true on success, otherwise false
+ *
+ * @hide
+ */
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED
+ })
+ public boolean groupRemoveNode(int group_id, @NonNull BluetoothDevice device) {
+ if (VDBG) log("groupRemoveNode()");
+ final IBluetoothLeAudio service = getService();
+ try {
+ if (service != null && mAdapter.isEnabled()) {
+ return service.groupRemoveNode(group_id, device, mAttributionSource);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
* Set connection policy of the profile
*
* <p> The device should already be paired.
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 67b7252..858819e 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -155,12 +155,11 @@
@SystemApi
public static final ParcelUuid HEARING_AID =
ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
- /** Placeholder until specification is released
- * @hide */
+ /** @hide */
@NonNull
@SystemApi
public static final ParcelUuid LE_AUDIO =
- ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+ ParcelUuid.fromString("0000184E-0000-1000-8000-00805F9B34FB");
/** @hide */
@NonNull
@SystemApi
@@ -189,6 +188,11 @@
/** @hide */
@NonNull
@SystemApi
+ public static final ParcelUuid CAP =
+ ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/bluetooth/UidTraffic.java b/core/java/android/bluetooth/UidTraffic.java
index 2ee786a..9982fa6 100644
--- a/core/java/android/bluetooth/UidTraffic.java
+++ b/core/java/android/bluetooth/UidTraffic.java
@@ -15,6 +15,7 @@
*/
package android.bluetooth;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,27 +24,27 @@
*
* @hide
*/
-public class UidTraffic implements Cloneable, Parcelable {
+@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+public final class UidTraffic implements Cloneable, Parcelable {
private final int mAppUid;
private long mRxBytes;
private long mTxBytes;
- public UidTraffic(int appUid) {
- mAppUid = appUid;
- }
-
+ /** @hide */
public UidTraffic(int appUid, long rx, long tx) {
mAppUid = appUid;
mRxBytes = rx;
mTxBytes = tx;
}
- UidTraffic(Parcel in) {
+ /** @hide */
+ private UidTraffic(Parcel in) {
mAppUid = in.readInt();
mRxBytes = in.readLong();
mTxBytes = in.readLong();
}
+ /** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mAppUid);
@@ -51,44 +52,60 @@
dest.writeLong(mTxBytes);
}
+ /** @hide */
public void setRxBytes(long bytes) {
mRxBytes = bytes;
}
+ /** @hide */
public void setTxBytes(long bytes) {
mTxBytes = bytes;
}
+ /** @hide */
public void addRxBytes(long bytes) {
mRxBytes += bytes;
}
+ /** @hide */
public void addTxBytes(long bytes) {
mTxBytes += bytes;
}
+ /**
+ * @return corresponding app Uid
+ */
public int getUid() {
return mAppUid;
}
+ /**
+ * @return rx bytes count
+ */
public long getRxBytes() {
return mRxBytes;
}
+ /**
+ * @return tx bytes count
+ */
public long getTxBytes() {
return mTxBytes;
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
+ /** @hide */
@Override
public UidTraffic clone() {
return new UidTraffic(mAppUid, mRxBytes, mTxBytes);
}
+ /** @hide */
@Override
public String toString() {
return "UidTraffic{mAppUid=" + mAppUid + ", mRxBytes=" + mRxBytes + ", mTxBytes="
diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java
index 6381f55..ed50b09 100644
--- a/core/java/android/bluetooth/le/BluetoothLeUtils.java
+++ b/core/java/android/bluetooth/le/BluetoothLeUtils.java
@@ -24,6 +24,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.UUID;
/**
* Helper class for Bluetooth LE utils.
@@ -137,4 +138,21 @@
}
}
+ /**
+ * Compares two UUIDs with a UUID mask.
+ *
+ * @param data first {@link #UUID} to compare.
+ * @param uuid second {@link #UUID} to compare.
+ * @param mask mask {@link #UUID}.
+ * @return true if both UUIDs are equals when masked, false otherwise.
+ */
+ static boolean maskedEquals(UUID data, UUID uuid, UUID mask) {
+ if (mask == null) {
+ return Objects.equals(data, uuid);
+ }
+ return (data.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ && (data.getMostSignificantBits() & mask.getMostSignificantBits())
+ == (uuid.getMostSignificantBits() & mask.getMostSignificantBits());
+ }
}
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 8ff0181..b059193 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -28,8 +28,6 @@
import android.os.ParcelUuid;
import android.os.Parcelable;
-import com.android.internal.util.BitUtils;
-
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -448,7 +446,7 @@
// Check if the uuid pattern matches the particular service uuid.
private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
- return BitUtils.maskedEquals(data, uuid, mask);
+ return BluetoothLeUtils.maskedEquals(data, uuid, mask);
}
/**
@@ -478,7 +476,7 @@
// Check if the solicitation uuid pattern matches the particular service solicitation uuid.
private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid,
UUID solicitationUuidMask, UUID data) {
- return BitUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask);
+ return BluetoothLeUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask);
}
// Check whether the data pattern matches the parsed data.
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 5e2340c..ef5f84c 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -22,7 +22,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.le.ScanFilter;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.wifi.ScanResult;
import android.os.Build;
@@ -30,9 +29,13 @@
import android.os.Parcelable;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
import java.util.regex.Pattern;
/** @hide */
@@ -73,12 +76,19 @@
static boolean matchesServiceUuid(ParcelUuid serviceUuid, ParcelUuid serviceUuidMask,
BluetoothDevice device) {
- ParcelUuid[] uuids = device.getUuids();
- final boolean result = serviceUuid == null ||
- ScanFilter.matchesServiceUuids(
- serviceUuid,
- serviceUuidMask,
- uuids == null ? Collections.emptyList() : Arrays.asList(uuids));
+ boolean result = false;
+ List<ParcelUuid> deviceUuids = device.getUuids() == null
+ ? Collections.emptyList() : Arrays.asList(device.getUuids());
+ if (serviceUuid == null) {
+ result = true;
+ } else {
+ for (ParcelUuid parcelUuid : deviceUuids) {
+ UUID uuidMask = serviceUuidMask == null ? null : serviceUuidMask.getUuid();
+ if (uuidsMaskedEquals(parcelUuid.getUuid(), serviceUuid.getUuid(), uuidMask)) {
+ result = true;
+ }
+ }
+ }
if (DEBUG) debugLogMatchResult(result, device, serviceUuid);
return result;
}
@@ -143,4 +153,23 @@
throw new IllegalArgumentException("Unknown device type: " + device);
}
}
+
+ /**
+ * Compares two {@link #UUID} with a {@link #UUID} mask.
+ *
+ * @param data first {@link #UUID}.
+ * @param uuid second {@link #UUID}.
+ * @param mask mask {@link #UUID}.
+ * @return true if both UUIDs are equals when masked, false otherwise.
+ */
+ @VisibleForTesting
+ public static boolean uuidsMaskedEquals(UUID data, UUID uuid, UUID mask) {
+ if (mask == null) {
+ return Objects.equals(data, uuid);
+ }
+ return (data.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits())
+ && (data.getMostSignificantBits() & mask.getMostSignificantBits())
+ == (uuid.getMostSignificantBits() & mask.getMostSignificantBits());
+ }
}
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index 828d482..58898cc 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -75,7 +75,7 @@
String renameSuffix, int renameBytesFrom, int renameBytesLength,
int renameNameFrom, int renameNameLength, boolean renameBytesReverseOrder) {
mNamePattern = namePattern;
- mScanFilter = ObjectUtils.firstNotNull(scanFilter, ScanFilter.EMPTY);
+ mScanFilter = ObjectUtils.firstNotNull(scanFilter, new ScanFilter.Builder().build());
mRawDataFilter = rawDataFilter;
mRawDataFilterMask = rawDataFilterMask;
mRenamePrefix = renamePrefix;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index b66f048..755114e 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1736,35 +1736,9 @@
* object and the given one. Does not change the values of either. Any
* undefined fields in <var>delta</var> are ignored.
* @return Returns a bit mask indicating which configuration
- * values has changed, containing any combination of
- * {@link android.content.pm.ActivityInfo#CONFIG_FONT_SCALE
- * PackageManager.ActivityInfo.CONFIG_FONT_SCALE},
- * {@link android.content.pm.ActivityInfo#CONFIG_MCC
- * PackageManager.ActivityInfo.CONFIG_MCC},
- * {@link android.content.pm.ActivityInfo#CONFIG_MNC
- * PackageManager.ActivityInfo.CONFIG_MNC},
- * {@link android.content.pm.ActivityInfo#CONFIG_LOCALE
- * PackageManager.ActivityInfo.CONFIG_LOCALE},
- * {@link android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN
- * PackageManager.ActivityInfo.CONFIG_TOUCHSCREEN},
- * {@link android.content.pm.ActivityInfo#CONFIG_KEYBOARD
- * PackageManager.ActivityInfo.CONFIG_KEYBOARD},
- * {@link android.content.pm.ActivityInfo#CONFIG_NAVIGATION
- * PackageManager.ActivityInfo.CONFIG_NAVIGATION},
- * {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION
- * PackageManager.ActivityInfo.CONFIG_ORIENTATION},
- * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT
- * PackageManager.ActivityInfo.CONFIG_SCREEN_LAYOUT}, or
- * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE
- * PackageManager.ActivityInfo.CONFIG_SCREEN_SIZE}, or
- * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE
- * PackageManager.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE}.
- * {@link android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION
- * PackageManager.ActivityInfo.CONFIG_LAYOUT_DIRECTION}.
- * {@link android.content.pm.ActivityInfo#CONFIG_FONT_WEIGHT_ADJUSTMENT
- * PackageManager.ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT.
+ * values have changed.
*/
- public int diff(Configuration delta) {
+ public @Config int diff(Configuration delta) {
return diff(delta, false /* compareUndefined */, false /* publicOnly */);
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 1d07a03..eb8f43e 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -220,8 +220,10 @@
String networkId = null;
boolean roaming = !snapshot.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- boolean metered = !snapshot.getNetworkCapabilities().hasCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ boolean metered = !(snapshot.getNetworkCapabilities().hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ || snapshot.getNetworkCapabilities().hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED));
final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 08f75df..74506da 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -160,19 +160,19 @@
}
/**
- * Template to match cellular networks with the given IMSI and {@code ratType}.
- * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
- * See {@code TelephonyManager.NETWORK_TYPE_*}.
+ * Template to match cellular networks with the given IMSI, {@code ratType} and
+ * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when
+ * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}.
*/
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
- @NetworkType int ratType) {
+ @NetworkType int ratType, int metered) {
if (TextUtils.isEmpty(subscriberId)) {
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
@@ -305,6 +305,7 @@
}
}
+ // 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);
@@ -312,9 +313,14 @@
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId) {
- this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ // 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,
+ (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);
}
// TODO: Remove it after updating all of the caller.
@@ -589,11 +595,7 @@
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
- // Only metered mobile network would be matched regardless of metered filter.
- // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650.
- // TODO: Respect metered filter and remove mMetered condition.
- return (ident.mType == TYPE_MOBILE && ident.mMetered)
- && !ArrayUtils.isEmpty(mMatchSubscriberIds)
+ return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
}
@@ -707,8 +709,7 @@
if (ident.mType == TYPE_WIMAX) {
return true;
} else {
- return (ident.mType == TYPE_MOBILE && ident.mMetered)
- && matchesCollapsedRatType(ident);
+ return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident);
}
}
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index 4ea8a54..f55bcd3 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -2,4 +2,5 @@
include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS
-per-file SSL*, Uri*, Url* = prb@google.com, dauletz@google.com, narayan@google.com, ngeoffray@google.com
+per-file SSL*,Uri*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com
+per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index f6852e6..0eb4cf3 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -17,16 +17,26 @@
package android.net;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.sntp.Duration64;
+import android.net.sntp.Timestamp64;
import android.os.SystemClock;
import android.util.Log;
+import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.TrafficStatsConstants;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.util.Arrays;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Objects;
+import java.util.Random;
+import java.util.function.Supplier;
/**
* {@hide}
@@ -60,17 +70,21 @@
private static final int NTP_STRATUM_DEATH = 0;
private static final int NTP_STRATUM_MAX = 15;
- // Number of seconds between Jan 1, 1900 and Jan 1, 1970
- // 70 years plus 17 leap days
- private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
+ // The source of the current system clock time, replaceable for testing.
+ private final Supplier<Instant> mSystemTimeSupplier;
- // system time computed from NTP server response
+ private final Random mRandom;
+
+ // The last offset calculated from an NTP server response
+ private long mClockOffset;
+
+ // The last system time computed from an NTP server response
private long mNtpTime;
- // value of SystemClock.elapsedRealtime() corresponding to mNtpTime
+ // The value of SystemClock.elapsedRealtime() corresponding to mNtpTime / mClockOffset
private long mNtpTimeReference;
- // round trip time in milliseconds
+ // The round trip (network) time in milliseconds
private long mRoundTripTime;
private static class InvalidServerReplyException extends Exception {
@@ -81,6 +95,13 @@
@UnsupportedAppUsage
public SntpClient() {
+ this(Instant::now, defaultRandom());
+ }
+
+ @VisibleForTesting
+ public SntpClient(Supplier<Instant> systemTimeSupplier, Random random) {
+ mSystemTimeSupplier = Objects.requireNonNull(systemTimeSupplier);
+ mRandom = Objects.requireNonNull(random);
}
/**
@@ -126,9 +147,13 @@
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
// get current time and write it to the request packet
- final long requestTime = System.currentTimeMillis();
+ final Instant requestTime = mSystemTimeSupplier.get();
+ final Timestamp64 requestTimestamp = Timestamp64.fromInstant(requestTime);
+
+ final Timestamp64 randomizedRequestTimestamp =
+ requestTimestamp.randomizeSubMillis(mRandom);
final long requestTicks = SystemClock.elapsedRealtime();
- writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);
+ writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, randomizedRequestTimestamp);
socket.send(request);
@@ -136,42 +161,44 @@
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
final long responseTicks = SystemClock.elapsedRealtime();
- final long responseTime = requestTime + (responseTicks - requestTicks);
+ final Instant responseTime = requestTime.plusMillis(responseTicks - requestTicks);
+ final Timestamp64 responseTimestamp = Timestamp64.fromInstant(responseTime);
// extract the results
final byte leap = (byte) ((buffer[0] >> 6) & 0x3);
final byte mode = (byte) (buffer[0] & 0x7);
final int stratum = (int) (buffer[1] & 0xff);
- final long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
- final long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
- final long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
- final long referenceTime = readTimeStamp(buffer, REFERENCE_TIME_OFFSET);
+ final Timestamp64 referenceTimestamp = readTimeStamp(buffer, REFERENCE_TIME_OFFSET);
+ final Timestamp64 originateTimestamp = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
+ final Timestamp64 receiveTimestamp = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
+ final Timestamp64 transmitTimestamp = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
/* Do validation according to RFC */
- // TODO: validate originateTime == requestTime.
- checkValidServerReply(leap, mode, stratum, transmitTime, referenceTime);
+ checkValidServerReply(leap, mode, stratum, transmitTimestamp, referenceTimestamp,
+ randomizedRequestTimestamp, originateTimestamp);
- long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
- // receiveTime = originateTime + transit + skew
- // responseTime = transmitTime + transit - skew
- // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2
- // = ((originateTime + transit + skew - originateTime) +
- // (transmitTime - (transmitTime + transit - skew)))/2
- // = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2
- // = (transit + skew - transit + skew)/2
- // = (2 * skew)/2 = skew
- long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
- EventLogTags.writeNtpSuccess(address.toString(), roundTripTime, clockOffset);
+ long totalTransactionDurationMillis = responseTicks - requestTicks;
+ long serverDurationMillis =
+ Duration64.between(receiveTimestamp, transmitTimestamp).toDuration().toMillis();
+ long roundTripTimeMillis = totalTransactionDurationMillis - serverDurationMillis;
+
+ Duration clockOffsetDuration = calculateClockOffset(requestTimestamp,
+ receiveTimestamp, transmitTimestamp, responseTimestamp);
+ long clockOffsetMillis = clockOffsetDuration.toMillis();
+
+ EventLogTags.writeNtpSuccess(
+ address.toString(), roundTripTimeMillis, clockOffsetMillis);
if (DBG) {
- Log.d(TAG, "round trip: " + roundTripTime + "ms, " +
- "clock offset: " + clockOffset + "ms");
+ Log.d(TAG, "round trip: " + roundTripTimeMillis + "ms, "
+ + "clock offset: " + clockOffsetMillis + "ms");
}
// save our results - use the times on this side of the network latency
// (response rather than request time)
- mNtpTime = responseTime + clockOffset;
+ mClockOffset = clockOffsetMillis;
+ mNtpTime = responseTime.plus(clockOffsetDuration).toEpochMilli();
mNtpTimeReference = responseTicks;
- mRoundTripTime = roundTripTime;
+ mRoundTripTime = roundTripTimeMillis;
} catch (Exception e) {
EventLogTags.writeNtpFailure(address.toString(), e.toString());
if (DBG) Log.d(TAG, "request time failed: " + e);
@@ -186,6 +213,28 @@
return true;
}
+ /** Performs the NTP clock offset calculation. */
+ @VisibleForTesting
+ public static Duration calculateClockOffset(Timestamp64 clientRequestTimestamp,
+ Timestamp64 serverReceiveTimestamp, Timestamp64 serverTransmitTimestamp,
+ Timestamp64 clientResponseTimestamp) {
+ // According to RFC4330:
+ // t is the system clock offset (the adjustment we are trying to find)
+ // t = ((T2 - T1) + (T3 - T4)) / 2
+ //
+ // Which is:
+ // t = (([server]receiveTimestamp - [client]requestTimestamp)
+ // + ([server]transmitTimestamp - [client]responseTimestamp)) / 2
+ //
+ // See the NTP spec and tests: the numeric types used are deliberate:
+ // + Duration64.between() uses 64-bit arithmetic (32-bit for the seconds).
+ // + plus() / dividedBy() use Duration, which isn't the double precision floating point
+ // used in NTPv4, but is good enough.
+ return Duration64.between(clientRequestTimestamp, serverReceiveTimestamp)
+ .plus(Duration64.between(clientResponseTimestamp, serverTransmitTimestamp))
+ .dividedBy(2);
+ }
+
@Deprecated
@UnsupportedAppUsage
public boolean requestTime(String host, int timeout) {
@@ -194,6 +243,14 @@
}
/**
+ * Returns the offset calculated to apply to the client clock to arrive at {@link #getNtpTime()}
+ */
+ @VisibleForTesting
+ public long getClockOffset() {
+ return mClockOffset;
+ }
+
+ /**
* Returns the time computed from the NTP transaction.
*
* @return time value computed from NTP server response.
@@ -225,8 +282,9 @@
}
private static void checkValidServerReply(
- byte leap, byte mode, int stratum, long transmitTime, long referenceTime)
- throws InvalidServerReplyException {
+ byte leap, byte mode, int stratum, Timestamp64 transmitTimestamp,
+ Timestamp64 referenceTimestamp, Timestamp64 randomizedRequestTimestamp,
+ Timestamp64 originateTimestamp) throws InvalidServerReplyException {
if (leap == NTP_LEAP_NOSYNC) {
throw new InvalidServerReplyException("unsynchronized server");
}
@@ -236,73 +294,68 @@
if ((stratum == NTP_STRATUM_DEATH) || (stratum > NTP_STRATUM_MAX)) {
throw new InvalidServerReplyException("untrusted stratum: " + stratum);
}
- if (transmitTime == 0) {
- throw new InvalidServerReplyException("zero transmitTime");
+ if (!randomizedRequestTimestamp.equals(originateTimestamp)) {
+ throw new InvalidServerReplyException(
+ "originateTimestamp != randomizedRequestTimestamp");
}
- if (referenceTime == 0) {
- throw new InvalidServerReplyException("zero reference timestamp");
+ if (transmitTimestamp.equals(Timestamp64.ZERO)) {
+ throw new InvalidServerReplyException("zero transmitTimestamp");
+ }
+ if (referenceTimestamp.equals(Timestamp64.ZERO)) {
+ throw new InvalidServerReplyException("zero referenceTimestamp");
}
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
- private long read32(byte[] buffer, int offset) {
- byte b0 = buffer[offset];
- byte b1 = buffer[offset+1];
- byte b2 = buffer[offset+2];
- byte b3 = buffer[offset+3];
+ private long readUnsigned32(byte[] buffer, int offset) {
+ int i0 = buffer[offset++] & 0xFF;
+ int i1 = buffer[offset++] & 0xFF;
+ int i2 = buffer[offset++] & 0xFF;
+ int i3 = buffer[offset] & 0xFF;
- // convert signed bytes to unsigned values
- int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
- int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
- int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
- int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
-
- return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
+ int bits = (i0 << 24) | (i1 << 16) | (i2 << 8) | i3;
+ return bits & 0xFFFF_FFFFL;
}
/**
- * Reads the NTP time stamp at the given offset in the buffer and returns
- * it as a system time (milliseconds since January 1, 1970).
+ * Reads the NTP time stamp from the given offset in the buffer.
*/
- private long readTimeStamp(byte[] buffer, int offset) {
- long seconds = read32(buffer, offset);
- long fraction = read32(buffer, offset + 4);
- // Special case: zero means zero.
- if (seconds == 0 && fraction == 0) {
- return 0;
- }
- return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
+ private Timestamp64 readTimeStamp(byte[] buffer, int offset) {
+ long seconds = readUnsigned32(buffer, offset);
+ int fractionBits = (int) readUnsigned32(buffer, offset + 4);
+ return Timestamp64.fromComponents(seconds, fractionBits);
}
/**
- * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp
- * at the given offset in the buffer.
+ * Writes the NTP time stamp at the given offset in the buffer.
*/
- private void writeTimeStamp(byte[] buffer, int offset, long time) {
- // Special case: zero means zero.
- if (time == 0) {
- Arrays.fill(buffer, offset, offset + 8, (byte) 0x00);
- return;
- }
-
- long seconds = time / 1000L;
- long milliseconds = time - seconds * 1000L;
- seconds += OFFSET_1900_TO_1970;
-
+ private void writeTimeStamp(byte[] buffer, int offset, Timestamp64 timestamp) {
+ long seconds = timestamp.getEraSeconds();
// write seconds in big endian format
- buffer[offset++] = (byte)(seconds >> 24);
- buffer[offset++] = (byte)(seconds >> 16);
- buffer[offset++] = (byte)(seconds >> 8);
- buffer[offset++] = (byte)(seconds >> 0);
+ buffer[offset++] = (byte) (seconds >>> 24);
+ buffer[offset++] = (byte) (seconds >>> 16);
+ buffer[offset++] = (byte) (seconds >>> 8);
+ buffer[offset++] = (byte) (seconds);
- long fraction = milliseconds * 0x100000000L / 1000L;
+ int fractionBits = timestamp.getFractionBits();
// write fraction in big endian format
- buffer[offset++] = (byte)(fraction >> 24);
- buffer[offset++] = (byte)(fraction >> 16);
- buffer[offset++] = (byte)(fraction >> 8);
- // low order bits should be random data
- buffer[offset++] = (byte)(Math.random() * 255.0);
+ buffer[offset++] = (byte) (fractionBits >>> 24);
+ buffer[offset++] = (byte) (fractionBits >>> 16);
+ buffer[offset++] = (byte) (fractionBits >>> 8);
+ buffer[offset] = (byte) (fractionBits);
+ }
+
+ private static Random defaultRandom() {
+ Random random;
+ try {
+ random = SecureRandom.getInstanceStrong();
+ } catch (NoSuchAlgorithmException e) {
+ // This should never happen.
+ Slog.wtf(TAG, "Unable to access SecureRandom", e);
+ random = new Random(System.currentTimeMillis());
+ }
+ return random;
}
}
diff --git a/core/java/android/net/TEST_MAPPING b/core/java/android/net/TEST_MAPPING
index 8c13ef9..a379c33 100644
--- a/core/java/android/net/TEST_MAPPING
+++ b/core/java/android/net/TEST_MAPPING
@@ -16,5 +16,24 @@
{
"path": "frameworks/opt/net/wifi"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.net"
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
]
}
diff --git a/core/java/android/net/sntp/Duration64.java b/core/java/android/net/sntp/Duration64.java
new file mode 100644
index 0000000..7f29cdb
--- /dev/null
+++ b/core/java/android/net/sntp/Duration64.java
@@ -0,0 +1,141 @@
+/*
+ * 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.sntp;
+
+import java.time.Duration;
+
+/**
+ * A type similar to {@link Timestamp64} but used when calculating the difference between two
+ * timestamps. As such, it is a signed type, but still uses 64-bits in total and so can only
+ * represent half the magnitude of {@link Timestamp64}.
+ *
+ * <p>See <a href="https://www.eecis.udel.edu/~mills/time.html">4. Time Difference Calculations</a>.
+ *
+ * @hide
+ */
+public final class Duration64 {
+
+ public static final Duration64 ZERO = new Duration64(0);
+ private final long mBits;
+
+ private Duration64(long bits) {
+ this.mBits = bits;
+ }
+
+ /**
+ * Returns the difference between two 64-bit NTP timestamps as a {@link Duration64}, as
+ * described in the NTP spec. The times represented by the timestamps have to be within {@link
+ * Timestamp64#MAX_SECONDS_IN_ERA} (~68 years) of each other for the calculation to produce a
+ * correct answer.
+ */
+ public static Duration64 between(Timestamp64 startInclusive, Timestamp64 endExclusive) {
+ long oneBits = (startInclusive.getEraSeconds() << 32)
+ | (startInclusive.getFractionBits() & 0xFFFF_FFFFL);
+ long twoBits = (endExclusive.getEraSeconds() << 32)
+ | (endExclusive.getFractionBits() & 0xFFFF_FFFFL);
+ long resultBits = twoBits - oneBits;
+ return new Duration64(resultBits);
+ }
+
+ /**
+ * Add two {@link Duration64} instances together. This performs the calculation in {@link
+ * Duration} and returns a {@link Duration} to increase the magnitude of accepted arguments,
+ * since {@link Duration64} only supports signed 32-bit seconds. The use of {@link Duration}
+ * limits precision to nanoseconds.
+ */
+ public Duration plus(Duration64 other) {
+ // From https://www.eecis.udel.edu/~mills/time.html:
+ // "The offset and delay calculations require sums and differences of these raw timestamp
+ // differences that can span no more than from 34 years in the future to 34 years in the
+ // past without overflow. This is a fundamental limitation in 64-bit integer calculations.
+ //
+ // In the NTPv4 reference implementation, all calculations involving offset and delay values
+ // use 64-bit floating double arithmetic, with the exception of raw timestamp subtraction,
+ // as mentioned above. The raw timestamp differences are then converted to 64-bit floating
+ // double format without loss of precision or chance of overflow in subsequent
+ // calculations."
+ //
+ // Here, we use Duration instead, which provides sufficient range, but loses precision below
+ // nanos.
+ return this.toDuration().plus(other.toDuration());
+ }
+
+ /**
+ * Returns a {@link Duration64} equivalent of the supplied duration, if the magnitude can be
+ * represented. Because {@link Duration64} uses a fixed point type for sub-second values it
+ * cannot represent all nanosecond values precisely and so the conversion can be lossy.
+ *
+ * @throws IllegalArgumentException if the supplied duration is too big to be represented
+ */
+ public static Duration64 fromDuration(Duration duration) {
+ long seconds = duration.getSeconds();
+ if (seconds < Integer.MIN_VALUE || seconds > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException();
+ }
+ long bits = (seconds << 32)
+ | (Timestamp64.nanosToFractionBits(duration.getNano()) & 0xFFFF_FFFFL);
+ return new Duration64(bits);
+ }
+
+ /**
+ * Returns a {@link Duration} equivalent of this duration. Because {@link Duration64} uses a
+ * fixed point type for sub-second values it can values smaller than nanosecond precision and so
+ * the conversion can be lossy.
+ */
+ public Duration toDuration() {
+ int seconds = getSeconds();
+ int nanos = getNanos();
+ return Duration.ofSeconds(seconds, nanos);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Duration64 that = (Duration64) o;
+ return mBits == that.mBits;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(mBits);
+ }
+
+ @Override
+ public String toString() {
+ Duration duration = toDuration();
+ return Long.toHexString(mBits)
+ + "(" + duration.getSeconds() + "s " + duration.getNano() + "ns)";
+ }
+
+ /**
+ * Returns the <em>signed</em> seconds in this duration.
+ */
+ public int getSeconds() {
+ return (int) (mBits >> 32);
+ }
+
+ /**
+ * Returns the <em>unsigned</em> nanoseconds in this duration (truncated).
+ */
+ public int getNanos() {
+ return Timestamp64.fractionBitsToNanos((int) (mBits & 0xFFFF_FFFFL));
+ }
+}
diff --git a/core/java/android/net/sntp/OWNERS b/core/java/android/net/sntp/OWNERS
new file mode 100644
index 0000000..9a3e264
--- /dev/null
+++ b/core/java/android/net/sntp/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/timedetector/OWNERS
diff --git a/core/java/android/net/sntp/Timestamp64.java b/core/java/android/net/sntp/Timestamp64.java
new file mode 100644
index 0000000..8ddfd77
--- /dev/null
+++ b/core/java/android/net/sntp/Timestamp64.java
@@ -0,0 +1,188 @@
+/*
+ * 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.sntp;
+
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.time.Instant;
+import java.util.Objects;
+import java.util.Random;
+
+/**
+ * The 64-bit type ("timestamp") that NTP uses to represent a point in time. It only holds the
+ * lowest 32-bits of the number of seconds since 1900-01-01 00:00:00. Consequently, to turn an
+ * instance into an unambiguous point in time the era number must be known. Era zero runs from
+ * 1900-01-01 00:00:00 to a date in 2036.
+ *
+ * It stores sub-second values using a 32-bit fixed point type, so it can resolve values smaller
+ * than a nanosecond, but is imprecise (i.e. it truncates).
+ *
+ * See also <a href=https://www.eecis.udel.edu/~mills/y2k.html>NTP docs</a>.
+ *
+ * @hide
+ */
+public final class Timestamp64 {
+
+ public static final Timestamp64 ZERO = fromComponents(0, 0);
+ static final int SUB_MILLIS_BITS_TO_RANDOMIZE = 32 - 10;
+
+ // Number of seconds between Jan 1, 1900 and Jan 1, 1970
+ // 70 years plus 17 leap days
+ static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
+ static final long MAX_SECONDS_IN_ERA = 0xFFFF_FFFFL;
+ static final long SECONDS_IN_ERA = MAX_SECONDS_IN_ERA + 1;
+
+ static final int NANOS_PER_SECOND = 1_000_000_000;
+
+ /** Creates a {@link Timestamp64} from the seconds and fraction components. */
+ public static Timestamp64 fromComponents(long eraSeconds, int fractionBits) {
+ return new Timestamp64(eraSeconds, fractionBits);
+ }
+
+ /** Creates a {@link Timestamp64} by decoding a string in the form "e4dc720c.4d4fc9eb". */
+ public static Timestamp64 fromString(String string) {
+ final int requiredLength = 17;
+ if (string.length() != requiredLength || string.charAt(8) != '.') {
+ throw new IllegalArgumentException(string);
+ }
+ String eraSecondsString = string.substring(0, 8);
+ String fractionString = string.substring(9);
+ long eraSeconds = Long.parseLong(eraSecondsString, 16);
+
+ // Use parseLong() because the type is unsigned. Integer.parseInt() will reject 0x70000000
+ // or above as being out of range.
+ long fractionBitsAsLong = Long.parseLong(fractionString, 16);
+ if (fractionBitsAsLong < 0 || fractionBitsAsLong > 0xFFFFFFFFL) {
+ throw new IllegalArgumentException("Invalid fractionBits:" + fractionString);
+ }
+ return new Timestamp64(eraSeconds, (int) fractionBitsAsLong);
+ }
+
+ /**
+ * Converts an {@link Instant} into a {@link Timestamp64}. This is lossy: Timestamp64 only
+ * contains the number of seconds in a given era, but the era is not stored. Also, sub-second
+ * values are not stored precisely.
+ */
+ public static Timestamp64 fromInstant(Instant instant) {
+ long ntpEraSeconds = instant.getEpochSecond() + OFFSET_1900_TO_1970;
+ if (ntpEraSeconds < 0) {
+ ntpEraSeconds = SECONDS_IN_ERA - (-ntpEraSeconds % SECONDS_IN_ERA);
+ }
+ ntpEraSeconds %= SECONDS_IN_ERA;
+
+ long nanos = instant.getNano();
+ int fractionBits = nanosToFractionBits(nanos);
+
+ return new Timestamp64(ntpEraSeconds, fractionBits);
+ }
+
+ private final long mEraSeconds;
+ private final int mFractionBits;
+
+ private Timestamp64(long eraSeconds, int fractionBits) {
+ if (eraSeconds < 0 || eraSeconds > MAX_SECONDS_IN_ERA) {
+ throw new IllegalArgumentException(
+ "Invalid parameters. seconds=" + eraSeconds + ", fraction=" + fractionBits);
+ }
+ this.mEraSeconds = eraSeconds;
+ this.mFractionBits = fractionBits;
+ }
+
+ /** Returns the number of seconds in the NTP era. */
+ public long getEraSeconds() {
+ return mEraSeconds;
+ }
+
+ /** Returns the fraction of a second as 32-bit, unsigned fixed-point bits. */
+ public int getFractionBits() {
+ return mFractionBits;
+ }
+
+ @Override
+ public String toString() {
+ return TextUtils.formatSimple("%08x.%08x", mEraSeconds, mFractionBits);
+ }
+
+ /** Returns the instant represented by this value in the specified NTP era. */
+ public Instant toInstant(int ntpEra) {
+ long secondsSinceEpoch = mEraSeconds - OFFSET_1900_TO_1970;
+ secondsSinceEpoch += ntpEra * SECONDS_IN_ERA;
+
+ int nanos = fractionBitsToNanos(mFractionBits);
+ return Instant.ofEpochSecond(secondsSinceEpoch, nanos);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Timestamp64 that = (Timestamp64) o;
+ return mEraSeconds == that.mEraSeconds && mFractionBits == that.mFractionBits;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEraSeconds, mFractionBits);
+ }
+
+ static int fractionBitsToNanos(int fractionBits) {
+ long fractionBitsLong = fractionBits & 0xFFFF_FFFFL;
+ return (int) ((fractionBitsLong * NANOS_PER_SECOND) >>> 32);
+ }
+
+ static int nanosToFractionBits(long nanos) {
+ if (nanos > NANOS_PER_SECOND) {
+ throw new IllegalArgumentException();
+ }
+ return (int) ((nanos << 32) / NANOS_PER_SECOND);
+ }
+
+ /**
+ * Randomizes the fraction bits that represent sub-millisecond values. i.e. the randomization
+ * won't change the number of milliseconds represented after truncation. This is used to
+ * implement the part of the NTP spec that calls for clients with millisecond accuracy clocks
+ * to send randomized LSB values rather than zeros.
+ */
+ public Timestamp64 randomizeSubMillis(Random random) {
+ int randomizedFractionBits =
+ randomizeLowestBits(random, this.mFractionBits, SUB_MILLIS_BITS_TO_RANDOMIZE);
+ return new Timestamp64(mEraSeconds, randomizedFractionBits);
+ }
+
+ /**
+ * Randomizes the specified number of LSBs in {@code value} by using replacement bits from
+ * {@code Random.getNextInt()}.
+ */
+ @VisibleForTesting
+ public static int randomizeLowestBits(Random random, int value, int bitsToRandomize) {
+ if (bitsToRandomize < 1 || bitsToRandomize >= Integer.SIZE) {
+ // There's no point in randomizing all bits or none of the bits.
+ throw new IllegalArgumentException(Integer.toString(bitsToRandomize));
+ }
+
+ int upperBitMask = 0xFFFF_FFFF << bitsToRandomize;
+ int lowerBitMask = ~upperBitMask;
+
+ int randomValue = random.nextInt();
+ return (value & upperBitMask) | (randomValue & lowerBitMask);
+ }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 635f581..b677b69 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -313,7 +313,7 @@
* @hide
*/
@CriticalNative
- public static final native boolean isHandlingTransaction();
+ public static final native boolean isDirectlyHandlingTransaction();
/**
* Return the Linux uid assigned to the process that sent the transaction
@@ -323,7 +323,7 @@
* executing an incoming transaction.
*/
public static final int getCallingUidOrThrow() {
- if (!isHandlingTransaction()) {
+ if (!isDirectlyHandlingTransaction()) {
throw new IllegalStateException(
"Thread is not in a binder transcation");
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index e7c3a83..92861fb 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -1,18 +1,18 @@
# Haptics
-per-file CombinedVibrationEffect.aidl = michaelwr@google.com
-per-file CombinedVibrationEffect.java = michaelwr@google.com
-per-file ExternalVibration.aidl = michaelwr@google.com
-per-file ExternalVibration.java = michaelwr@google.com
-per-file IExternalVibrationController.aidl = michaelwr@google.com
-per-file IExternalVibratorService.aidl = michaelwr@google.com
-per-file IVibratorManagerService.aidl = michaelwr@google.com
-per-file NullVibrator.java = michaelwr@google.com
-per-file SystemVibrator.java = michaelwr@google.com
-per-file SystemVibratorManager.java = michaelwr@google.com
-per-file VibrationEffect.aidl = michaelwr@google.com
-per-file VibrationEffect.java = michaelwr@google.com
-per-file Vibrator.java = michaelwr@google.com
-per-file VibratorManager.java = michaelwr@google.com
+per-file CombinedVibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file CombinedVibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file ExternalVibration.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file ExternalVibration.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file IExternalVibrationController.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file IExternalVibratorService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file IVibratorManagerService.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file NullVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file SystemVibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file SystemVibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file VibrationEffect.aidl = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file VibrationEffect.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file Vibrator.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file VibratorManager.java = file:/services/core/java/com/android/server/vibrator/OWNERS
# PowerManager
per-file IPowerManager.aidl = michaelwr@google.com, santoscordon@google.com
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 44d51db..ab2c8c0 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -384,6 +384,8 @@
long thisNativePtr, long otherNativePtr, int offset, int length);
@CriticalNative
private static native boolean nativeHasFileDescriptors(long nativePtr);
+ private static native boolean nativeHasFileDescriptorsInRange(
+ long nativePtr, int offset, int length);
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
@@ -399,7 +401,7 @@
private static final int WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS = 1000;
@CriticalNative
- private static native long nativeGetBlobAshmemSize(long nativePtr);
+ private static native long nativeGetOpenAshmemSize(long nativePtr);
public final static Parcelable.Creator<String> STRING_CREATOR
= new Parcelable.Creator<String>() {
@@ -717,11 +719,26 @@
/**
* Report whether the parcel contains any marshalled file descriptors.
*/
- public final boolean hasFileDescriptors() {
+ public boolean hasFileDescriptors() {
return nativeHasFileDescriptors(mNativePtr);
}
/**
+ * Report whether the parcel contains any marshalled file descriptors in the range defined by
+ * {@code offset} and {@code length}.
+ *
+ * @param offset The offset from which the range starts. Should be between 0 and
+ * {@link #dataSize()}.
+ * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code
+ * offset}.
+ * @return whether there are file descriptors or not.
+ * @throws IllegalArgumentException if the parameters are out of the permitted ranges.
+ */
+ public boolean hasFileDescriptors(int offset, int length) {
+ return nativeHasFileDescriptorsInRange(mNativePtr, offset, length);
+ }
+
+ /**
* Check if the object used in {@link #readValue(ClassLoader)} / {@link #writeValue(Object)}
* has file descriptors.
*
@@ -2874,9 +2891,11 @@
/**
* Same as {@link #readList(List, ClassLoader)} but accepts {@code clazz} parameter as
- * the type required for each item. If the item to be deserialized is not an instance
- * of that class or any of its children class
- * a {@link BadParcelableException} will be thrown.
+ * the type required for each item.
+ *
+ * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
+ * is not an instance of that class or any of its children classes or there was an error
+ * trying to instantiate an element.
*/
public <T> void readList(@NonNull List<? super T> outVal,
@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
@@ -3536,15 +3555,26 @@
int start = dataPosition();
int type = readInt();
if (isLengthPrefixed(type)) {
- int length = readInt();
- setDataPosition(MathUtils.addOrThrow(dataPosition(), length));
- return new LazyValue(this, start, length, type, loader);
+ int objectLength = readInt();
+ int end = MathUtils.addOrThrow(dataPosition(), objectLength);
+ int valueLength = end - start;
+ setDataPosition(end);
+ return new LazyValue(this, start, valueLength, type, loader);
} else {
return readValue(type, loader, /* clazz */ null);
}
}
+
private static final class LazyValue implements Supplier<Object> {
+ /**
+ * | 4B | 4B |
+ * mSource = Parcel{... | type | length | object | ...}
+ * a b c d
+ * length = d - c
+ * mPosition = a
+ * mLength = d - a
+ */
private final int mPosition;
private final int mLength;
private final int mType;
@@ -3592,7 +3622,7 @@
public void writeToParcel(Parcel out) {
Parcel source = mSource;
if (source != null) {
- out.appendFrom(source, mPosition, mLength + 8);
+ out.appendFrom(source, mPosition, mLength);
} else {
out.writeValue(mObject);
}
@@ -3601,7 +3631,7 @@
public boolean hasFileDescriptors() {
Parcel source = mSource;
return (source != null)
- ? getValueParcel(source).hasFileDescriptors()
+ ? source.hasFileDescriptors(mPosition, mLength)
: Parcel.hasFileDescriptors(mObject);
}
@@ -3662,10 +3692,7 @@
Parcel parcel = mValueParcel;
if (parcel == null) {
parcel = Parcel.obtain();
- // mLength is the length of object representation, excluding the type and length.
- // mPosition is the position of the entire value container, right before the type.
- // So, we add 4 bytes for the type + 4 bytes for the length written.
- parcel.appendFrom(source, mPosition, mLength + 8);
+ parcel.appendFrom(source, mPosition, mLength);
mValueParcel = parcel;
}
return parcel;
@@ -3869,8 +3896,11 @@
/**
* Same as {@link #readParcelable(ClassLoader)} but accepts {@code clazz} parameter as the type
- * required for each item. If the item to be deserialized is not an instance of that class or
- * any of its children classes a {@link BadParcelableException} will be thrown.
+ * required for each item.
+ *
+ * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
+ * is not an instance of that class or any of its children classes or there was an error
+ * trying to instantiate an element.
*/
@Nullable
public <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader,
@@ -3936,8 +3966,11 @@
/**
* Same as {@link #readParcelableCreator(ClassLoader)} but accepts {@code clazz} parameter
- * as the required type. If the item to be deserialized is not an instance of that class
- * or any of its children classes a {@link BadParcelableException} will be thrown.
+ * as the required type.
+ *
+ * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
+ * is not an instance of that class or any of its children class or there there was an error
+ * trying to read the {@link Parcelable.Creator}.
*/
@Nullable
public <T> Parcelable.Creator<T> readParcelableCreator(
@@ -4348,8 +4381,8 @@
/**
* @hide For testing
*/
- public long getBlobAshmemSize() {
- return nativeGetBlobAshmemSize(mNativePtr);
+ public long getOpenAshmemSize() {
+ return nativeGetOpenAshmemSize(mNativePtr);
}
private static String valueTypeToString(int type) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 51f19eb..b4acb67 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -706,6 +706,25 @@
/**
* Contains the recent calls.
+ * <p>
+ * Note: If you want to query the call log and limit the results to a single value, you should
+ * append the {@link #LIMIT_PARAM_KEY} parameter to the content URI. For example:
+ * <pre>
+ * {@code
+ * getContentResolver().query(
+ * Calls.CONTENT_URI.buildUpon().appendQueryParameter(LIMIT_PARAM_KEY, "1")
+ * .build(),
+ * null, null, null, null);
+ * }
+ * </pre>
+ * <p>
+ * The call log provider enforces strict SQL grammar, so you CANNOT append "LIMIT" to the SQL
+ * query as below:
+ * <pre>
+ * {@code
+ * getContentResolver().query(Calls.CONTENT_URI, null, "LIMIT 1", null, null);
+ * }
+ * </pre>
*/
public static class Calls implements BaseColumns {
/**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 0f0f123..eda3699 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -37,6 +37,7 @@
import android.content.ContextWrapper;
import android.content.CursorEntityIterator;
import android.content.Entity;
+import android.content.Entity.NamedContentValues;
import android.content.EntityIterator;
import android.content.Intent;
import android.content.IntentFilter;
@@ -55,6 +56,7 @@
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.Pair;
import android.view.View;
@@ -64,7 +66,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -5135,6 +5139,8 @@
*/
public final static class RawContactsEntity
implements BaseColumns, DataColumns, RawContactsColumns {
+ private static final String TAG = "ContactsContract.RawContactsEntity";
+
/**
* This utility class cannot be instantiated
*/
@@ -5187,6 +5193,73 @@
* <P>Type: INTEGER</P>
*/
public static final String DATA_ID = "data_id";
+
+ /**
+ * Query raw contacts entity by a contact ID, which can potentially be a corp profile
+ * contact ID
+ *
+ * @param context A context to get the ContentResolver from
+ * @param contactId Contact ID, which can potentialy be a corp profile contact ID.
+ *
+ * @return A map from a mimetype to a List of the entity content values.
+ * {@hide}
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ public static @NonNull Map<String, List<ContentValues>> queryRawContactEntity(
+ @NonNull ContentResolver contentResolver, long contactId) {
+ Uri uri = RawContactsEntity.CONTENT_URI;
+ long realContactId = contactId;
+
+ if (Contacts.isEnterpriseContactId(contactId)) {
+ uri = RawContactsEntity.CORP_CONTENT_URI;
+ realContactId = contactId - Contacts.ENTERPRISE_CONTACT_ID_BASE;
+ }
+ final Map<String, List<ContentValues>> contentValuesListMap =
+ new HashMap<String, List<ContentValues>>();
+ // The resolver may return the entity iterator with no data. It is possible.
+ // e.g. If all the data in the contact of the given contact id are not exportable ones,
+ // they are hidden from the view of this method, though contact id itself exists.
+ EntityIterator entityIterator = null;
+ try {
+ final String selection = Data.CONTACT_ID + "=?";
+ final String[] selectionArgs = new String[] {String.valueOf(realContactId)};
+
+ entityIterator = RawContacts.newEntityIterator(contentResolver.query(
+ uri, null, selection, selectionArgs, null));
+
+ if (entityIterator == null) {
+ Log.e(TAG, "EntityIterator is null");
+ return contentValuesListMap;
+ }
+
+ if (!entityIterator.hasNext()) {
+ Log.w(TAG, "Data does not exist. contactId: " + realContactId);
+ return contentValuesListMap;
+ }
+
+ while (entityIterator.hasNext()) {
+ Entity entity = entityIterator.next();
+ for (NamedContentValues namedContentValues : entity.getSubValues()) {
+ ContentValues contentValues = namedContentValues.values;
+ String key = contentValues.getAsString(Data.MIMETYPE);
+ if (key != null) {
+ List<ContentValues> contentValuesList = contentValuesListMap.get(key);
+ if (contentValuesList == null) {
+ contentValuesList = new ArrayList<ContentValues>();
+ contentValuesListMap.put(key, contentValuesList);
+ }
+ contentValuesList.add(contentValues);
+ }
+ }
+ }
+ } finally {
+ if (entityIterator != null) {
+ entityIterator.close();
+ }
+ }
+ return contentValuesListMap;
+ }
}
/**
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index f5f5eb8..25e3a4f 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -298,6 +298,14 @@
public static final String NAMESPACE_NETD_NATIVE = "netd_native";
/**
+ * Namespace for all Android NNAPI related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_NNAPI_NATIVE = "nnapi_native";
+
+ /**
* Namespace for features related to the Package Manager Service.
*
* @hide
diff --git a/core/java/android/service/timezone/OWNERS b/core/java/android/service/timezone/OWNERS
index 28aff18..b5144d1 100644
--- a/core/java/android/service/timezone/OWNERS
+++ b/core/java/android/service/timezone/OWNERS
@@ -1,3 +1,3 @@
# Bug component: 847766
-nfuller@google.com
-include /core/java/android/app/timedetector/OWNERS
+# System APIs for system server time zone detection plugins.
+include /services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index dd4de0a..3028a6d 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -691,6 +691,11 @@
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ *
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
void onMessageWaitingIndicatorChanged(boolean mwi);
@@ -710,6 +715,11 @@
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ *
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
void onCallForwardingIndicatorChanged(boolean cfi);
@@ -868,6 +878,10 @@
* subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+ *
* @param callState {@link PreciseCallState}
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -910,6 +924,10 @@
* subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+ *
* @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -932,9 +950,9 @@
* subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
*
* @param dataConnectionState {@link PreciseDataConnectionState}
*/
@@ -1063,6 +1081,10 @@
* given subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ *
* @param emergencyNumberList Map associating all active subscriptions on the device with
* the list of emergency numbers originating from that
* subscription.
@@ -1157,6 +1179,11 @@
* For example, it could be the current active opportunistic subscription
* in use, or the subscription user selected as default data subscription in
* DSDS mode.
+ *
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PHONE_STATE}.
+ *
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
void onActiveDataSubscriptionIdChanged(int subId);
@@ -1225,6 +1252,11 @@
* <p>Because registration failures are ephemeral, this callback is not sticky.
* Registrants will not receive the most recent past value when registering.
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} and
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
+ *
* @param cellIdentity the CellIdentity, which must include the globally unique
* identifier
* for the cell (for example, all components of the CGI or ECGI).
@@ -1308,6 +1340,10 @@
* subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+ *
* @param callAttributes the call attributes
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -1324,6 +1360,11 @@
* <p>Barring info is provided for all services applicable to the current camped/registered
* cell, for the registered PLMN and current access class/access category.
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} and
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
+ *
* @param barringInfo for all services on the current cell.
* @see android.telephony.BarringInfo
*/
@@ -1341,6 +1382,10 @@
/**
* Callback invoked when the current physical channel configuration has changed
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+ *
* @param configs List of the current {@link PhysicalChannelConfig}s
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -1357,6 +1402,10 @@
/**
* Callback invoked when the data enabled changes.
*
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+ *
* @param enabled {@code true} if data is enabled, otherwise disabled.
* @param reason Reason for data enabled/disabled.
* See {@link TelephonyManager.DataEnabledReason}.
diff --git a/core/java/android/timezone/OWNERS b/core/java/android/timezone/OWNERS
index 8f80897..8b5e156 100644
--- a/core/java/android/timezone/OWNERS
+++ b/core/java/android/timezone/OWNERS
@@ -1,3 +1,5 @@
-# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# Bug component: 24949
+# APIs originally intended to provide a stable API surface to access time zone rules data for use by
+# unbundled components like a telephony mainline module and the ART module. Not exposed, potentially
+# deletable if callers do not unbundle.
+include platform/libcore:/OWNERS
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8c63f38..630851d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12143,7 +12143,7 @@
rxTimeMs = info.getControllerRxTimeMillis();
txTimeMs = info.getControllerTxTimeMillis();
energy = info.getControllerEnergyUsed();
- if (info.getUidTraffic() != null) {
+ if (!info.getUidTraffic().isEmpty()) {
for (UidTraffic traffic : info.getUidTraffic()) {
uidRxBytes.put(traffic.getUid(), traffic.getRxBytes());
uidTxBytes.put(traffic.getUid(), traffic.getTxBytes());
@@ -12294,10 +12294,10 @@
long totalTxBytes = 0;
long totalRxBytes = 0;
- final UidTraffic[] uidTraffic = info.getUidTraffic();
- final int numUids = uidTraffic != null ? uidTraffic.length : 0;
+ final List<UidTraffic> uidTraffic = info.getUidTraffic();
+ final int numUids = uidTraffic.size();
for (int i = 0; i < numUids; i++) {
- final UidTraffic traffic = uidTraffic[i];
+ final UidTraffic traffic = uidTraffic.get(i);
final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(
traffic.getUid());
final long txBytes = traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(
@@ -12320,7 +12320,7 @@
if ((totalTxBytes != 0 || totalRxBytes != 0) && (leftOverRxTimeMs != 0
|| leftOverTxTimeMs != 0)) {
for (int i = 0; i < numUids; i++) {
- final UidTraffic traffic = uidTraffic[i];
+ final UidTraffic traffic = uidTraffic.get(i);
final int uid = traffic.getUid();
final long rxBytes =
traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(uid);
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index aadd320..be9aaaf 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -596,13 +596,10 @@
jlong otherNativePtr)
{
Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
- if (thisParcel == NULL) {
- return 0;
- }
+ LOG_ALWAYS_FATAL_IF(thisParcel == nullptr, "Should not be null");
+
Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
- if (otherParcel == NULL) {
- return thisParcel->getOpenAshmemSize();
- }
+ LOG_ALWAYS_FATAL_IF(otherParcel == nullptr, "Should not be null");
return thisParcel->compareData(*otherParcel);
}
@@ -638,6 +635,22 @@
return ret;
}
+static jboolean android_os_Parcel_hasFileDescriptorsInRange(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint offset,
+ jint length) {
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ if (parcel != NULL) {
+ bool result;
+ status_t err = parcel->hasFileDescriptorsInRange(offset, length, &result);
+ if (err != NO_ERROR) {
+ signalExceptionForError(env, clazz, err);
+ return JNI_FALSE;
+ }
+ return result ? JNI_TRUE : JNI_FALSE;
+ }
+ return JNI_FALSE;
+}
+
// String tries to allocate itself on the stack, within a known size, but will
// make a heap allocation if not.
template <size_t StackReserve>
@@ -727,11 +740,11 @@
return Parcel::getGlobalAllocCount();
}
-static jlong android_os_Parcel_getBlobAshmemSize(jlong nativePtr)
+static jlong android_os_Parcel_getOpenAshmemSize(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
- return parcel->getBlobAshmemSize();
+ return parcel->getOpenAshmemSize();
}
return 0;
}
@@ -831,6 +844,7 @@
{"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom},
// @CriticalNative
{"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
+ {"nativeHasFileDescriptorsInRange", "(JII)Z", (void*)android_os_Parcel_hasFileDescriptorsInRange},
{"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
{"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
@@ -838,7 +852,7 @@
{"getGlobalAllocCount", "()J", (void*)android_os_Parcel_getGlobalAllocCount},
// @CriticalNative
- {"nativeGetBlobAshmemSize", "(J)J", (void*)android_os_Parcel_getBlobAshmemSize},
+ {"nativeGetOpenAshmemSize", "(J)J", (void*)android_os_Parcel_getOpenAshmemSize},
// @CriticalNative
{"nativeReadCallingWorkSourceUid", "(J)I", (void*)android_os_Parcel_readCallingWorkSourceUid},
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 793b4eb..61b91dd 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -959,8 +959,7 @@
return IPCThreadState::self()->getCallingUid();
}
-static jboolean android_os_Binder_isHandlingTransaction()
-{
+static jboolean android_os_Binder_isDirectlyHandlingTransaction() {
return getCurrentServingCall() == BinderCallType::BINDER;
}
@@ -1056,6 +1055,7 @@
// ----------------------------------------------------------------------------
+// clang-format off
static const JNINativeMethod gBinderMethods[] = {
/* name, signature, funcPtr */
// @CriticalNative
@@ -1063,7 +1063,7 @@
// @CriticalNative
{ "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
// @CriticalNative
- { "isHandlingTransaction", "()Z", (void*)android_os_Binder_isHandlingTransaction },
+ { "isDirectlyHandlingTransaction", "()Z", (void*)android_os_Binder_isDirectlyHandlingTransaction },
// @CriticalNative
{ "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
// @CriticalNative
@@ -1088,6 +1088,7 @@
{ "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
{ "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
};
+// clang-format on
const char* const kBinderPathName = "android/os/Binder";
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 44ea23f..78650ed 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -8,9 +8,6 @@
yro@google.com
zhouwenjie@google.com
-# Settings UI
-per-file settings_enums.proto=tmfang@google.com
-
# Frameworks
ogunwale@google.com
jjaggi@google.com
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bd89578..1418dbe 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1976,6 +1976,14 @@
android:label="@string/permlab_uwb_ranging"
android:protectionLevel="dangerous" />
+ <!-- Required to be able to advertise and connect to nearby devices via Wi-Fi.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.NEARBY_WIFI_DEVICES"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:description="@string/permdesc_nearby_wifi_devices"
+ android:label="@string/permlab_nearby_wifi_devices"
+ android:protectionLevel="dangerous" />
+
<!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the
user from using them until they are unsuspended.
@hide
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 684202b..165dcad 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -28,3 +28,6 @@
# Multiuser
per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
+
+# Car
+per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
\ No newline at end of file
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a99a220..a350d14 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1488,6 +1488,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]-->
<string name="permdesc_uwb_ranging">Allow the app to determine relative position between nearby Ultra-Wideband devices</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50]-->
+ <string name="permlab_nearby_wifi_devices">interact with nearby Wi\u2011Fi devices</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=120]-->
+ <string name="permdesc_nearby_wifi_devices">Allows the app to advertise, connect, and determine the relative position of nearby Wi\u2011Fi devices</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_preferredPaymentInfo">Preferred NFC Payment Service Information</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/companiontests/Android.bp b/core/tests/companiontests/Android.bp
new file mode 100644
index 0000000..d31b8f4
--- /dev/null
+++ b/core/tests/companiontests/Android.bp
@@ -0,0 +1,21 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "CompanionTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/core/tests/companiontests/AndroidManifest.xml b/core/tests/companiontests/AndroidManifest.xml
new file mode 100644
index 0000000..f436d97
--- /dev/null
+++ b/core/tests/companiontests/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.companion.tests"
+ android:sharedUserId="android.uid.system" >
+
+ <application >
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="android.companion.CompanionTestRunner"
+ android:targetPackage="com.android.companion.tests"
+ android:label="Companion Tests" />
+
+</manifest>
diff --git a/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java b/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java
new file mode 100644
index 0000000..1ddbbd8
--- /dev/null
+++ b/core/tests/companiontests/src/android/companion/BluetoothDeviceFilterUtilsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 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.companion;
+
+import android.os.ParcelUuid;
+import android.test.InstrumentationTestCase;
+
+public class BluetoothDeviceFilterUtilsTest extends InstrumentationTestCase {
+ private static final String TAG = "BluetoothDeviceFilterUtilsTest";
+
+ private final ParcelUuid mServiceUuid =
+ ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mNonMatchingDeviceUuid =
+ ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mMatchingDeviceUuid =
+ ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mMaskUuid =
+ ParcelUuid.fromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+ private final ParcelUuid mMatchingMaskUuid =
+ ParcelUuid.fromString("F0FFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testUuidsMaskedEquals() {
+ assertFalse(BluetoothDeviceFilterUtils.uuidsMaskedEquals(
+ mNonMatchingDeviceUuid.getUuid(),
+ mServiceUuid.getUuid(),
+ mMaskUuid.getUuid()));
+
+ assertTrue(BluetoothDeviceFilterUtils.uuidsMaskedEquals(
+ mMatchingDeviceUuid.getUuid(),
+ mServiceUuid.getUuid(),
+ mMaskUuid.getUuid()));
+
+ assertTrue(BluetoothDeviceFilterUtils.uuidsMaskedEquals(
+ mNonMatchingDeviceUuid.getUuid(),
+ mServiceUuid.getUuid(),
+ mMatchingMaskUuid.getUuid()));
+ }
+}
diff --git a/core/tests/companiontests/src/android/companion/CompanionTestRunner.java b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java
new file mode 100644
index 0000000..caa2c68
--- /dev/null
+++ b/core/tests/companiontests/src/android/companion/CompanionTestRunner.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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.companion;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import junit.framework.TestSuite;
+
+
+/**
+ * Instrumentation test runner for Companion tests.
+ */
+public class CompanionTestRunner extends InstrumentationTestRunner {
+ private static final String TAG = "CompanionTestRunner";
+
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(BluetoothDeviceFilterUtilsTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return CompanionTestRunner.class.getClassLoader();
+ }
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ super.onCreate(arguments);
+ }
+}
diff --git a/core/tests/coretests/src/android/app/time/OWNERS b/core/tests/coretests/src/android/app/time/OWNERS
index 8f80897..292cb72 100644
--- a/core/tests/coretests/src/android/app/time/OWNERS
+++ b/core/tests/coretests/src/android/app/time/OWNERS
@@ -1,3 +1,2 @@
# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+include /core/java/android/app/time/OWNERS
diff --git a/core/tests/coretests/src/android/app/timedetector/OWNERS b/core/tests/coretests/src/android/app/timedetector/OWNERS
index 8f80897..c612473 100644
--- a/core/tests/coretests/src/android/app/timedetector/OWNERS
+++ b/core/tests/coretests/src/android/app/timedetector/OWNERS
@@ -1,3 +1,2 @@
# Bug component: 847766
-mingaleev@google.com
include /core/java/android/app/timedetector/OWNERS
diff --git a/core/tests/coretests/src/android/app/timezone/OWNERS b/core/tests/coretests/src/android/app/timezone/OWNERS
index 8f80897..381ecf1 100644
--- a/core/tests/coretests/src/android/app/timezone/OWNERS
+++ b/core/tests/coretests/src/android/app/timezone/OWNERS
@@ -1,3 +1,2 @@
-# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# Bug component: 24949
+include /core/java/android/app/timezone/OWNERS
diff --git a/core/tests/coretests/src/android/app/timezonedetector/OWNERS b/core/tests/coretests/src/android/app/timezonedetector/OWNERS
index 8f80897..2e9c324 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/OWNERS
+++ b/core/tests/coretests/src/android/app/timezonedetector/OWNERS
@@ -1,3 +1,2 @@
# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+include /core/java/android/app/timezonedetector/OWNERS
diff --git a/core/tests/coretests/src/android/net/OWNERS b/core/tests/coretests/src/android/net/OWNERS
index aa87958..4e5136f 100644
--- a/core/tests/coretests/src/android/net/OWNERS
+++ b/core/tests/coretests/src/android/net/OWNERS
@@ -1 +1,3 @@
include /services/core/java/com/android/server/net/OWNERS
+
+per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index bf9978c..b400b9b 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -22,7 +22,10 @@
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import android.net.sntp.Duration64;
+import android.net.sntp.Timestamp64;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
@@ -38,7 +41,13 @@
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.Arrays;
+import java.util.Random;
+import java.util.function.Supplier;
@RunWith(AndroidJUnit4.class)
public class SntpClientTest {
@@ -54,41 +63,232 @@
//
// Server, Leap indicator: (0), Stratum 2 (secondary reference), poll 6 (64s), precision -20
// Root Delay: 0.005447, Root dispersion: 0.002716, Reference-ID: 221.253.71.41
- // Reference Timestamp: 3653932102.507969856 (2015/10/15 14:08:22)
- // Originator Timestamp: 3653932113.576327741 (2015/10/15 14:08:33)
- // Receive Timestamp: 3653932113.581012725 (2015/10/15 14:08:33)
- // Transmit Timestamp: 3653932113.581012725 (2015/10/15 14:08:33)
+ // Reference Timestamp:
+ // d9ca9446.820a5000 / ERA0: 2015-10-15 21:08:22 UTC / ERA1: 2151-11-22 03:36:38 UTC
+ // Originator Timestamp:
+ // d9ca9451.938a3771 / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC
+ // Receive Timestamp:
+ // d9ca9451.94bd3fff / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC
+ // Transmit Timestamp:
+ // d9ca9451.94bd4001 / ERA0: 2015-10-15 21:08:33 UTC / ERA1: 2151-11-22 03:36:49 UTC
+ //
// Originator - Receive Timestamp: +0.004684958
// Originator - Transmit Timestamp: +0.004684958
- private static final String WORKING_VERSION4 =
- "240206ec" +
- "00000165" +
- "000000b2" +
- "ddfd4729" +
- "d9ca9446820a5000" +
- "d9ca9451938a3771" +
- "d9ca945194bd3fff" +
- "d9ca945194bd4001";
+ private static final String LATE_ERA_RESPONSE =
+ "240206ec"
+ + "00000165"
+ + "000000b2"
+ + "ddfd4729"
+ + "d9ca9446820a5000"
+ + "d9ca9451938a3771"
+ + "d9ca945194bd3fff"
+ + "d9ca945194bd4001";
+
+ /** This is the actual UTC time in the server if it is in ERA0 */
+ private static final Instant LATE_ERA0_SERVER_TIME =
+ calculateIdealServerTime("d9ca9451.94bd3fff", "d9ca9451.94bd4001", 0);
+
+ /**
+ * This is the Unix epoch time matches the originate timestamp from {@link #LATE_ERA_RESPONSE}
+ * when interpreted as an ERA0 timestamp.
+ */
+ private static final Instant LATE_ERA0_REQUEST_TIME =
+ Timestamp64.fromString("d9ca9451.938a3771").toInstant(0);
+
+ // A tweaked version of the ERA0 response to represent an ERA 1 response.
+ //
+ // Server, Leap indicator: (0), Stratum 2 (secondary reference), poll 6 (64s), precision -20
+ // Root Delay: 0.005447, Root dispersion: 0.002716, Reference-ID: 221.253.71.41
+ // Reference Timestamp:
+ // 1db2d246.820a5000 / ERA0: 1915-10-16 21:08:22 UTC / ERA1: 2051-11-22 03:36:38 UTC
+ // Originate Timestamp:
+ // 1db2d251.938a3771 / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC
+ // Receive Timestamp:
+ // 1db2d251.94bd3fff / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC
+ // Transmit Timestamp:
+ // 1db2d251.94bd4001 / ERA0: 1915-10-16 21:08:33 UTC / ERA1: 2051-11-22 03:36:49 UTC
+ //
+ // Originate - Receive Timestamp: +0.004684958
+ // Originate - Transmit Timestamp: +0.004684958
+ private static final String EARLY_ERA_RESPONSE =
+ "240206ec"
+ + "00000165"
+ + "000000b2"
+ + "ddfd4729"
+ + "1db2d246820a5000"
+ + "1db2d251938a3771"
+ + "1db2d25194bd3fff"
+ + "1db2d25194bd4001";
+
+ /** This is the actual UTC time in the server if it is in ERA0 */
+ private static final Instant EARLY_ERA1_SERVER_TIME =
+ calculateIdealServerTime("1db2d251.94bd3fff", "1db2d251.94bd4001", 1);
+
+ /**
+ * This is the Unix epoch time matches the originate timestamp from {@link #EARLY_ERA_RESPONSE}
+ * when interpreted as an ERA1 timestamp.
+ */
+ private static final Instant EARLY_ERA1_REQUEST_TIME =
+ Timestamp64.fromString("1db2d251.938a3771").toInstant(1);
private SntpTestServer mServer;
private SntpClient mClient;
private Network mNetwork;
+ private Supplier<Instant> mSystemTimeSupplier;
+ private Random mRandom;
+ @SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
+ mServer = new SntpTestServer();
+
// A mock network has NETID_UNSET, which allows the test to run, with a loopback server,
// even w/o external networking.
mNetwork = mock(Network.class, CALLS_REAL_METHODS);
- mServer = new SntpTestServer();
- mClient = new SntpClient();
+ mRandom = mock(Random.class);
+
+ mSystemTimeSupplier = mock(Supplier.class);
+ // Returning zero means the "randomized" bottom bits of the clients transmit timestamp /
+ // server's originate timestamp will be zeros.
+ when(mRandom.nextInt()).thenReturn(0);
+ mClient = new SntpClient(mSystemTimeSupplier, mRandom);
}
+ /** Tests when the client and server are in ERA0. b/199481251. */
@Test
- public void testBasicWorkingSntpClientQuery() throws Exception {
- mServer.setServerReply(HexEncoding.decode(WORKING_VERSION4.toCharArray(), false));
+ public void testRequestTime_era0ClientEra0RServer() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false));
assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
assertEquals(1, mServer.numRequestsReceived());
assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(LATE_ERA0_REQUEST_TIME, LATE_ERA0_SERVER_TIME, mClient);
+ }
+
+ /** Tests when the client is behind the server and in the previous ERA. b/199481251. */
+ @Test
+ public void testRequestTime_era0ClientEra1Server() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(EARLY_ERA_RESPONSE.toCharArray(), false));
+ assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(LATE_ERA0_REQUEST_TIME, EARLY_ERA1_SERVER_TIME, mClient);
+
+ }
+
+ /** Tests when the client is ahead of the server and in the next ERA. b/199481251. */
+ @Test
+ public void testRequestTime_era1ClientEra0Server() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(EARLY_ERA1_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false));
+ assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(EARLY_ERA1_REQUEST_TIME, LATE_ERA0_SERVER_TIME, mClient);
+ }
+
+ /** Tests when the client and server are in ERA1. b/199481251. */
+ @Test
+ public void testRequestTime_era1ClientEra1Server() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(EARLY_ERA1_REQUEST_TIME);
+
+ mServer.setServerReply(HexEncoding.decode(EARLY_ERA_RESPONSE.toCharArray(), false));
+ assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+
+ checkRequestTimeCalcs(EARLY_ERA1_REQUEST_TIME, EARLY_ERA1_SERVER_TIME, mClient);
+ }
+
+ private static void checkRequestTimeCalcs(
+ Instant clientTime, Instant serverTime, SntpClient client) {
+ // The tests don't attempt to control the elapsed time tracking, which influences the
+ // round trip time (i.e. time spent in due to the network), but they control everything
+ // else, so assertions are allowed some slop and round trip time just has to be >= 0.
+ assertTrue("getRoundTripTime()=" + client.getRoundTripTime(),
+ client.getRoundTripTime() >= 0);
+
+ // Calculate the ideal offset if nothing took any time.
+ long expectedOffset = serverTime.toEpochMilli() - clientTime.toEpochMilli();
+ long allowedSlop = (client.getRoundTripTime() / 2) + 1; // +1 to allow for truncation loss.
+ assertNearlyEquals(expectedOffset, client.getClockOffset(), allowedSlop);
+ assertNearlyEquals(clientTime.toEpochMilli() + expectedOffset,
+ client.getNtpTime(), allowedSlop);
+ }
+
+ /**
+ * Unit tests for the low-level offset calculations. More targeted / easier to write than the
+ * end-to-end tests above that simulate the server. b/199481251.
+ */
+ @Test
+ public void testCalculateClockOffset() {
+ Instant era0Time1 = utcInstant(2021, 10, 5, 2, 2, 2, 2);
+ // Confirm what happens when the client and server are completely in sync.
+ checkCalculateClockOffset(era0Time1, era0Time1);
+
+ Instant era0Time2 = utcInstant(2021, 10, 6, 1, 1, 1, 1);
+ checkCalculateClockOffset(era0Time1, era0Time2);
+ checkCalculateClockOffset(era0Time2, era0Time1);
+
+ Instant era1Time1 = utcInstant(2061, 10, 5, 2, 2, 2, 2);
+ checkCalculateClockOffset(era1Time1, era1Time1);
+
+ Instant era1Time2 = utcInstant(2061, 10, 6, 1, 1, 1, 1);
+ checkCalculateClockOffset(era1Time1, era1Time2);
+ checkCalculateClockOffset(era1Time2, era1Time1);
+
+ // Cross-era calcs (requires they are still within 68 years of each other).
+ checkCalculateClockOffset(era0Time1, era1Time1);
+ checkCalculateClockOffset(era1Time1, era0Time1);
+ }
+
+ private void checkCalculateClockOffset(Instant clientTime, Instant serverTime) {
+ // The expected (ideal) offset is the difference between the client and server clocks. NTP
+ // assumes delays are symmetric, i.e. that the server time is between server
+ // receive/transmit time, client time is between request/response time, and send networking
+ // delay == receive networking delay.
+ Duration expectedOffset = Duration.between(clientTime, serverTime);
+
+ // Try simulating various round trip delays, including zero.
+ for (long totalElapsedTimeMillis : Arrays.asList(0, 20, 200, 2000, 20000)) {
+ // Simulate that a 10% of the elapsed time is due to time spent in the server, the rest
+ // is network / client processing time.
+ long simulatedServerElapsedTimeMillis = totalElapsedTimeMillis / 10;
+ long simulatedClientElapsedTimeMillis = totalElapsedTimeMillis;
+
+ // Create some symmetrical timestamps.
+ Timestamp64 clientRequestTimestamp = Timestamp64.fromInstant(
+ clientTime.minusMillis(simulatedClientElapsedTimeMillis / 2));
+ Timestamp64 clientResponseTimestamp = Timestamp64.fromInstant(
+ clientTime.plusMillis(simulatedClientElapsedTimeMillis / 2));
+ Timestamp64 serverReceiveTimestamp = Timestamp64.fromInstant(
+ serverTime.minusMillis(simulatedServerElapsedTimeMillis / 2));
+ Timestamp64 serverTransmitTimestamp = Timestamp64.fromInstant(
+ serverTime.plusMillis(simulatedServerElapsedTimeMillis / 2));
+
+ Duration actualOffset = SntpClient.calculateClockOffset(
+ clientRequestTimestamp, serverReceiveTimestamp,
+ serverTransmitTimestamp, clientResponseTimestamp);
+
+ // We allow up to 1ms variation because NTP types are lossy and the simulated elapsed
+ // time millis may not divide exactly.
+ int allowedSlopMillis = 1;
+ assertNearlyEquals(
+ expectedOffset.toMillis(), actualOffset.toMillis(), allowedSlopMillis);
+ }
+ }
+
+ private static Instant utcInstant(
+ int year, int monthOfYear, int day, int hour, int minute, int second, int nanos) {
+ return LocalDateTime.of(year, monthOfYear, day, hour, minute, second, nanos)
+ .toInstant(ZoneOffset.UTC);
}
@Test
@@ -98,6 +298,8 @@
@Test
public void testTimeoutFailure() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
mServer.clearServerReply();
assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
assertEquals(1, mServer.numRequestsReceived());
@@ -106,7 +308,9 @@
@Test
public void testIgnoreLeapNoSync() throws Exception {
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
reply[0] |= (byte) 0xc0;
mServer.setServerReply(reply);
assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
@@ -116,7 +320,9 @@
@Test
public void testAcceptOnlyServerAndBroadcastModes() throws Exception {
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
for (int i = 0; i <= 7; i++) {
final String logMsg = "mode: " + i;
reply[0] &= (byte) 0xf8;
@@ -140,10 +346,12 @@
@Test
public void testAcceptableStrataOnly() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
final int STRATUM_MIN = 1;
final int STRATUM_MAX = 15;
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
for (int i = 0; i < 256; i++) {
final String logMsg = "stratum: " + i;
reply[1] = (byte) i;
@@ -162,7 +370,9 @@
@Test
public void testZeroTransmitTime() throws Exception {
- final byte[] reply = HexEncoding.decode(WORKING_VERSION4.toCharArray(), false);
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
Arrays.fill(reply, TRANSMIT_TIME_OFFSET, TRANSMIT_TIME_OFFSET + 8, (byte) 0x00);
mServer.setServerReply(reply);
assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
@@ -170,6 +380,19 @@
assertEquals(1, mServer.numRepliesSent());
}
+ @Test
+ public void testNonMatchingOriginateTime() throws Exception {
+ when(mSystemTimeSupplier.get()).thenReturn(LATE_ERA0_REQUEST_TIME);
+
+ final byte[] reply = HexEncoding.decode(LATE_ERA_RESPONSE.toCharArray(), false);
+ mServer.setServerReply(reply);
+ mServer.setGenerateValidOriginateTimestamp(false);
+
+ assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500, mNetwork));
+ assertEquals(1, mServer.numRequestsReceived());
+ assertEquals(1, mServer.numRepliesSent());
+ }
+
private static class SntpTestServer {
private final Object mLock = new Object();
@@ -177,6 +400,7 @@
private final InetAddress mAddress;
private final int mPort;
private byte[] mReply;
+ private boolean mGenerateValidOriginateTimestamp = true;
private int mRcvd;
private int mSent;
private Thread mListeningThread;
@@ -201,10 +425,16 @@
synchronized (mLock) {
mRcvd++;
if (mReply == null) { continue; }
- // Copy transmit timestamp into originate timestamp.
- // TODO: bounds checking.
- System.arraycopy(ntpMsg.getData(), TRANSMIT_TIME_OFFSET,
- mReply, ORIGINATE_TIME_OFFSET, 8);
+ if (mGenerateValidOriginateTimestamp) {
+ // Copy the transmit timestamp into originate timestamp: This is
+ // validated by well-behaved clients.
+ System.arraycopy(ntpMsg.getData(), TRANSMIT_TIME_OFFSET,
+ mReply, ORIGINATE_TIME_OFFSET, 8);
+ } else {
+ // Fill it with junk instead.
+ Arrays.fill(mReply, ORIGINATE_TIME_OFFSET,
+ ORIGINATE_TIME_OFFSET + 8, (byte) 0xFF);
+ }
ntpMsg.setData(mReply);
ntpMsg.setLength(mReply.length);
try {
@@ -245,9 +475,38 @@
}
}
+ /**
+ * Controls the test server's behavior of copying the client's transmit timestamp into the
+ * response's originate timestamp (which is required of a real server).
+ */
+ public void setGenerateValidOriginateTimestamp(boolean enabled) {
+ synchronized (mLock) {
+ mGenerateValidOriginateTimestamp = enabled;
+ }
+ }
+
public InetAddress getAddress() { return mAddress; }
public int getPort() { return mPort; }
public int numRequestsReceived() { synchronized (mLock) { return mRcvd; } }
public int numRepliesSent() { synchronized (mLock) { return mSent; } }
}
+
+ /**
+ * Generates the "real" server time assuming it is exactly between the receive and transmit
+ * timestamp and in the NTP era specified.
+ */
+ private static Instant calculateIdealServerTime(String receiveTimestampString,
+ String transmitTimestampString, int era) {
+ Timestamp64 receiveTimestamp = Timestamp64.fromString(receiveTimestampString);
+ Timestamp64 transmitTimestamp = Timestamp64.fromString(transmitTimestampString);
+ Duration serverProcessingTime =
+ Duration64.between(receiveTimestamp, transmitTimestamp).toDuration();
+ return receiveTimestamp.toInstant(era)
+ .plusMillis(serverProcessingTime.dividedBy(2).toMillis());
+ }
+
+ private static void assertNearlyEquals(long expected, long actual, long allowedSlop) {
+ assertTrue("expected=" + expected + ", actual=" + actual + ", allowedSlop=" + allowedSlop,
+ actual >= expected - allowedSlop && actual <= expected + allowedSlop);
+ }
}
diff --git a/core/tests/coretests/src/android/net/sntp/Duration64Test.java b/core/tests/coretests/src/android/net/sntp/Duration64Test.java
new file mode 100644
index 0000000..60b69f6
--- /dev/null
+++ b/core/tests/coretests/src/android/net/sntp/Duration64Test.java
@@ -0,0 +1,268 @@
+/*
+ * 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.sntp;
+
+import static android.net.sntp.Timestamp64.NANOS_PER_SECOND;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+@RunWith(AndroidJUnit4.class)
+public class Duration64Test {
+
+ @Test
+ public void testBetween_rangeChecks() {
+ long maxDuration64Seconds = Timestamp64.MAX_SECONDS_IN_ERA / 2;
+
+ Timestamp64 zeroNoFrac = Timestamp64.fromComponents(0, 0);
+ assertEquals(Duration64.ZERO, Duration64.between(zeroNoFrac, zeroNoFrac));
+
+ {
+ Timestamp64 ceilNoFrac = Timestamp64.fromComponents(maxDuration64Seconds, 0);
+ assertEquals(Duration64.ZERO, Duration64.between(ceilNoFrac, ceilNoFrac));
+
+ long expectedNanos = maxDuration64Seconds * NANOS_PER_SECOND;
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(zeroNoFrac, ceilNoFrac).toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(ceilNoFrac, zeroNoFrac).toDuration());
+ }
+
+ {
+ // This value is the largest fraction of a second representable. It is 1-(1/2^32)), and
+ // so numerically larger than 999_999_999 nanos.
+ int fractionBits = 0xFFFF_FFFF;
+ Timestamp64 ceilWithFrac = Timestamp64
+ .fromComponents(maxDuration64Seconds, fractionBits);
+ assertEquals(Duration64.ZERO, Duration64.between(ceilWithFrac, ceilWithFrac));
+
+ long expectedNanos = maxDuration64Seconds * NANOS_PER_SECOND + 999_999_999;
+ assertEquals(
+ Duration.ofNanos(expectedNanos),
+ Duration64.between(zeroNoFrac, ceilWithFrac).toDuration());
+ // The -1 nanos demonstrates asymmetry due to the way Duration64 has different
+ // precision / range of sub-second fractions.
+ assertEquals(
+ Duration.ofNanos(-expectedNanos - 1),
+ Duration64.between(ceilWithFrac, zeroNoFrac).toDuration());
+ }
+ }
+
+ @Test
+ public void testBetween_smallSecondsOnly() {
+ long expectedNanos = 5L * NANOS_PER_SECOND;
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(Timestamp64.fromComponents(5, 0),
+ Timestamp64.fromComponents(10, 0))
+ .toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(Timestamp64.fromComponents(10, 0),
+ Timestamp64.fromComponents(5, 0))
+ .toDuration());
+ }
+
+ @Test
+ public void testBetween_smallSecondsAndFraction() {
+ // Choose a nanos values we know can be represented exactly with fixed point binary (1/2
+ // second, 1/4 second, etc.).
+ {
+ long expectedNanos = 5L * NANOS_PER_SECOND + 500_000_000L;
+ int fractionHalfSecond = 0x8000_0000;
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(5, 0),
+ Timestamp64.fromComponents(10, fractionHalfSecond)).toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(10, fractionHalfSecond),
+ Timestamp64.fromComponents(5, 0)).toDuration());
+ }
+
+ {
+ long expectedNanos = 5L * NANOS_PER_SECOND + 250_000_000L;
+ int fractionHalfSecond = 0x8000_0000;
+ int fractionQuarterSecond = 0x4000_0000;
+
+ assertEquals(Duration.ofNanos(expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(5, fractionQuarterSecond),
+ Timestamp64.fromComponents(10, fractionHalfSecond)).toDuration());
+ assertEquals(Duration.ofNanos(-expectedNanos),
+ Duration64.between(
+ Timestamp64.fromComponents(10, fractionHalfSecond),
+ Timestamp64.fromComponents(5, fractionQuarterSecond)).toDuration());
+ }
+
+ }
+
+ @Test
+ public void testBetween_sameEra0() {
+ int arbitraryEra0Year = 2021;
+ Instant one = utcInstant(arbitraryEra0Year, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 0);
+
+ checkDuration64Behavior(one, one);
+
+ Instant two = utcInstant(arbitraryEra0Year + 1, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 0);
+
+ checkDuration64Behavior(one, two);
+ checkDuration64Behavior(two, one);
+ }
+
+ @Test
+ public void testBetween_sameEra1() {
+ int arbitraryEra1Year = 2037;
+ Instant one = utcInstant(arbitraryEra1Year, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 1);
+
+ checkDuration64Behavior(one, one);
+
+ Instant two = utcInstant(arbitraryEra1Year + 1, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 1);
+
+ checkDuration64Behavior(one, two);
+ checkDuration64Behavior(two, one);
+ }
+
+ /**
+ * Tests that two timestamps can originate from times in different eras, and the works
+ * calculation still works providing the two times aren't more than 68 years apart (half of the
+ * 136 years representable using an unsigned 32-bit seconds representation).
+ */
+ @Test
+ public void testBetween_adjacentEras() {
+ int yearsSeparation = 68;
+
+ // This year just needs to be < 68 years before the end of NTP timestamp era 0.
+ int arbitraryYearInEra0 = 2021;
+
+ Instant one = utcInstant(arbitraryYearInEra0, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 0);
+
+ checkDuration64Behavior(one, one);
+
+ Instant two = utcInstant(arbitraryYearInEra0 + yearsSeparation, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 1);
+
+ checkDuration64Behavior(one, two);
+ checkDuration64Behavior(two, one);
+ }
+
+ /**
+ * This test confirms that duration calculations fail in the expected fashion if two
+ * Timestamp64s are more than 2^31 seconds apart.
+ *
+ * <p>The types / math specified by NTP for timestamps deliberately takes place in 64-bit signed
+ * arithmetic for the bits used to represent timestamps (32-bit unsigned integer seconds,
+ * 32-bits fixed point for fraction of seconds). Timestamps can therefore represent ~136 years
+ * of seconds.
+ * When subtracting one timestamp from another, we end up with a signed 32-bit seconds value.
+ * This means the max duration representable is ~68 years before numbers will over or underflow.
+ * i.e. the client and server are in the same or adjacent NTP eras and the difference in their
+ * clocks isn't more than ~68 years. >= ~68 years and things break down.
+ */
+ @Test
+ public void testBetween_tooFarApart() {
+ int tooManyYearsSeparation = 68 + 1;
+
+ Instant one = utcInstant(2021, 1, 1, 0, 0, 0, 500);
+ assertNtpEraOfInstant(one, 0);
+ Instant two = utcInstant(2021 + tooManyYearsSeparation, 1, 1, 0, 0, 0, 250);
+ assertNtpEraOfInstant(two, 1);
+
+ checkDuration64OverflowBehavior(one, two);
+ checkDuration64OverflowBehavior(two, one);
+ }
+
+ private static void checkDuration64Behavior(Instant one, Instant two) {
+ // This is the answer if we perform the arithmetic in a lossless fashion.
+ Duration expectedDuration = Duration.between(one, two);
+ Duration64 expectedDuration64 = Duration64.fromDuration(expectedDuration);
+
+ // Sub-second precision is limited in Timestamp64, so we can lose 1ms.
+ assertEqualsOrSlightlyLessThan(
+ expectedDuration.toMillis(), expectedDuration64.toDuration().toMillis());
+
+ Timestamp64 one64 = Timestamp64.fromInstant(one);
+ Timestamp64 two64 = Timestamp64.fromInstant(two);
+
+ // This is the answer if we perform the arithmetic in a lossy fashion.
+ Duration64 actualDuration64 = Duration64.between(one64, two64);
+ assertEquals(expectedDuration64.getSeconds(), actualDuration64.getSeconds());
+ assertEqualsOrSlightlyLessThan(expectedDuration64.getNanos(), actualDuration64.getNanos());
+ }
+
+ private static void checkDuration64OverflowBehavior(Instant one, Instant two) {
+ // This is the answer if we perform the arithmetic in a lossless fashion.
+ Duration trueDuration = Duration.between(one, two);
+
+ // Confirm the maths is expected to overflow / underflow.
+ assertTrue(trueDuration.getSeconds() > Integer.MAX_VALUE / 2
+ || trueDuration.getSeconds() < Integer.MIN_VALUE / 2);
+
+ // Now perform the arithmetic as specified for NTP: do subtraction using the 64-bit
+ // timestamp.
+ Timestamp64 one64 = Timestamp64.fromInstant(one);
+ Timestamp64 two64 = Timestamp64.fromInstant(two);
+
+ Duration64 actualDuration64 = Duration64.between(one64, two64);
+ assertNotEquals(trueDuration.getSeconds(), actualDuration64.getSeconds());
+ }
+
+ /**
+ * Asserts the instant provided is in the specified NTP timestamp era. Used to confirm /
+ * document values picked for tests have the properties needed.
+ */
+ private static void assertNtpEraOfInstant(Instant one, int ntpEra) {
+ long expectedSeconds = one.getEpochSecond();
+
+ // The conversion to Timestamp64 is lossy (it loses the era). We then supply the expected
+ // era. If the era was correct, we will end up with the value we started with (modulo nano
+ // precision loss). If the era is wrong, we won't.
+ Instant roundtrippedInstant = Timestamp64.fromInstant(one).toInstant(ntpEra);
+
+ long actualSeconds = roundtrippedInstant.getEpochSecond();
+ assertEquals(expectedSeconds, actualSeconds);
+ }
+
+ /**
+ * Used to account for the fact that NTP types used 32-bit fixed point storage, so cannot store
+ * all values precisely. The value we get out will always be the value we put in, or one that is
+ * one unit smaller (due to truncation).
+ */
+ private static void assertEqualsOrSlightlyLessThan(long expected, long actual) {
+ assertTrue("expected=" + expected + ", actual=" + actual,
+ expected == actual || expected == actual - 1);
+ }
+
+ private static Instant utcInstant(
+ int year, int monthOfYear, int day, int hour, int minute, int second, int nanos) {
+ return LocalDateTime.of(year, monthOfYear, day, hour, minute, second, nanos)
+ .toInstant(ZoneOffset.UTC);
+ }
+}
diff --git a/core/tests/coretests/src/android/net/sntp/OWNERS b/core/tests/coretests/src/android/net/sntp/OWNERS
new file mode 100644
index 0000000..232c2eb
--- /dev/null
+++ b/core/tests/coretests/src/android/net/sntp/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/net/sntp/OWNERS
diff --git a/core/tests/coretests/src/android/net/sntp/PredictableRandom.java b/core/tests/coretests/src/android/net/sntp/PredictableRandom.java
new file mode 100644
index 0000000..bb2922b
--- /dev/null
+++ b/core/tests/coretests/src/android/net/sntp/PredictableRandom.java
@@ -0,0 +1,34 @@
+/*
+ * 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.sntp;
+
+import java.util.Random;
+
+class PredictableRandom extends Random {
+ private int[] mIntSequence = new int[] { 1 };
+ private int mIntPos = 0;
+
+ public void setIntSequence(int[] intSequence) {
+ this.mIntSequence = intSequence;
+ }
+
+ @Override
+ public int nextInt() {
+ int value = mIntSequence[mIntPos++];
+ mIntPos %= mIntSequence.length;
+ return value;
+ }
+}
diff --git a/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java
new file mode 100644
index 0000000..1b1c500
--- /dev/null
+++ b/core/tests/coretests/src/android/net/sntp/Timestamp64Test.java
@@ -0,0 +1,316 @@
+/*
+ * 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.sntp;
+
+import static android.net.sntp.Timestamp64.NANOS_PER_SECOND;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Instant;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class Timestamp64Test {
+
+ @Test
+ public void testFromComponents() {
+ long minNtpEraSeconds = 0;
+ long maxNtpEraSeconds = 0xFFFFFFFFL;
+
+ expectIllegalArgumentException(() -> Timestamp64.fromComponents(minNtpEraSeconds - 1, 0));
+ expectIllegalArgumentException(() -> Timestamp64.fromComponents(maxNtpEraSeconds + 1, 0));
+
+ assertComponentCreation(minNtpEraSeconds, 0);
+ assertComponentCreation(maxNtpEraSeconds, 0);
+ assertComponentCreation(maxNtpEraSeconds, Integer.MIN_VALUE);
+ assertComponentCreation(maxNtpEraSeconds, Integer.MAX_VALUE);
+ }
+
+ private static void assertComponentCreation(long ntpEraSeconds, int fractionBits) {
+ Timestamp64 value = Timestamp64.fromComponents(ntpEraSeconds, fractionBits);
+ assertEquals(ntpEraSeconds, value.getEraSeconds());
+ assertEquals(fractionBits, value.getFractionBits());
+ }
+
+ @Test
+ public void testEqualsAndHashcode() {
+ assertEqualsAndHashcode(0, 0);
+ assertEqualsAndHashcode(1, 0);
+ assertEqualsAndHashcode(0, 1);
+ }
+
+ private static void assertEqualsAndHashcode(int eraSeconds, int fractionBits) {
+ Timestamp64 one = Timestamp64.fromComponents(eraSeconds, fractionBits);
+ Timestamp64 two = Timestamp64.fromComponents(eraSeconds, fractionBits);
+ assertEquals(one, two);
+ assertEquals(one.hashCode(), two.hashCode());
+ }
+
+ @Test
+ public void testStringForm() {
+ expectIllegalArgumentException(() -> Timestamp64.fromString(""));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("."));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("1234567812345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678?12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678..12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("1.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("123456.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("1234567.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.1"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.12"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.123456"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.1234567"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("X2345678.12345678"));
+ expectIllegalArgumentException(() -> Timestamp64.fromString("12345678.X2345678"));
+
+ assertStringCreation("00000000.00000000", 0, 0);
+ assertStringCreation("00000001.00000001", 1, 1);
+ assertStringCreation("ffffffff.ffffffff", 0xFFFFFFFFL, 0xFFFFFFFF);
+ }
+
+ private static void assertStringCreation(
+ String string, long expectedSeconds, int expectedFractionBits) {
+ Timestamp64 timestamp64 = Timestamp64.fromString(string);
+ assertEquals(string, timestamp64.toString());
+ assertEquals(expectedSeconds, timestamp64.getEraSeconds());
+ assertEquals(expectedFractionBits, timestamp64.getFractionBits());
+ }
+
+ @Test
+ public void testStringForm_lenientHexCasing() {
+ Timestamp64 mixedCaseValue = Timestamp64.fromString("AaBbCcDd.EeFf1234");
+ assertEquals(0xAABBCCDDL, mixedCaseValue.getEraSeconds());
+ assertEquals(0xEEFF1234, mixedCaseValue.getFractionBits());
+ }
+
+ @Test
+ public void testFromInstant_secondsHandling() {
+ final int era0 = 0;
+ final int eraNeg1 = -1;
+ final int eraNeg2 = -2;
+ final int era1 = 1;
+
+ assertInstantCreationOnlySeconds(-Timestamp64.OFFSET_1900_TO_1970, 0, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA, 0, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA, 0, era1);
+
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - 1, Timestamp64.MAX_SECONDS_IN_ERA, -1);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA - 1,
+ Timestamp64.MAX_SECONDS_IN_ERA, eraNeg2);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA - 1,
+ Timestamp64.MAX_SECONDS_IN_ERA, era0);
+
+ assertInstantCreationOnlySeconds(-Timestamp64.OFFSET_1900_TO_1970 + 1, 1, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 - Timestamp64.SECONDS_IN_ERA + 1, 1, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.OFFSET_1900_TO_1970 + Timestamp64.SECONDS_IN_ERA + 1, 1, era1);
+
+ assertInstantCreationOnlySeconds(0, Timestamp64.OFFSET_1900_TO_1970, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.SECONDS_IN_ERA, Timestamp64.OFFSET_1900_TO_1970, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ Timestamp64.SECONDS_IN_ERA, Timestamp64.OFFSET_1900_TO_1970, era1);
+
+ assertInstantCreationOnlySeconds(1, Timestamp64.OFFSET_1900_TO_1970 + 1, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.SECONDS_IN_ERA + 1, Timestamp64.OFFSET_1900_TO_1970 + 1, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ Timestamp64.SECONDS_IN_ERA + 1, Timestamp64.OFFSET_1900_TO_1970 + 1, era1);
+
+ assertInstantCreationOnlySeconds(-1, Timestamp64.OFFSET_1900_TO_1970 - 1, era0);
+ assertInstantCreationOnlySeconds(
+ -Timestamp64.SECONDS_IN_ERA - 1, Timestamp64.OFFSET_1900_TO_1970 - 1, eraNeg1);
+ assertInstantCreationOnlySeconds(
+ Timestamp64.SECONDS_IN_ERA - 1, Timestamp64.OFFSET_1900_TO_1970 - 1, era1);
+ }
+
+ private static void assertInstantCreationOnlySeconds(
+ long epochSeconds, long expectedNtpEraSeconds, int ntpEra) {
+ int nanosOfSecond = 0;
+ Instant instant = Instant.ofEpochSecond(epochSeconds, nanosOfSecond);
+ Timestamp64 timestamp = Timestamp64.fromInstant(instant);
+ assertEquals(expectedNtpEraSeconds, timestamp.getEraSeconds());
+
+ int expectedFractionBits = 0;
+ assertEquals(expectedFractionBits, timestamp.getFractionBits());
+
+ // Confirm the Instant can be round-tripped if we know the era. Also assumes the nanos can
+ // be stored precisely; 0 can be.
+ Instant roundTrip = timestamp.toInstant(ntpEra);
+ assertEquals(instant, roundTrip);
+ }
+
+ @Test
+ public void testFromInstant_fractionHandling() {
+ // Try some values we know can be represented exactly.
+ assertInstantCreationOnlyFractionExact(0x0, 0);
+ assertInstantCreationOnlyFractionExact(0x80000000, 500_000_000L);
+ assertInstantCreationOnlyFractionExact(0x40000000, 250_000_000L);
+
+ // Test the limits of precision.
+ assertInstantCreationOnlyFractionExact(0x00000006, 1L);
+ assertInstantCreationOnlyFractionExact(0x00000005, 1L);
+ assertInstantCreationOnlyFractionExact(0x00000004, 0L);
+ assertInstantCreationOnlyFractionExact(0x00000002, 0L);
+ assertInstantCreationOnlyFractionExact(0x00000001, 0L);
+
+ // Confirm nanosecond storage / precision is within 1ns.
+ final boolean exhaustive = false;
+ for (int i = 0; i < NANOS_PER_SECOND; i++) {
+ Instant instant = Instant.ofEpochSecond(0, i);
+ Instant roundTripped = Timestamp64.fromInstant(instant).toInstant(0);
+ assertNanosWithTruncationAllowed(i, roundTripped);
+ if (!exhaustive) {
+ i += 999_999;
+ }
+ }
+ }
+
+ @SuppressWarnings("JavaInstantGetSecondsGetNano")
+ private static void assertInstantCreationOnlyFractionExact(
+ int fractionBits, long expectedNanos) {
+ Timestamp64 timestamp64 = Timestamp64.fromComponents(0, fractionBits);
+
+ final int ntpEra = 0;
+ Instant instant = timestamp64.toInstant(ntpEra);
+
+ assertEquals(expectedNanos, instant.getNano());
+ }
+
+ @SuppressWarnings("JavaInstantGetSecondsGetNano")
+ private static void assertNanosWithTruncationAllowed(long expectedNanos, Instant instant) {
+ // Allow for < 1ns difference due to truncation.
+ long actualNanos = instant.getNano();
+ assertTrue("expectedNanos=" + expectedNanos + ", actualNanos=" + actualNanos,
+ actualNanos == expectedNanos || actualNanos == expectedNanos - 1);
+ }
+
+ @SuppressWarnings("JavaInstantGetSecondsGetNano")
+ @Test
+ public void testMillisRandomizationConstant() {
+ // Mathematically, we can say that to represent 1000 different values, we need 10 binary
+ // digits (2^10 = 1024). The same is true whether we're dealing with integers or fractions.
+ // Unfortunately, for fractions those 1024 values do not correspond to discrete decimal
+ // values. Discrete millisecond values as fractions (e.g. 0.001 - 0.999) cannot be
+ // represented exactly except where the value can also be represented as some combination of
+ // powers of -2. When we convert back and forth, we truncate, so millisecond decimal
+ // fraction N represented as a binary fraction will always be equal to or lower than N. If
+ // we are truncating correctly it will never be as low as (N-0.001). N -> [N-0.001, N].
+
+ // We need to keep 10 bits to hold millis (inaccurately, since there are numbers that
+ // cannot be represented exactly), leaving us able to randomize the remaining 22 bits of the
+ // fraction part without significantly affecting the number represented.
+ assertEquals(22, Timestamp64.SUB_MILLIS_BITS_TO_RANDOMIZE);
+
+ // Brute force proof that randomization logic will keep the timestamp within the range
+ // [N-0.001, N] where x is in milliseconds.
+ int smallFractionRandomizedLow = 0;
+ int smallFractionRandomizedHigh = 0b00000000_00111111_11111111_11111111;
+ int largeFractionRandomizedLow = 0b11111111_11000000_00000000_00000000;
+ int largeFractionRandomizedHigh = 0b11111111_11111111_11111111_11111111;
+
+ long smallLowNanos = Timestamp64.fromComponents(
+ 0, smallFractionRandomizedLow).toInstant(0).getNano();
+ long smallHighNanos = Timestamp64.fromComponents(
+ 0, smallFractionRandomizedHigh).toInstant(0).getNano();
+ long smallDelta = smallHighNanos - smallLowNanos;
+ long millisInNanos = 1_000_000_000 / 1_000;
+ assertTrue(smallDelta >= 0 && smallDelta < millisInNanos);
+
+ long largeLowNanos = Timestamp64.fromComponents(
+ 0, largeFractionRandomizedLow).toInstant(0).getNano();
+ long largeHighNanos = Timestamp64.fromComponents(
+ 0, largeFractionRandomizedHigh).toInstant(0).getNano();
+ long largeDelta = largeHighNanos - largeLowNanos;
+ assertTrue(largeDelta >= 0 && largeDelta < millisInNanos);
+
+ PredictableRandom random = new PredictableRandom();
+ random.setIntSequence(new int[] { 0xFFFF_FFFF });
+ Timestamp64 zero = Timestamp64.fromComponents(0, 0);
+ Timestamp64 zeroWithFractionRandomized = zero.randomizeSubMillis(random);
+ assertEquals(zero.getEraSeconds(), zeroWithFractionRandomized.getEraSeconds());
+ assertEquals(smallFractionRandomizedHigh, zeroWithFractionRandomized.getFractionBits());
+ }
+
+ @Test
+ public void testRandomizeLowestBits() {
+ Random random = new Random(1);
+ {
+ int fractionBits = 0;
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, -1));
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, 0));
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, Integer.SIZE));
+ expectIllegalArgumentException(
+ () -> Timestamp64.randomizeLowestBits(random, fractionBits, Integer.SIZE + 1));
+ }
+
+ // Check the behavior looks correct from a probabilistic point of view.
+ for (int input : new int[] { 0, 0xFFFFFFFF }) {
+ for (int bitCount = 1; bitCount < Integer.SIZE; bitCount++) {
+ int upperBitMask = 0xFFFFFFFF << bitCount;
+ int expectedUpperBits = input & upperBitMask;
+
+ Set<Integer> values = new HashSet<>();
+ values.add(input);
+
+ int trials = 100;
+ for (int i = 0; i < trials; i++) {
+ int outputFractionBits =
+ Timestamp64.randomizeLowestBits(random, input, bitCount);
+
+ // Record the output value for later analysis.
+ values.add(outputFractionBits);
+
+ // Check upper bits did not change.
+ assertEquals(expectedUpperBits, outputFractionBits & upperBitMask);
+ }
+
+ // It's possible to be more rigorous here, perhaps with a histogram. As bitCount
+ // rises, values.size() quickly trend towards the value of trials + 1. For now, this
+ // mostly just guards against a no-op implementation.
+ assertTrue(bitCount + ":" + values.size(), values.size() > 1);
+ }
+ }
+ }
+
+ private static void expectIllegalArgumentException(Runnable r) {
+ try {
+ r.run();
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS
index 9a9b474..a42285e 100644
--- a/core/tests/coretests/src/android/os/OWNERS
+++ b/core/tests/coretests/src/android/os/OWNERS
@@ -2,11 +2,11 @@
per-file BrightnessLimit.java = michaelwr@google.com, santoscordon@google.com
# Haptics
-per-file CombinedVibrationEffectTest.java = michaelwr@google.com
-per-file ExternalVibrationTest.java = michaelwr@google.com
-per-file VibrationEffectTest.java = michaelwr@google.com
-per-file VibratorInfoTest.java = michaelwr@google.com
-per-file VibratorTest.java = michaelwr@google.com
+per-file CombinedVibrationEffectTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file ExternalVibrationTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file VibrationEffectTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file VibratorInfoTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file VibratorTest.java = file:/services/core/java/com/android/server/vibrator/OWNERS
# Power
-per-file PowerManager*.java = michaelwr@google.com, santoscordon@google.com
+per-file PowerManager*.java = michaelwr@google.com, santoscordon@google.com
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/service/timezone/OWNERS b/core/tests/coretests/src/android/service/timezone/OWNERS
new file mode 100644
index 0000000..8116388
--- /dev/null
+++ b/core/tests/coretests/src/android/service/timezone/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 847766
+include /core/java/android/service/timezone/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 5c84794..d361da9 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -33,6 +33,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class BluetoothPowerCalculatorTest {
@@ -105,10 +107,10 @@
final BluetoothActivityEnergyInfo info = new BluetoothActivityEnergyInfo(1000,
BluetoothActivityEnergyInfo.BT_STACK_STATE_STATE_ACTIVE, 7000, 5000, 0,
reportedEnergyUc);
- info.setUidTraffic(new UidTraffic[]{
- new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000),
- new UidTraffic(APP_UID, 3000, 4000)
- });
+ info.setUidTraffic(new ArrayList<UidTraffic>(){{
+ add(new UidTraffic(Process.BLUETOOTH_UID, 1000, 2000));
+ add(new UidTraffic(APP_UID, 3000, 4000));
+ }});
mStatsRule.getBatteryStats().updateBluetoothStateLocked(info,
consumedEnergyUc, 1000, 1000);
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
index b24a22d..16f732f 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
@@ -22,6 +22,8 @@
import android.system.keystore2.Domain;
import android.system.keystore2.KeyDescriptor;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.security.Key;
/**
@@ -46,7 +48,11 @@
// We do not include this member in comparisons.
private final KeyStoreSecurityLevel mSecurityLevel;
- AndroidKeyStoreKey(@NonNull KeyDescriptor descriptor,
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public AndroidKeyStoreKey(@NonNull KeyDescriptor descriptor,
long keyId,
@NonNull Authorization[] authorizations,
@NonNull String algorithm,
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
index 4842984..0b3be32 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java
@@ -23,7 +23,7 @@
import android.system.keystore2.KeyMetadata;
import java.security.PublicKey;
-import java.util.Objects;
+import java.util.Arrays;
/**
* {@link PublicKey} backed by Android Keystore.
@@ -62,8 +62,8 @@
int result = 1;
result = prime * result + super.hashCode();
- result = prime * result + ((mCertificate == null) ? 0 : mCertificate.hashCode());
- result = prime * result + ((mCertificateChain == null) ? 0 : mCertificateChain.hashCode());
+ result = prime * result + Arrays.hashCode(mCertificate);
+ result = prime * result + Arrays.hashCode(mCertificateChain);
return result;
}
@@ -83,7 +83,7 @@
*/
final AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
- return Objects.equals(mCertificate, other.mCertificate) && Objects.equals(mCertificateChain,
+ return Arrays.equals(mCertificate, other.mCertificate) && Arrays.equals(mCertificateChain,
other.mCertificateChain);
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 67358c4..33411e1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -601,8 +601,6 @@
}
KeyProtection params = (KeyProtection) param;
- @SecurityLevel int securityLevel = params.isStrongBoxBacked() ? SecurityLevel.STRONGBOX :
- SecurityLevel.TRUSTED_ENVIRONMENT;
@Domain int targetDomain = (getTargetDomain());
if (key instanceof AndroidKeyStoreSecretKey) {
@@ -794,6 +792,9 @@
flags |= IKeystoreSecurityLevel.KEY_FLAG_AUTH_BOUND_WITHOUT_CRYPTOGRAPHIC_LSKF_BINDING;
}
+ @SecurityLevel int securityLevel = params.isStrongBoxBacked() ? SecurityLevel.STRONGBOX :
+ SecurityLevel.TRUSTED_ENVIRONMENT;
+
try {
KeyStoreSecurityLevel securityLevelInterface = mKeyStore.getSecurityLevel(
securityLevel);
diff --git a/keystore/tests/src/android/security/keystore2/AndroidKeyStoreSpiTest.java b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreSpiTest.java
index 1bd3069..f96c39c8 100644
--- a/keystore/tests/src/android/security/keystore2/AndroidKeyStoreSpiTest.java
+++ b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreSpiTest.java
@@ -24,7 +24,13 @@
import android.security.KeyStore2;
import android.security.KeyStoreException;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -52,4 +58,112 @@
verify(mKeystore2).list(anyInt(), anyLong());
}
+ @Mock
+ private KeyStoreSecurityLevel mKeystoreSecurityLevel;
+
+ private static KeyDescriptor descriptor() {
+ final KeyDescriptor keyDescriptor = new KeyDescriptor();
+ keyDescriptor.alias = "key";
+ keyDescriptor.blob = null;
+ keyDescriptor.domain = Domain.APP;
+ keyDescriptor.nspace = -1;
+ return keyDescriptor;
+ }
+
+ private static KeyMetadata metadata(byte[] cert, byte[] certChain) {
+ KeyMetadata metadata = new KeyMetadata();
+ metadata.authorizations = new Authorization[0];
+ metadata.certificate = cert;
+ metadata.certificateChain = certChain;
+ metadata.key = descriptor();
+ metadata.modificationTimeMs = 0;
+ metadata.keySecurityLevel = 1;
+ return metadata;
+ }
+
+ private static byte[] bytes(String string) {
+ return string.getBytes();
+ }
+
+ class MyPublicKey extends AndroidKeyStorePublicKey {
+ MyPublicKey(String cert, String chain, KeyStoreSecurityLevel securityLevel) {
+ super(descriptor(), metadata(cert.getBytes(), chain.getBytes()), "N/A".getBytes(),
+ "RSA", securityLevel);
+ }
+
+ @Override
+ AndroidKeyStorePrivateKey getPrivateKey() {
+ return null;
+ }
+ }
+
+ private AndroidKeyStorePublicKey makePrivateKeyObject(String cert, String chain) {
+ return new MyPublicKey(cert, chain, mKeystoreSecurityLevel);
+ }
+
+ @Test
+ public void testKeystoreKeysAdhereToContractBetweenEqualsAndHashCode() throws Exception {
+ AndroidKeyStoreKey key1 = new AndroidKeyStoreKey(descriptor(), 1, new Authorization[0],
+ "RSA", mKeystoreSecurityLevel);
+ AndroidKeyStoreKey key2 = new AndroidKeyStoreKey(descriptor(), 2, new Authorization[0],
+ "RSA", mKeystoreSecurityLevel);
+ AndroidKeyStoreKey key1_clone = new AndroidKeyStoreKey(descriptor(), 1,
+ new Authorization[0], "RSA", mKeystoreSecurityLevel);
+
+ assertThat("Identity should yield true", key1.equals(key1));
+ Assert.assertEquals("Identity should yield same hash codes",
+ key1.hashCode(), key1.hashCode());
+ assertThat("Identity should yield true", key2.equals(key2));
+ Assert.assertEquals("Identity should yield same hash codes",
+ key2.hashCode(), key2.hashCode());
+ assertThat("Different keys should differ", !key1.equals(key2));
+ Assert.assertNotEquals("Different keys should have different hash codes",
+ key1.hashCode(), key2.hashCode());
+
+ assertThat("Same keys should yield true", key1.equals(key1_clone));
+ assertThat("Same keys should yield true", key1_clone.equals(key1));
+ Assert.assertEquals("Same keys should yield same hash codes",
+ key1.hashCode(), key1_clone.hashCode());
+
+ assertThat("anything.equal(null) should yield false", !key1.equals(null));
+ assertThat("anything.equal(null) should yield false", !key2.equals(null));
+ assertThat("anything.equal(null) should yield false", !key1_clone.equals(null));
+ }
+
+ @Test
+ public void testKeystorePublicKeysAdhereToContractBetweenEqualsAndHashCode() throws Exception {
+ AndroidKeyStorePublicKey key1 = makePrivateKeyObject("myCert1", "myChain1");
+ AndroidKeyStorePublicKey key2 = makePrivateKeyObject("myCert2", "myChain1");
+ AndroidKeyStorePublicKey key3 = makePrivateKeyObject("myCert1", "myChain3");
+ AndroidKeyStorePublicKey key1_clone = makePrivateKeyObject("myCert1", "myChain1");
+
+ assertThat("Identity should yield true", key1.equals(key1));
+ Assert.assertEquals("Identity should yield same hash codes",
+ key1.hashCode(), key1.hashCode());
+ assertThat("Identity should yield true", key2.equals(key2));
+ Assert.assertEquals("Identity should yield same hash codes",
+ key2.hashCode(), key2.hashCode());
+ assertThat("Identity should yield true", key3.equals(key3));
+ Assert.assertEquals("Identity should yield same hash codes",
+ key3.hashCode(), key3.hashCode());
+ assertThat("Different keys should differ", !key1.equals(key2));
+ Assert.assertNotEquals("Different keys should have different hash codes",
+ key1.hashCode(), key2.hashCode());
+ assertThat("Different keys should differ", !key1.equals(key3));
+ Assert.assertNotEquals("Different keys should have different hash codes",
+ key1.hashCode(), key3.hashCode());
+ assertThat("Different keys should differ", !key2.equals(key3));
+ Assert.assertNotEquals("Different keys should have different hash codes",
+ key2.hashCode(), key3.hashCode());
+
+ assertThat("Same keys should yield true", key1.equals(key1_clone));
+ assertThat("Same keys should yield true", key1_clone.equals(key1));
+ Assert.assertEquals("Same keys should yield same hash codes",
+ key1.hashCode(), key1_clone.hashCode());
+
+ assertThat("anything.equal(null) should yield false", !key1.equals(null));
+ assertThat("anything.equal(null) should yield false", !key2.equals(null));
+ assertThat("anything.equal(null) should yield false", !key3.equals(null));
+ assertThat("anything.equal(null) should yield false", !key1_clone.equals(null));
+ }
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c068963..ed8cdb9 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5203,21 +5203,6 @@
}
}
- /**
- * @hide
- * Notifies AudioService that it is connected to an A2DP device that supports absolute volume,
- * so that AudioService can send volume change events to the A2DP device, rather than handling
- * them.
- */
- public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
- final IAudioService service = getService();
- try {
- service.avrcpSupportsAbsoluteVolume(address, support);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/**
* {@hide}
*/
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 7191280..dd44fdf 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -171,8 +171,6 @@
int getEncodedSurroundMode(int targetSdkVersion);
- oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
-
void setSpeakerphoneOn(IBinder cb, boolean on);
boolean isSpeakerphoneOn();
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 7e9d2d8..9c9e83b 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -106,7 +106,7 @@
@IntDef({
TYPE_UNKNOWN, TYPE_BUILTIN_SPEAKER, TYPE_WIRED_HEADSET,
TYPE_WIRED_HEADPHONES, TYPE_BLUETOOTH_A2DP, TYPE_HDMI, TYPE_USB_DEVICE,
- TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID,
+ TYPE_USB_ACCESSORY, TYPE_DOCK, TYPE_USB_HEADSET, TYPE_HEARING_AID, TYPE_BLE_HEADSET,
TYPE_REMOTE_TV, TYPE_REMOTE_SPEAKER, TYPE_GROUP})
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
@@ -202,6 +202,14 @@
public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
/**
+ * A route type describing a BLE HEADSET.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET;
+
+ /**
* A route type indicating the presentation of the media is happening on a TV.
*
* @see #getType
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 30a14c8..a0f6fb9 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1658,6 +1658,25 @@
*/
String COLUMN_CONTENT_ID = "content_id";
+ /**
+ * The start time of this TV program, in milliseconds since the epoch.
+ *
+ * <p>Should be empty if this program is not live.
+ *
+ * <p>Type: INTEGER (long)
+ * @see #COLUMN_LIVE
+ */
+ String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+
+ /**
+ * The end time of this TV program, in milliseconds since the epoch.
+ *
+ * <p>Should be empty if this program is not live.
+ *
+ * <p>Type: INTEGER (long)
+ * @see #COLUMN_LIVE
+ */
+ String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
}
/** Column definitions for the TV channels table. */
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index bc73f6a..c775b6f 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -183,8 +183,8 @@
"libmedia",
"libnativehelper",
"libutils",
- "tv_tuner_aidl_interface-ndk_platform",
- "tv_tuner_resource_manager_aidl_interface-ndk_platform",
+ "tv_tuner_aidl_interface-ndk",
+ "tv_tuner_resource_manager_aidl_interface-ndk",
],
static_libs: [
diff --git a/packages/SettingsLib/res/drawable/ic_bt_le_audio.xml b/packages/SettingsLib/res/drawable/ic_bt_le_audio.xml
new file mode 100644
index 0000000..5b52a04
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_le_audio.xml
@@ -0,0 +1,31 @@
+<!--
+ Copyright 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal" >
+ <path
+ android:pathData="M18.2,1L9.8,1C8.81,1 8,1.81 8,2.8v14.4c0,0.99 0.81,1.79 1.8,1.79l8.4,0.01c0.99,0 1.8,-0.81 1.8,-1.8L20,2.8c0,-0.99 -0.81,-1.8 -1.8,-1.8zM14,3c1.1,0 2,0.89 2,2s-0.9,2 -2,2 -2,-0.89 -2,-2 0.9,-2 2,-2zM14,16.5c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="M14,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="M6,5H4v16c0,1.1 0.89,2 2,2h10v-2H6V5z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6b840bd..a56c490 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -257,8 +257,12 @@
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. -->
<string name="bluetooth_profile_hearing_aid">Hearing Aids</string>
+ <!-- Bluetooth settings. The user-visible string that is used whenever referring to the LE_AUDIO profile. -->
+ <string name="bluetooth_profile_le_audio">LE_AUDIO</string>
<!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. -->
<string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aids</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the LE_AUDIO checkbox preference when LE_AUDIO is connected. -->
+ <string name="bluetooth_le_audio_profile_summary_connected">Connected to LE_AUDIO</string>
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. -->
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
@@ -299,6 +303,8 @@
<string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
<!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. -->
<string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aids</string>
+ <!-- Bluetooth settings. Connection options screen. The summary for the LE_AUDIO checkbox preference that describes how checking it will set the LE_AUDIO profile as preferred. -->
+ <string name="bluetooth_le_audio_profile_summary_use_for">Use for LE_AUDIO</string>
<!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
<string name="bluetooth_pairing_accept">Pair</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 8750309..58d2185 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -22,6 +22,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -116,6 +117,8 @@
addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED, new ActiveDeviceChangedHandler());
addHandler(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED,
new ActiveDeviceChangedHandler());
+ addHandler(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED,
+ new ActiveDeviceChangedHandler());
// Headset state changed broadcasts
addHandler(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
@@ -127,9 +130,6 @@
addHandler(BluetoothDevice.ACTION_ACL_CONNECTED, new AclStateChangedHandler());
addHandler(BluetoothDevice.ACTION_ACL_DISCONNECTED, new AclStateChangedHandler());
- addHandler(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE,
- new SetMemberAvailableHandler());
-
registerAdapterIntentReceiver();
}
@@ -455,6 +455,9 @@
bluetoothProfile = BluetoothProfile.HEADSET;
} else if (Objects.equals(action, BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED)) {
bluetoothProfile = BluetoothProfile.HEARING_AID;
+ } else if (Objects.equals(action,
+ BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED)) {
+ bluetoothProfile = BluetoothProfile.LE_AUDIO;
} else {
Log.w(TAG, "ActiveDeviceChangedHandler: unknown action " + action);
return;
@@ -515,29 +518,4 @@
dispatchAudioModeChanged();
}
}
-
- private class SetMemberAvailableHandler implements Handler {
- @Override
- public void onReceive(Context context, Intent intent, BluetoothDevice device) {
- final String action = intent.getAction();
- if (device == null) {
- Log.e(TAG, "SetMemberAvailableHandler: device is null");
- return;
- }
-
- if (action == null) {
- Log.e(TAG, "SetMemberAvailableHandler: action is null");
- return;
- }
-
- final int groupId = intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID,
- BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
- if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
- Log.e(TAG, "SetMemberAvailableHandler: Invalid group id");
- return;
- }
-
- mDeviceManager.onSetMemberAppear(device, groupId);
- }
- }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 7ce9b51..021ba224 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -69,6 +70,7 @@
// Some Hearing Aids (especially the 2nd device) needs more time to do service discovery
private static final long MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT = 15000;
private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
+ private static final long MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT = 30000;
private static final long MAX_MEDIA_PROFILE_CONNECT_DELAY = 60000;
private final Context mContext;
@@ -108,10 +110,12 @@
private boolean mIsActiveDeviceA2dp = false;
private boolean mIsActiveDeviceHeadset = false;
private boolean mIsActiveDeviceHearingAid = false;
+ private boolean mIsActiveDeviceLeAudio = false;
// Media profile connect state
private boolean mIsA2dpProfileConnectedFail = false;
private boolean mIsHeadsetProfileConnectedFail = false;
private boolean mIsHearingAidProfileConnectedFail = false;
+ private boolean mIsLeAudioProfileConnectedFail = false;
// Group second device for Hearing Aid
private CachedBluetoothDevice mSubDevice;
// Group member devices for the coordinated set
@@ -132,6 +136,9 @@
case BluetoothProfile.HEARING_AID:
mIsHearingAidProfileConnectedFail = true;
break;
+ case BluetoothProfile.LE_AUDIO:
+ mIsLeAudioProfileConnectedFail = true;
+ break;
default:
Log.w(TAG, "handleMessage(): unknown message : " + msg.what);
break;
@@ -265,6 +272,9 @@
case BluetoothProfile.HEARING_AID:
mIsHearingAidProfileConnectedFail = isFailed;
break;
+ case BluetoothProfile.LE_AUDIO:
+ mIsLeAudioProfileConnectedFail = isFailed;
+ break;
default:
Log.w(TAG, "setProfileConnectedStatus(): unknown profile id : " + profileId);
break;
@@ -540,6 +550,13 @@
result = true;
}
}
+ LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile();
+ if ((leAudioProfile != null) && isConnectedProfile(leAudioProfile)) {
+ if (leAudioProfile.setActiveDevice(getDevice())) {
+ Log.i(TAG, "OnPreferenceClickListener: LeAudio active device=" + this);
+ result = true;
+ }
+ }
return result;
}
@@ -618,6 +635,10 @@
changed = (mIsActiveDeviceHearingAid != isActive);
mIsActiveDeviceHearingAid = isActive;
break;
+ case BluetoothProfile.LE_AUDIO:
+ changed = (mIsActiveDeviceLeAudio != isActive);
+ mIsActiveDeviceLeAudio = isActive;
+ break;
default:
Log.w(TAG, "onActiveDeviceChanged: unknown profile " + bluetoothProfile +
" isActive " + isActive);
@@ -649,6 +670,8 @@
return mIsActiveDeviceHeadset;
case BluetoothProfile.HEARING_AID:
return mIsActiveDeviceHearingAid;
+ case BluetoothProfile.LE_AUDIO:
+ return mIsActiveDeviceLeAudio;
default:
Log.w(TAG, "getActiveDevice: unknown profile " + bluetoothProfile);
break;
@@ -743,6 +766,10 @@
if (hearingAidProfile != null) {
mIsActiveDeviceHearingAid = hearingAidProfile.getActiveDevices().contains(mDevice);
}
+ LeAudioProfile leAudio = mProfileManager.getLeAudioProfile();
+ if (leAudio != null) {
+ mIsActiveDeviceLeAudio = leAudio.getActiveDevices().contains(mDevice);
+ }
}
/**
@@ -757,6 +784,8 @@
timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
} else if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID)) {
timeout = MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT;
+ } else if (ArrayUtils.contains(uuids, BluetoothUuid.LE_AUDIO)) {
+ timeout = MAX_LEAUDIO_DELAY_FOR_AUTO_CONNECT;
}
if (BluetoothUtils.D) {
@@ -981,6 +1010,7 @@
boolean a2dpConnected = true; // A2DP is connected
boolean hfpConnected = true; // HFP is connected
boolean hearingAidConnected = true; // Hearing Aid is connected
+ boolean leAudioConnected = true; // LeAudio is connected
int leftBattery = -1;
int rightBattery = -1;
@@ -1012,6 +1042,8 @@
hfpConnected = false;
} else if (profile instanceof HearingAidProfile) {
hearingAidConnected = false;
+ } else if (profile instanceof LeAudioProfile) {
+ leAudioConnected = false;
}
}
break;
@@ -1054,7 +1086,8 @@
// 1. Hearing Aid device active.
// 2. Headset device active with in-calling state.
// 3. A2DP device active without in-calling state.
- if (a2dpConnected || hfpConnected || hearingAidConnected) {
+ // 4. Le Audio device active
+ if (a2dpConnected || hfpConnected || hearingAidConnected || leAudioConnected) {
final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
if ((mIsActiveDeviceHearingAid)
|| (mIsActiveDeviceHeadset && isOnCall)
@@ -1089,7 +1122,8 @@
private boolean isProfileConnectedFail() {
return mIsA2dpProfileConnectedFail || mIsHearingAidProfileConnectedFail
- || (!isConnectedSapDevice() && mIsHeadsetProfileConnectedFail);
+ || (!isConnectedSapDevice() && mIsHeadsetProfileConnectedFail)
+ || mIsLeAudioProfileConnectedFail;
}
/**
@@ -1100,6 +1134,7 @@
boolean a2dpNotConnected = false; // A2DP is preferred but not connected
boolean hfpNotConnected = false; // HFP is preferred but not connected
boolean hearingAidNotConnected = false; // Hearing Aid is preferred but not connected
+ boolean leAudioNotConnected = false; // LeAudio is preferred but not connected
synchronized (mProfileLock) {
for (LocalBluetoothProfile profile : getProfiles()) {
@@ -1125,6 +1160,8 @@
hfpNotConnected = true;
} else if (profile instanceof HearingAidProfile) {
hearingAidNotConnected = true;
+ } else if (profile instanceof LeAudioProfile) {
+ leAudioNotConnected = true;
}
}
break;
@@ -1163,6 +1200,11 @@
return mContext.getString(R.string.bluetooth_connected, activeDeviceString);
}
+ if (!leAudioNotConnected && mIsActiveDeviceLeAudio) {
+ activeDeviceString = activeDeviceStringsArray[1];
+ return mContext.getString(R.string.bluetooth_connected, activeDeviceString);
+ }
+
if (profileConnected) {
if (a2dpNotConnected && hfpNotConnected) {
if (batteryLevelPercentageString != null) {
@@ -1232,6 +1274,15 @@
BluetoothProfile.STATE_CONNECTED;
}
+ /**
+ * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio device
+ */
+ public boolean isConnectedLeAudioDevice() {
+ LeAudioProfile leAudio = mProfileManager.getLeAudioProfile();
+ return leAudio != null && leAudio.getConnectionStatus(mDevice) ==
+ BluetoothProfile.STATE_CONNECTED;
+ }
+
private boolean isConnectedSapDevice() {
SapProfile sapProfile = mProfileManager.getSapProfile();
return sapProfile != null && sapProfile.getConnectionStatus(mDevice)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 1f75ae3..b429fe6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -340,22 +340,24 @@
/**
* Called when we found a set member of a group. The function will check the {@code groupId} if
- * it exists and if there is a ongoing pair, the device would be ignored.
+ * it exists and the bond state of the device is BOND_NOE, and if there isn't any ongoing pair
+ * , and then return {@code true} to pair the device automatically.
*
* @param device The found device
* @param groupId The group id of the found device
+ *
+ * @return {@code true}, if the device should pair automatically; Otherwise, return
+ * {@code false}.
*/
- public synchronized void onSetMemberAppear(BluetoothDevice device, int groupId) {
- Log.d(TAG, "onSetMemberAppear, groupId: " + groupId + " device: " + device.toString());
-
- if (mOngoingSetMemberPair != null) {
- Log.d(TAG, "Ongoing set memberPairing in process, drop it!");
- return;
+ public synchronized boolean shouldPairByCsip(BluetoothDevice device, int groupId) {
+ if (mOngoingSetMemberPair != null || device.getBondState() != BluetoothDevice.BOND_NONE
+ || !mCsipDeviceManager.isExistedGroupId(groupId)) {
+ return false;
}
- if (mCsipDeviceManager.onSetMemberAppear(device, groupId)) {
- mOngoingSetMemberPair = device;
- }
+ Log.d(TAG, "Bond " + device.getName() + " by CSIP");
+ mOngoingSetMemberPair = device;
+ return true;
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 347e14b..1d29966 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -240,22 +240,15 @@
}
/**
- * Called when we found a set member of a group. The function will check bond state, and
- * the {@code groupId} if it exists, and then create the bond.
+ * Check if the {@code groupId} is existed.
*
- * @param device The found device
- * @param groupId The group id of the found device
+ * @param groupId The group id
*
- * @return {@code true}, if the we create bond with the device. Otherwise, return
- * {@code false}.
+ * @return {@code true}, if we could find a device with this {@code groupId}; Otherwise,
+ * return {@code false}.
*/
- public boolean onSetMemberAppear(BluetoothDevice device, int groupId) {
- if (device.getBondState() != BluetoothDevice.BOND_NONE) {
- return false;
- }
-
+ public boolean isExistedGroupId(int groupId) {
if (getCachedDevice(groupId) != null) {
- device.createBond(BluetoothDevice.TRANSPORT_LE);
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
new file mode 100644
index 0000000..209507a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -0,0 +1,264 @@
+/* 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 com.android.settingslib.bluetooth;
+
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+
+import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.Build;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class LeAudioProfile implements LocalBluetoothProfile {
+ private static final String TAG = "LeAudioProfile";
+ private static boolean DEBUG = true;
+
+ private Context mContext;
+
+ private BluetoothLeAudio mService;
+ private boolean mIsProfileReady;
+
+ private final CachedBluetoothDeviceManager mDeviceManager;
+
+ static final String NAME = "LE_AUDIO";
+ private final LocalBluetoothProfileManager mProfileManager;
+ private final BluetoothAdapter mBluetoothAdapter;
+
+ // Order of this profile in device profiles list
+ private static final int ORDINAL = 1;
+
+ // These callbacks run on the main thread.
+ private final class LeAudioServiceListener
+ implements BluetoothProfile.ServiceListener {
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (DEBUG) {
+ Log.d(TAG,"Bluetooth service connected");
+ }
+ mService = (BluetoothLeAudio) proxy;
+ // We just bound to the service, so refresh the UI for any connected LeAudio devices.
+ List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+ while (!deviceList.isEmpty()) {
+ BluetoothDevice nextDevice = deviceList.remove(0);
+ CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+ // we may add a new device here, but generally this should not happen
+ if (device == null) {
+ if (DEBUG) {
+ Log.d(TAG, "LeAudioProfile found new device: " + nextDevice);
+ }
+ device = mDeviceManager.addDevice(nextDevice);
+ }
+ device.onProfileStateChanged(LeAudioProfile.this,
+ BluetoothProfile.STATE_CONNECTED);
+ device.refresh();
+ }
+
+ mProfileManager.callServiceConnectedListeners();
+ mIsProfileReady = true;
+ }
+
+ public void onServiceDisconnected(int profile) {
+ if (DEBUG) {
+ Log.d(TAG,"Bluetooth service disconnected");
+ }
+ mProfileManager.callServiceDisconnectedListeners();
+ mIsProfileReady = false;
+ }
+ }
+
+ public boolean isProfileReady() {
+ return mIsProfileReady;
+ }
+
+ @Override
+ public int getProfileId() {
+ return BluetoothProfile.LE_AUDIO;
+ }
+
+ LeAudioProfile(Context context, CachedBluetoothDeviceManager deviceManager,
+ LocalBluetoothProfileManager profileManager) {
+ mContext = context;
+ mDeviceManager = deviceManager;
+ mProfileManager = profileManager;
+
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mBluetoothAdapter.getProfileProxy(
+ context, new LeAudioServiceListener(),
+ BluetoothProfile.LE_AUDIO);
+ }
+
+ public boolean accessProfileEnabled() {
+ return true;
+ }
+
+ public boolean isAutoConnectable() {
+ return true;
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService == null) {
+ return new ArrayList<BluetoothDevice>(0);
+ }
+ return mService.getDevicesMatchingConnectionStates(
+ new int[] {BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTING});
+ }
+
+ /*
+ * @hide
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (mService == null) {
+ return false;
+ }
+ return mService.connect(device);
+ }
+
+ /*
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (mService == null) {
+ return false;
+ }
+ return mService.disconnect(device);
+ }
+
+ public int getConnectionStatus(BluetoothDevice device) {
+ if (mService == null) {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ return mService.getConnectionState(device);
+ }
+
+ public boolean setActiveDevice(BluetoothDevice device) {
+ if (mBluetoothAdapter == null) {
+ return false;
+ }
+ return device == null
+ ? mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_ALL)
+ : mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_ALL);
+ }
+
+ public List<BluetoothDevice> getActiveDevices() {
+ if (mService == null) {
+ return new ArrayList<>();
+ }
+ return mService.getActiveDevices();
+ }
+
+ @Override
+ public boolean isEnabled(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return false;
+ }
+ return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
+ }
+
+ @Override
+ public int getConnectionPolicy(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return CONNECTION_POLICY_FORBIDDEN;
+ }
+ return mService.getConnectionPolicy(device);
+ }
+
+ @Override
+ public boolean setEnabled(BluetoothDevice device, boolean enabled) {
+ boolean isEnabled = false;
+ if (mService == null || device == null) {
+ return false;
+ }
+ if (enabled) {
+ if (mService.getConnectionPolicy(device) < CONNECTION_POLICY_ALLOWED) {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
+ }
+ } else {
+ isEnabled = mService.setConnectionPolicy(device, CONNECTION_POLICY_FORBIDDEN);
+ }
+
+ return isEnabled;
+ }
+
+ public String toString() {
+ return NAME;
+ }
+
+ public int getOrdinal() {
+ return ORDINAL;
+ }
+
+ public int getNameResource(BluetoothDevice device) {
+ return R.string.bluetooth_profile_le_audio;
+ }
+
+ public int getSummaryResourceForDevice(BluetoothDevice device) {
+ int state = getConnectionStatus(device);
+ switch (state) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ return R.string.bluetooth_le_audio_profile_summary_use_for;
+
+ case BluetoothProfile.STATE_CONNECTED:
+ return R.string.bluetooth_le_audio_profile_summary_connected;
+
+ default:
+ return BluetoothUtils.getConnectionStateSummary(state);
+ }
+ }
+
+ public int getDrawableResource(BluetoothClass btClass) {
+ return R.drawable.ic_bt_le_audio;
+ }
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ protected void finalize() {
+ if (DEBUG) {
+ Log.d(TAG, "finalize()");
+ }
+ if (mService != null) {
+ try {
+ BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.LE_AUDIO,
+ mService);
+ mService = null;
+ }catch (Throwable t) {
+ Log.w(TAG, "Error cleaning up LeAudio proxy", t);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index bcb3455..3347920 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -24,6 +24,7 @@
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothHidDevice;
import android.bluetooth.BluetoothHidHost;
import android.bluetooth.BluetoothMap;
@@ -102,6 +103,7 @@
private PbapServerProfile mPbapProfile;
private HearingAidProfile mHearingAidProfile;
private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile;
+ private LeAudioProfile mLeAudioProfile;
private SapProfile mSapProfile;
private VolumeControlProfile mVolumeControlProfile;
@@ -232,6 +234,14 @@
// Note: no event handler for VCP, only for being connectable.
mProfileNameMap.put(VolumeControlProfile.NAME, mVolumeControlProfile);
}
+ if (mLeAudioProfile == null && supportedList.contains(BluetoothProfile.LE_AUDIO)) {
+ if (DEBUG) {
+ Log.d(TAG, "Adding local LE_AUDIO profile");
+ }
+ mLeAudioProfile = new LeAudioProfile(mContext, mDeviceManager, this);
+ addProfile(mLeAudioProfile, LeAudioProfile.NAME,
+ BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
+ }
if (mCsipSetCoordinatorProfile == null
&& supportedList.contains(BluetoothProfile.CSIP_SET_COORDINATOR)) {
if (DEBUG) {
@@ -487,6 +497,10 @@
return mHearingAidProfile;
}
+ public LeAudioProfile getLeAudioProfile() {
+ return mLeAudioProfile;
+ }
+
SapProfile getSapProfile() {
return mSapProfile;
}
@@ -614,6 +628,11 @@
removedProfiles.remove(mHearingAidProfile);
}
+ if (ArrayUtils.contains(uuids, BluetoothUuid.LE_AUDIO) && mLeAudioProfile != null) {
+ profiles.add(mLeAudioProfile);
+ removedProfiles.remove(mLeAudioProfile);
+ }
+
if (mSapProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.SAP)) {
profiles.add(mSapProfile);
removedProfiles.remove(mSapProfile);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3c43f4a6..54230c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -21,6 +21,7 @@
import static android.media.MediaRoute2Info.TYPE_GROUP;
import static android.media.MediaRoute2Info.TYPE_HDMI;
import static android.media.MediaRoute2Info.TYPE_HEARING_AID;
+import static android.media.MediaRoute2Info.TYPE_BLE_HEADSET;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_TV;
import static android.media.MediaRoute2Info.TYPE_UNKNOWN;
@@ -481,6 +482,7 @@
break;
case TYPE_HEARING_AID:
case TYPE_BLUETOOTH_A2DP:
+ case TYPE_BLE_HEADSET:
final BluetoothDevice device =
BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getAddress());
final CachedBluetoothDevice cachedDevice =
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 22001c9..215e2a0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -38,6 +38,7 @@
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
+import com.android.settingslib.bluetooth.LeAudioProfile;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -440,6 +441,7 @@
private boolean isActiveDevice(CachedBluetoothDevice device) {
boolean isActiveDeviceA2dp = false;
boolean isActiveDeviceHearingAid = false;
+ boolean isActiveLeAudio = false;
final A2dpProfile a2dpProfile = mLocalBluetoothManager.getProfileManager().getA2dpProfile();
if (a2dpProfile != null) {
isActiveDeviceA2dp = device.getDevice().equals(a2dpProfile.getActiveDevice());
@@ -453,7 +455,15 @@
}
}
- return isActiveDeviceA2dp || isActiveDeviceHearingAid;
+ if (!isActiveDeviceA2dp && !isActiveDeviceHearingAid) {
+ final LeAudioProfile leAudioProfile = mLocalBluetoothManager.getProfileManager()
+ .getLeAudioProfile();
+ if (leAudioProfile != null) {
+ isActiveLeAudio = leAudioProfile.getActiveDevices().contains(device.getDevice());
+ }
+ }
+
+ return isActiveDeviceA2dp || isActiveDeviceHearingAid || isActiveLeAudio;
}
private Collection<DeviceCallback> getCallbacks() {
@@ -526,7 +536,7 @@
if (cachedDevice != null) {
if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&& !cachedDevice.isConnected()
- && isA2dpOrHearingAidDevice(cachedDevice)) {
+ && isMediaDevice(cachedDevice)) {
deviceCount++;
cachedBluetoothDeviceList.add(cachedDevice);
if (deviceCount >= MAX_DISCONNECTED_DEVICE_NUM) {
@@ -550,9 +560,10 @@
return new ArrayList<>(mDisconnectedMediaDevices);
}
- private boolean isA2dpOrHearingAidDevice(CachedBluetoothDevice device) {
+ private boolean isMediaDevice(CachedBluetoothDevice device) {
for (LocalBluetoothProfile profile : device.getConnectableProfiles()) {
- if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile) {
+ if (profile instanceof A2dpProfile || profile instanceof HearingAidProfile ||
+ profile instanceof LeAudioProfile) {
return true;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index f21c359..a49d7f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -29,6 +29,7 @@
import static android.media.MediaRoute2Info.TYPE_USB_HEADSET;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import static android.media.MediaRoute2Info.TYPE_BLE_HEADSET;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -122,6 +123,7 @@
break;
case TYPE_HEARING_AID:
case TYPE_BLUETOOTH_A2DP:
+ case TYPE_BLE_HEADSET:
mType = MediaDeviceType.TYPE_BLUETOOTH_DEVICE;
break;
case TYPE_UNKNOWN:
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
index e887c450..f50802a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
@@ -52,6 +52,7 @@
when(mDevice.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(true);
when(mDevice.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true);
+ when(mDevice.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
mBluetoothMediaDevice = new BluetoothMediaDevice(mContext, mDevice, null, null, null);
}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index 46bda06..27d4ea7 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -21,6 +21,7 @@
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserManager;
import android.util.Log;
import android.webkit.PacProcessor;
@@ -33,16 +34,44 @@
public class PacService extends Service {
private static final String TAG = "PacService";
- private Object mLock = new Object();
+ private final Object mLock = new Object();
+ // Webkit PacProcessor cannot be instantiated before the user is unlocked, so this field is
+ // initialized lazily.
@GuardedBy("mLock")
- private final PacProcessor mPacProcessor = PacProcessor.getInstance();
+ private PacProcessor mPacProcessor;
+
+ // Stores PAC script when setPacFile is called before mPacProcessor is available. In case the
+ // script was already fed to the PacProcessor, it should be null.
+ @GuardedBy("mLock")
+ private String mPendingScript;
private ProxyServiceStub mStub = new ProxyServiceStub();
@Override
public void onCreate() {
super.onCreate();
+
+ synchronized (mLock) {
+ checkPacProcessorLocked();
+ }
+ }
+
+ /**
+ * Initializes PacProcessor if it hasn't been initialized yet and if the system user is
+ * unlocked, e.g. after the user has entered their PIN after a reboot.
+ * Returns whether PacProcessor is available.
+ */
+ private boolean checkPacProcessorLocked() {
+ if (mPacProcessor != null) {
+ return true;
+ }
+ UserManager um = getSystemService(UserManager.class);
+ if (um.isUserUnlocked()) {
+ mPacProcessor = PacProcessor.getInstance();
+ return true;
+ }
+ return false;
}
@Override
@@ -74,7 +103,20 @@
}
synchronized (mLock) {
- return mPacProcessor.findProxyForUrl(url);
+ if (checkPacProcessorLocked()) {
+ // Apply pending script in case it was set before processor was ready.
+ if (mPendingScript != null) {
+ if (!mPacProcessor.setProxyScript(mPendingScript)) {
+ Log.e(TAG, "Unable to parse proxy script.");
+ }
+ mPendingScript = null;
+ }
+ return mPacProcessor.findProxyForUrl(url);
+ } else {
+ Log.e(TAG, "PacProcessor isn't ready during early boot,"
+ + " request will be direct");
+ return null;
+ }
}
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid URL was passed");
@@ -88,8 +130,13 @@
throw new SecurityException();
}
synchronized (mLock) {
- if (!mPacProcessor.setProxyScript(script)) {
- Log.e(TAG, "Unable to parse proxy script.");
+ if (checkPacProcessorLocked()) {
+ if (!mPacProcessor.setProxyScript(script)) {
+ Log.e(TAG, "Unable to parse proxy script.");
+ }
+ } else {
+ Log.d(TAG, "PAC processor isn't ready, saving script for later.");
+ mPendingScript = script;
}
}
}
diff --git a/proto/src/criticalevents/OWNERS b/proto/src/criticalevents/OWNERS
new file mode 100644
index 0000000..07c0e70
--- /dev/null
+++ b/proto/src/criticalevents/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/criticalevents/OWNERS
diff --git a/services/companion/OWNERS b/services/companion/OWNERS
new file mode 100644
index 0000000..cb4cc56
--- /dev/null
+++ b/services/companion/OWNERS
@@ -0,0 +1,4 @@
+evanxinchen@google.com
+ewol@google.com
+guojing@google.com
+svetoslavganov@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index fdba098..469f465 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -476,7 +476,11 @@
*/
public static void addTombstoneToDropBox(Context ctx, File tombstone, boolean proto) {
final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
- final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
+ if (db == null) {
+ Slog.e(TAG, "Can't log tombstone: DropBoxManager not available");
+ return;
+ }
+
HashMap<String, Long> timestamps = readTimestamps();
try {
if (proto) {
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 95dc667..b641377 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -16,6 +16,9 @@
# ServiceWatcher
per-file ServiceWatcher.java = sooniln@google.com
+# Health
+per-file BatteryService.java = file:platform/hardware/interfaces:/health/aidl/OWNERS
+
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
per-file *AppOp* = file:/core/java/android/permission/OWNERS
per-file *Battery* = file:/BATTERY_STATS_OWNERS
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index edf832f..c11c4de 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -385,6 +385,10 @@
private int[] mAllowedNetworkTypeReason;
private long[] mAllowedNetworkTypeValue;
+ private static final List<LinkCapacityEstimate> INVALID_LCE_LIST =
+ new ArrayList<LinkCapacityEstimate>(Arrays.asList(new LinkCapacityEstimate(
+ LinkCapacityEstimate.LCE_TYPE_COMBINED,
+ LinkCapacityEstimate.INVALID, LinkCapacityEstimate.INVALID)));
private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists;
/**
@@ -719,7 +723,7 @@
mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
- mLinkCapacityEstimateLists.add(i, new ArrayList<>());
+ mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
}
}
@@ -819,7 +823,7 @@
mPhysicalChannelConfigs.add(i, new ArrayList<>());
mAllowedNetworkTypeReason[i] = -1;
mAllowedNetworkTypeValue[i] = -1;
- mLinkCapacityEstimateLists.add(i, new ArrayList<>());
+ mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST);
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index a03425c..b48e21e 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -681,7 +681,7 @@
intentFilter = new IntentFilter();
intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
mUserAllContext.registerReceiver(
- mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
+ mIntentReceiver, intentFilter, NETWORK_STACK, mHandler, Context.RECEIVER_EXPORTED);
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a2fec27..a29a49c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4906,7 +4906,9 @@
sr.setProcess(null, null, 0, null);
sr.isolatedProc = null;
sr.executeNesting = 0;
- sr.forceClearTracker();
+ synchronized (mAm.mProcessStats.mLock) {
+ sr.forceClearTracker();
+ }
if (mDestroyingServices.remove(sr)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
@@ -5056,7 +5058,9 @@
i--;
ServiceRecord sr = mDestroyingServices.get(i);
if (sr.app == app) {
- sr.forceClearTracker();
+ synchronized (mAm.mProcessStats.mLock) {
+ sr.forceClearTracker();
+ }
mDestroyingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "killServices remove destroying " + sr);
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 503b3a9..94bf62f 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1568,17 +1568,23 @@
perm = PackageManager.PERMISSION_DENIED;
}
- if (perm == PackageManager.PERMISSION_GRANTED) {
- skip = true;
- break;
- }
-
int appOp = AppOpsManager.permissionToOpCode(excludedPermission);
if (appOp != AppOpsManager.OP_NONE) {
- if (mService.getAppOpsManager().checkOpNoThrow(appOp,
+ // When there is an app op associated with the permission,
+ // skip when both the permission and the app op are
+ // granted.
+ if ((perm == PackageManager.PERMISSION_GRANTED) && (
+ mService.getAppOpsManager().checkOpNoThrow(appOp,
info.activityInfo.applicationInfo.uid,
info.activityInfo.packageName)
- == AppOpsManager.MODE_ALLOWED) {
+ == AppOpsManager.MODE_ALLOWED)) {
+ skip = true;
+ break;
+ }
+ } else {
+ // When there is no app op associated with the permission,
+ // skip when permission is granted.
+ if (perm == PackageManager.PERMISSION_GRANTED) {
skip = true;
break;
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 2f20efb..3ccacd8 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -87,6 +87,7 @@
DeviceConfig.NAMESPACE_LMKD_NATIVE,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
DeviceConfig.NAMESPACE_NETD_NATIVE,
+ DeviceConfig.NAMESPACE_NNAPI_NATIVE,
DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 38f71ba..c383f51 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -22,6 +22,7 @@
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothLeAudio;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -503,6 +504,18 @@
}
}
+ /*package*/ static final class BleVolumeInfo {
+ final int mIndex;
+ final int mMaxIndex;
+ final int mStreamType;
+
+ BleVolumeInfo(int index, int maxIndex, int streamType) {
+ mIndex = index;
+ mMaxIndex = maxIndex;
+ mStreamType = streamType;
+ }
+ };
+
/*package*/ static final class BtDeviceConnectionInfo {
final @NonNull BluetoothDevice mDevice;
final @AudioService.BtProfileConnectionState int mState;
@@ -711,6 +724,11 @@
sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
}
+ /*package*/ void postSetLeAudioVolumeIndex(int index, int maxIndex, int streamType) {
+ BleVolumeInfo info = new BleVolumeInfo(index, maxIndex, streamType);
+ sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
+ }
+
/*package*/ void postSetModeOwnerPid(int pid, int mode) {
sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
}
@@ -851,6 +869,10 @@
return mAudioService.getVssVolumeForDevice(streamType, device);
}
+ /*package*/ int getMaxVssVolumeForStream(int streamType) {
+ return mAudioService.getMaxVssVolumeForStream(streamType);
+ }
+
/*package*/ int getDeviceForStream(int streamType) {
return mAudioService.getDeviceForStream(streamType);
}
@@ -962,6 +984,10 @@
sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
}
+ /*package*/ void postDisconnectLeAudio() {
+ sendMsgNoDelay(MSG_DISCONNECT_BT_LE_AUDIO, SENDMSG_QUEUE);
+ }
+
/*package*/ void postDisconnectHeadset() {
sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
}
@@ -983,6 +1009,11 @@
hearingAidProfile);
}
+ /*package*/ void postBtLeAudioProfileConnected(BluetoothLeAudio leAudioProfile) {
+ sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO, SENDMSG_QUEUE,
+ leAudioProfile);
+ }
+
/*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) {
sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, client);
}
@@ -1321,6 +1352,12 @@
mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
}
break;
+ case MSG_II_SET_LE_AUDIO_OUT_VOLUME: {
+ final BleVolumeInfo info = (BleVolumeInfo) msg.obj;
+ synchronized (mDeviceStateLock) {
+ mBtHelper.setLeAudioVolume(info.mIndex, info.mMaxIndex, info.mStreamType);
+ }
+ } break;
case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME:
synchronized (mDeviceStateLock) {
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
@@ -1384,6 +1421,11 @@
}
}
break;
+ case MSG_DISCONNECT_BT_LE_AUDIO:
+ synchronized(mDeviceStateLock) {
+ mDeviceInventory.disconnectLeAudio();
+ }
+ break;
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
synchronized (mDeviceStateLock) {
mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
@@ -1399,6 +1441,12 @@
mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
}
break;
+
+ case MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO:
+ synchronized(mDeviceStateLock) {
+ mBtHelper.onLeAudioProfileConnected((BluetoothLeAudio) msg.obj);
+ }
+ break;
case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
@@ -1586,6 +1634,11 @@
private static final int MSG_IL_SET_LE_AUDIO_IN_CONNECTION_STATE = 43;
private static final int MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT = 44;
private static final int MSG_L_LE_AUDIO_DEVICE_IN_CONNECTION_CHANGE_EXT = 45;
+ // process set volume for Le Audio, obj is BleVolumeInfo
+ private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46;
+
+ private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_LE_AUDIO = 47;
+ private static final int MSG_DISCONNECT_BT_LE_AUDIO = 48;
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
@@ -1714,10 +1767,12 @@
MESSAGES_MUTE_MUSIC = new HashSet<>();
MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED);
MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED);
+ MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_LE_AUDIO_OUT_CONNECTION_STATE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_LE_AUDIO_DEVICE_OUT_CONNECTION_CHANGE_EXT);
MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE);
MESSAGES_MUTE_MUSIC.add(MSG_REPORT_NEW_ROUTES_A2DP);
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 64e620e..6c3c736 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -887,6 +887,28 @@
}
}
+ /*package*/ void disconnectLeAudio() {
+ synchronized (mDevicesLock) {
+ final ArraySet<String> toRemove = new ArraySet<>();
+ // Disconnect ALL DEVICE_OUT_BLE_HEADSET devices
+ mConnectedDevices.values().forEach(deviceInfo -> {
+ if (deviceInfo.mDeviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) {
+ toRemove.add(deviceInfo.mDeviceAddress);
+ }
+ });
+ new MediaMetrics.Item(mMetricsId + "disconnectLeAudio")
+ .record();
+ if (toRemove.size() > 0) {
+ final int delay = checkSendBecomingNoisyIntentInt(
+ AudioSystem.DEVICE_OUT_BLE_HEADSET, 0, AudioSystem.DEVICE_NONE);
+ toRemove.stream().forEach(deviceAddress ->
+ makeLeAudioDeviceUnavailable(deviceAddress,
+ AudioSystem.DEVICE_OUT_BLE_HEADSET)
+ );
+ }
+ }
+ }
+
// must be called before removing the device from mConnectedDevices
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
// from AudioSystem
@@ -1195,6 +1217,10 @@
return;
}
+ final int leAudioVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
+ AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType);
+ mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType);
mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable");
}
@@ -1243,6 +1269,7 @@
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_BLE_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bf5f4c2..d75f21c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -334,6 +334,10 @@
return mStreamStates[stream].getIndex(device);
}
+ /*package*/ int getMaxVssVolumeForStream(int stream) {
+ return mStreamStates[stream].getMaxIndex();
+ }
+
private SettingsObserver mSettingsObserver;
private AtomicInteger mMode = new AtomicInteger(AudioSystem.MODE_NORMAL);
@@ -2952,6 +2956,16 @@
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
}
+ if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET
+ && streamType == getBluetoothContextualVolumeStream()) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
+ + newIndex + " stream=" + streamType);
+ }
+ mDeviceBroker.postSetLeAudioVolumeIndex(newIndex,
+ mStreamStates[streamType].getMaxIndex(), streamType);
+ }
+
// Check if volume update should be send to Hearing Aid
if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
// only modify the hearing aid attenuation when the stream to modify matches
@@ -3580,6 +3594,16 @@
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
}
+ if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET
+ && streamType == getBluetoothContextualVolumeStream()) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
+ + index + " stream=" + streamType);
+ }
+ mDeviceBroker.postSetLeAudioVolumeIndex(index,
+ mStreamStates[streamType].getMaxIndex(), streamType);
+ }
+
if (device == AudioSystem.DEVICE_OUT_HEARING_AID
&& streamType == getBluetoothContextualVolumeStream()) {
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
@@ -6112,6 +6136,11 @@
if (pkgName == null) {
pkgName = "";
}
+ if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) {
+ avrcpSupportsAbsoluteVolume(device.getAddress(),
+ deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ return;
+ }
int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
device.getType());
@@ -7768,7 +7797,7 @@
}
}
- public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
+ private void avrcpSupportsAbsoluteVolume(String address, boolean support) {
// address is not used for now, but may be used when multiple a2dp devices are supported
sVolumeLogger.log(new AudioEventLogger.StringEvent("avrcpSupportsAbsoluteVolume addr="
+ address + " support=" + support));
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 0eb5a5d..3137fa5 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -155,6 +155,7 @@
static final int VOL_MODE_CHANGE_HEARING_AID = 7;
static final int VOL_SET_GROUP_VOL = 8;
static final int VOL_MUTE_STREAM_INT = 9;
+ static final int VOL_SET_LE_AUDIO_VOL = 10;
final int mOp;
final int mStream;
@@ -310,6 +311,13 @@
.set(MediaMetrics.Property.INDEX, mVal1)
.record();
return;
+ case VOL_SET_LE_AUDIO_VOL:
+ new MediaMetrics.Item(mMetricsId)
+ .set(MediaMetrics.Property.EVENT, "setLeAudioVolume")
+ .set(MediaMetrics.Property.INDEX, mVal1)
+ .set(MediaMetrics.Property.MAX_INDEX, mVal2)
+ .record();
+ return;
case VOL_SET_AVRCP_VOL:
new MediaMetrics.Item(mMetricsId)
.set(MediaMetrics.Property.EVENT, "setAvrcpVolume")
@@ -382,6 +390,11 @@
.append(" index:").append(mVal1)
.append(" gain dB:").append(mVal2)
.toString();
+ case VOL_SET_LE_AUDIO_VOL:
+ return new StringBuilder("setLeAudioVolume:")
+ .append(" index:").append(mVal1)
+ .append(" gain dB:").append(mVal2)
+ .toString();
case VOL_SET_AVRCP_VOL:
return new StringBuilder("setAvrcpVolume:")
.append(" index:").append(mVal1)
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 52e8edf..c924fde 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -25,6 +25,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
@@ -63,6 +64,8 @@
private @Nullable BluetoothHearingAid mHearingAid;
+ private @Nullable BluetoothLeAudio mLeAudio;
+
// Reference to BluetoothA2dp to query for AbsoluteVolume.
private @Nullable BluetoothA2dp mA2dp;
@@ -106,6 +109,8 @@
private static final int SCO_MODE_MAX = 2;
private static final int BT_HEARING_AID_GAIN_MIN = -128;
+ private static final int BT_LE_AUDIO_MIN_VOL = 0;
+ private static final int BT_LE_AUDIO_MAX_VOL = 255;
/**
* Returns a string representation of the scoAudioMode.
@@ -235,6 +240,8 @@
mBluetoothProfileServiceListener, BluetoothProfile.A2DP);
adapter.getProfileProxy(mDeviceBroker.getContext(),
mBluetoothProfileServiceListener, BluetoothProfile.HEARING_AID);
+ adapter.getProfileProxy(mDeviceBroker.getContext(),
+ mBluetoothProfileServiceListener, BluetoothProfile.LE_AUDIO);
}
}
@@ -389,6 +396,26 @@
return requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, SCO_MODE_VIRTUAL_CALL);
}
+ /*package*/ synchronized void setLeAudioVolume(int index, int maxIndex, int streamType) {
+ if (mLeAudio == null) {
+ if (AudioService.DEBUG_VOL) {
+ Log.i(TAG, "setLeAudioVolume: null mLeAudio");
+ }
+ return;
+ }
+ /* leaudio expect volume value in range 0 to 255
+ */
+ int volume = (index * (BT_LE_AUDIO_MAX_VOL - BT_LE_AUDIO_MIN_VOL)) / maxIndex ;
+
+ if (AudioService.DEBUG_VOL) {
+ Log.i(TAG, "setLeAudioVolume: calling mLeAudio.setVolume idx="
+ + index + " volume=" + volume);
+ }
+ AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
+ AudioServiceEvents.VolumeEvent.VOL_SET_LE_AUDIO_VOL, index, maxIndex));
+ mLeAudio.setVolume(volume);
+ }
+
/*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
if (mHearingAid == null) {
if (AudioService.DEBUG_VOL) {
@@ -428,6 +455,7 @@
mDeviceBroker.postDisconnectA2dpSink();
mDeviceBroker.postDisconnectHeadset();
mDeviceBroker.postDisconnectHearingAid();
+ mDeviceBroker.postDisconnectLeAudio();
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@@ -488,6 +516,23 @@
/*eventSource*/ "mBluetoothProfileServiceListener");
}
+ /*package*/ synchronized void onLeAudioProfileConnected(BluetoothLeAudio leAudio) {
+ mLeAudio = leAudio;
+ final List<BluetoothDevice> deviceList = mLeAudio.getConnectedDevices();
+ if (deviceList.isEmpty()) {
+ return;
+ }
+
+ final BluetoothDevice btDevice = deviceList.get(0);
+ final @BluetoothProfile.BtProfileState int state =
+ mLeAudio.getConnectionState(btDevice);
+ mDeviceBroker.postBluetoothLeAudioOutDeviceConnectionState(
+ btDevice, state,
+ /*suppressNoisyIntent*/ false,
+ /*musicDevice android.media.AudioSystem.DEVICE_NONE,*/
+ /*eventSource*/ "mBluetoothProfileServiceListener");
+ }
+
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
@@ -655,6 +700,13 @@
mDeviceBroker.postBtHearingAidProfileConnected(
(BluetoothHearingAid) proxy);
break;
+
+ case BluetoothProfile.LE_AUDIO:
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "BT profile service: connecting LE_AUDIO profile"));
+ mDeviceBroker.postBtLeAudioProfileConnected(
+ (BluetoothLeAudio) proxy);
+ break;
default:
break;
}
@@ -677,6 +729,9 @@
case BluetoothProfile.HEARING_AID:
mDeviceBroker.postDisconnectHearingAid();
break;
+ case BluetoothProfile.LE_AUDIO:
+ mDeviceBroker.postDisconnectLeAudio();
+ break;
default:
break;
@@ -899,6 +954,7 @@
pw.println(prefix + "mScoAudioState: " + scoAudioStateToString(mScoAudioState));
pw.println(prefix + "mScoAudioMode: " + scoAudioModeToString(mScoAudioMode));
pw.println("\n" + prefix + "mHearingAid: " + mHearingAid);
+ pw.println("\n" + prefix + "mLeAudio: " + mLeAudio);
pw.println(prefix + "mA2dp: " + mA2dp);
pw.println(prefix + "mAvrcpAbsVolSupported: " + mAvrcpAbsVolSupported);
}
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 091e6c4..a56a8ea 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -227,7 +227,7 @@
subscriberId = tele.getSubscriberId();
mNetworkTemplate = new NetworkTemplate(
NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
- null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL,
NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
mUsageCallback = new UsageCallback() {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 565c9ae..243a336b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1270,6 +1270,9 @@
capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
}
+ capsBuilder.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
+ ? Arrays.asList(mConfig.underlyingNetworks) : null);
+
mNetworkCapabilities = capsBuilder.build();
mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
mNetworkCapabilities, lp,
@@ -1290,8 +1293,6 @@
} finally {
Binder.restoreCallingIdentity(token);
}
- mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
- ? Arrays.asList(mConfig.underlyingNetworks) : null);
updateState(DetailedState.CONNECTED, "agentConnect");
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d66d7ee..329a696 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -512,7 +512,10 @@
*/
public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
synchronized (mLock) {
- mAlwaysRespectAppRequest = enabled;
+ if (mAlwaysRespectAppRequest != enabled) {
+ mAlwaysRespectAppRequest = enabled;
+ notifyDesiredDisplayModeSpecsChangedLocked();
+ }
}
}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 7afa81a..73de0f8 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -26,6 +26,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -56,6 +57,7 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
+ private static final String LE_AUDIO_ROUTE_ID_PREFIX = "LE_AUDIO_";
@SuppressWarnings("WeakerAccess") /* synthetic access */
// Maps hardware address to BluetoothRouteInfo
@@ -66,6 +68,8 @@
BluetoothA2dp mA2dpProfile;
@SuppressWarnings("WeakerAccess") /* synthetic access */
BluetoothHearingAid mHearingAidProfile;
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ BluetoothLeAudio mLeAudioProfile;
// Route type -> volume map
private final SparseIntArray mVolumeMap = new SparseIntArray();
@@ -108,6 +112,7 @@
public void start(UserHandle user) {
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID);
+ mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.LE_AUDIO);
// Bluetooth on/off broadcasts
addEventReceiver(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedReceiver());
@@ -119,6 +124,10 @@
deviceStateChangedReceiver);
addEventReceiver(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED,
deviceStateChangedReceiver);
+ addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED,
+ deviceStateChangedReceiver);
+ addEventReceiver(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED,
+ deviceStateChangedReceiver);
mContext.registerReceiverAsUser(mBroadcastReceiver, user,
mIntentFilter, null, null);
@@ -240,6 +249,8 @@
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
| AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
routeType = MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
+ } else if ((devices & (AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0) {
+ routeType = MediaRoute2Info.TYPE_BLE_HEADSET;
} else {
return false;
}
@@ -288,6 +299,12 @@
routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device);
type = MediaRoute2Info.TYPE_HEARING_AID;
}
+ if (mLeAudioProfile != null
+ && mLeAudioProfile.getConnectedDevices().contains(device)) {
+ newBtRoute.connectedProfiles.put(BluetoothProfile.LE_AUDIO, true);
+ routeId = LE_AUDIO_ROUTE_ID_PREFIX + mLeAudioProfile.getGroupId(device);
+ type = MediaRoute2Info.TYPE_BLE_HEADSET;
+ }
// Current volume will be set when connected.
newBtRoute.route = new MediaRoute2Info.Builder(routeId, deviceName)
@@ -358,11 +375,7 @@
}
}
- private void addActiveHearingAidDevices(BluetoothDevice device) {
- if (DEBUG) {
- Log.d(TAG, "Setting active hearing aid devices. device=" + device);
- }
-
+ private void addActiveDevices(BluetoothDevice device) {
// Let the given device be the first active device
BluetoothRouteInfo activeBtRoute = mBluetoothRoutes.get(device.getAddress());
addActiveRoute(activeBtRoute);
@@ -376,6 +389,21 @@
}
}
}
+ private void addActiveHearingAidDevices(BluetoothDevice device) {
+ if (DEBUG) {
+ Log.d(TAG, "Setting active hearing aid devices. device=" + device);
+ }
+
+ addActiveDevices(device);
+ }
+
+ private void addActiveLeAudioDevices(BluetoothDevice device) {
+ if (DEBUG) {
+ Log.d(TAG, "Setting active le audio devices. device=" + device);
+ }
+
+ addActiveDevices(device);
+ }
interface BluetoothRoutesUpdatedListener {
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
@@ -392,6 +420,11 @@
if (connectedProfiles.get(BluetoothProfile.HEARING_AID, false)) {
return MediaRoute2Info.TYPE_HEARING_AID;
}
+
+ if (connectedProfiles.get(BluetoothProfile.LE_AUDIO, false)) {
+ return MediaRoute2Info.TYPE_BLE_HEADSET;
+ }
+
return MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
}
}
@@ -410,6 +443,10 @@
mHearingAidProfile = (BluetoothHearingAid) proxy;
activeDevices = mHearingAidProfile.getActiveDevices();
break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudioProfile = (BluetoothLeAudio) proxy;
+ activeDevices = mLeAudioProfile.getActiveDevices();
+ break;
default:
return;
}
@@ -434,6 +471,9 @@
case BluetoothProfile.HEARING_AID:
mHearingAidProfile = null;
break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudioProfile = null;
+ break;
default:
return;
}
@@ -490,12 +530,22 @@
}
notifyBluetoothRoutesUpdated();
break;
+ case BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED:
+ clearActiveRoutesWithType(MediaRoute2Info.TYPE_BLE_HEADSET);
+ if (device != null) {
+ addActiveLeAudioDevices(device);
+ }
+ notifyBluetoothRoutesUpdated();
+ break;
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
handleConnectionStateChanged(BluetoothProfile.A2DP, intent, device);
break;
case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
handleConnectionStateChanged(BluetoothProfile.HEARING_AID, intent, device);
break;
+ case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
+ handleConnectionStateChanged(BluetoothProfile.LE_AUDIO, intent, device);
+ break;
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 84be7f5..20687c6 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -4073,7 +4073,7 @@
if (hasRestrictedModeAccess(uid)) {
uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
} else {
- uidBlockedState.allowedReasons &= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
+ uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
}
uidBlockedState.updateEffectiveBlockedReasons();
if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) {
diff --git a/services/core/java/com/android/server/pm/dex/OWNERS b/services/core/java/com/android/server/pm/dex/OWNERS
index 5a4431e..052a4ca 100644
--- a/services/core/java/com/android/server/pm/dex/OWNERS
+++ b/services/core/java/com/android/server/pm/dex/OWNERS
@@ -1,2 +1,3 @@
-calin@google.com
+alanstokes@google.com
+jiakaiz@google.com
ngeoffray@google.com
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 dab980a..7bea018 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -213,6 +213,7 @@
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_CONNECT);
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.BLUETOOTH_SCAN);
NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.UWB_RANGING);
+ NEARBY_DEVICES_PERMISSIONS.add(Manifest.permission.NEARBY_WIFI_DEVICES);
}
private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index 6366280..7ffff93 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -429,15 +429,7 @@
private static @NonNull
HidlMemory parcelFileDescriptorToHidlMemory(@Nullable ParcelFileDescriptor data, int dataSize) {
if (dataSize > 0) {
- // Extract a dup of the underlying FileDescriptor out of data.
- FileDescriptor fd = new FileDescriptor();
- try {
- ParcelFileDescriptor dup = data.dup();
- fd.setInt$(dup.detachFd());
- return HidlMemoryUtil.fileDescriptorToHidlMemory(fd, dataSize);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ return HidlMemoryUtil.fileDescriptorToHidlMemory(data.getFileDescriptor(), dataSize);
} else {
return HidlMemoryUtil.fileDescriptorToHidlMemory(null, 0);
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 61770ea..566028a 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -29,6 +29,7 @@
import static android.net.NetworkIdentity.OEM_PRIVATE;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkTemplate.MATCH_ETHERNET;
import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
@@ -1340,7 +1341,7 @@
@Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
final NetworkTemplate template = (transport == TRANSPORT_CELLULAR)
? NetworkTemplate.buildTemplateMobileWithRatType(
- /*subscriptionId=*/null, NETWORK_TYPE_ALL)
+ /*subscriptionId=*/null, NETWORK_TYPE_ALL, METERED_YES)
: NetworkTemplate.buildTemplateWifiWildcard();
return getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
}
@@ -1380,7 +1381,8 @@
final List<NetworkStatsExt> ret = new ArrayList<>();
for (final int ratType : getAllCollapsedRatTypes()) {
final NetworkTemplate template =
- buildTemplateMobileWithRatType(subInfo.subscriberId, ratType);
+ buildTemplateMobileWithRatType(subInfo.subscriberId, ratType,
+ METERED_YES);
final NetworkStats stats =
getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
if (stats != null) {
@@ -1601,7 +1603,7 @@
int pullBluetoothBytesTransferLocked(int atomTag, List<StatsEvent> pulledData) {
BluetoothActivityEnergyInfo info = fetchBluetoothData();
- if (info == null || info.getUidTraffic() == null) {
+ if (info == null) {
return StatsManager.PULL_SKIP;
}
for (UidTraffic traffic : info.getUidTraffic()) {
diff --git a/services/core/java/com/android/server/timedetector/OWNERS b/services/core/java/com/android/server/timedetector/OWNERS
index 8f80897..67fc9d6 100644
--- a/services/core/java/com/android/server/timedetector/OWNERS
+++ b/services/core/java/com/android/server/timedetector/OWNERS
@@ -1,3 +1,3 @@
# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# This code is maintained by the same OWNERS as timezonedetector.
+include /services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/services/core/java/com/android/server/timezone/OWNERS b/services/core/java/com/android/server/timezone/OWNERS
index 8f80897..2d36574 100644
--- a/services/core/java/com/android/server/timezone/OWNERS
+++ b/services/core/java/com/android/server/timezone/OWNERS
@@ -1,3 +1,2 @@
-# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# Bug component: 24949
+include platform/libcore:/OWNERS
diff --git a/services/core/java/com/android/server/timezonedetector/OWNERS b/services/core/java/com/android/server/timezonedetector/OWNERS
index 8f80897..0293242 100644
--- a/services/core/java/com/android/server/timezonedetector/OWNERS
+++ b/services/core/java/com/android/server/timezonedetector/OWNERS
@@ -1,3 +1,7 @@
# Bug component: 847766
+# This is the main list for platform time / time zone detection maintainers, for this dir and
+# ultimately referenced by other OWNERS files for components maintained by the same team.
+nfuller@google.com
+jmorace@google.com
mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+narayan@google.com
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 92e0845..f57a852 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -1075,17 +1075,22 @@
}
if (shouldRecreateAudioPatch) {
mCommittedVolume = volume;
- if (mAudioPatch != null) {
- mAudioManager.releaseAudioPatch(mAudioPatch);
- }
- mAudioManager.createAudioPatch(
+ // only recreate if something was updated or audioPath is null
+ if (mAudioPatch == null || sinkUpdated ||sourceUpdated ) {
+ if (mAudioPatch != null) {
+ mAudioManager.releaseAudioPatch(mAudioPatch);
+ audioPatchArray[0] = null;
+ }
+ mAudioManager.createAudioPatch(
audioPatchArray,
new AudioPortConfig[] { sourceConfig },
sinkConfigs.toArray(new AudioPortConfig[sinkConfigs.size()]));
- mAudioPatch = audioPatchArray[0];
- if (sourceGainConfig != null) {
- mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
+ mAudioPatch = audioPatchArray[0];
}
+ }
+
+ if (sourceGainConfig != null) {
+ mAudioManager.setAudioPortGain(mAudioSource, sourceGainConfig);
}
}
diff --git a/services/core/java/com/android/server/vibrator/OWNERS b/services/core/java/com/android/server/vibrator/OWNERS
index 7e7335d..08f0a90 100644
--- a/services/core/java/com/android/server/vibrator/OWNERS
+++ b/services/core/java/com/android/server/vibrator/OWNERS
@@ -1 +1,3 @@
+lsandrade@google.com
michaelwr@google.com
+sbowden@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f3ba56a..08f3b1a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3387,9 +3387,15 @@
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
mRootWindowContainer.moveActivityToPinnedRootTask(
r, "enterPictureInPictureMode");
- final Task rootTask = r.getRootTask();
- rootTask.setPictureInPictureAspectRatio(aspectRatio);
- rootTask.setPictureInPictureActions(actions);
+ final Task task = r.getTask();
+ task.setPictureInPictureAspectRatio(aspectRatio);
+ task.setPictureInPictureActions(actions);
+
+ // Continue the pausing process after entering pip.
+ if (task.getPausingActivity() == r) {
+ task.schedulePauseActivity(r, false /* userLeaving */,
+ false /* pauseImmediately */, "auto-pip");
+ }
}
};
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ced5af1..516be55 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5771,23 +5771,8 @@
+ "directly: %s", prev);
didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs);
- mPausingActivity = null;
} else {
- ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
- try {
- EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
- prev.shortComponentName, "userLeaving=" + userLeaving, reason);
-
- mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
- prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
- prev.configChangeFlags, pauseImmediately));
- } catch (Exception e) {
- // Ignore exception, if process died other code will cleanup.
- Slog.w(TAG, "Exception thrown during pause", e);
- mPausingActivity = null;
- mLastPausedActivity = null;
- mTaskSupervisor.mNoHistoryActivities.remove(prev);
- }
+ schedulePauseActivity(prev, userLeaving, pauseImmediately, reason);
}
} else {
mPausingActivity = null;
@@ -5802,7 +5787,7 @@
}
// If already entered PIP mode, no need to keep pausing.
- if (mPausingActivity != null && !didAutoPip) {
+ if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
// activity has started. If we're pausing the activity just because
// the screen is being turned off and the UI is sleeping, don't interrupt
@@ -5835,6 +5820,25 @@
}
}
+ void schedulePauseActivity(ActivityRecord prev, boolean userLeaving,
+ boolean pauseImmediately, String reason) {
+ ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
+ try {
+ EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
+ prev.shortComponentName, "userLeaving=" + userLeaving, reason);
+
+ mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
+ prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
+ prev.configChangeFlags, pauseImmediately));
+ } catch (Exception e) {
+ // Ignore exception, if process died other code will cleanup.
+ Slog.w(TAG, "Exception thrown during pause", e);
+ mPausingActivity = null;
+ mLastPausedActivity = null;
+ mTaskSupervisor.mNoHistoryActivities.remove(prev);
+ }
+ }
+
@VisibleForTesting
void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
// Complete the pausing process of a pausing activity, so it doesn't make sense to
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 5540cc5..4857fb3 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1547,7 +1547,9 @@
// activity as it could lead to incorrect display metrics. For ex, IME services
// expect their config to match the config of the display with the IME window
// showing.
+ // If the configuration has been overridden by previous activity, empty it.
mIsActivityConfigOverrideAllowed = false;
+ unregisterActivityConfigurationListener();
break;
default:
break;
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 2722b8d..710a304 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -165,7 +165,7 @@
"android.hardware.power@1.1",
"android.hardware.power-V2-cpp",
"android.hardware.power.stats@1.0",
- "android.hardware.power.stats-V1-ndk_platform",
+ "android.hardware.power.stats-V1-ndk",
"android.hardware.thermal@1.0",
"android.hardware.tv.input@1.0",
"android.hardware.vibrator-V2-cpp",
@@ -178,7 +178,7 @@
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
"android.frameworks.stats@1.0",
- "android.frameworks.stats-V1-ndk_platform",
+ "android.frameworks.stats-V1-ndk",
"android.system.suspend.control-V1-cpp",
"android.system.suspend.control.internal-cpp",
"android.system.suspend-V1-ndk",
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 7fea547..fe86ff1 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -178,9 +178,10 @@
void enableAutoSuspend() {
static bool enabled = false;
if (!enabled) {
+ static sp<IBinder> autosuspendClientToken = new BBinder();
sp<system::suspend::internal::ISuspendControlServiceInternal> suspendControl =
getSuspendControlInternal();
- suspendControl->enableAutosuspend(&enabled);
+ suspendControl->enableAutosuspend(autosuspendClientToken, &enabled);
}
{
diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS
index f1402ea..6a7d298 100644
--- a/services/tests/servicestests/src/com/android/server/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/OWNERS
@@ -3,4 +3,5 @@
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
+per-file BatteryServiceTest.java = file:platform/hardware/interfaces:/health/aidl/OWNERS
per-file GestureLauncherServiceTest.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
index 8f80897..a0f46e1 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
@@ -1,3 +1,2 @@
# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+include /services/core/java/com/android/server/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
index 8f80897..6165260 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
@@ -1,3 +1,2 @@
-# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+# Bug component: 24949
+include /services/core/java/com/android/server/timezone/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
index 8f80897..a6ff1ba 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
@@ -1,3 +1,2 @@
# Bug component: 847766
-mingaleev@google.com
-include /core/java/android/app/timedetector/OWNERS
+include /services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/startop/OWNERS b/startop/OWNERS
index 2d1eb38..11d5ad0 100644
--- a/startop/OWNERS
+++ b/startop/OWNERS
@@ -1,7 +1,2 @@
-# mailing list: startop-eng@google.com
-calin@google.com
-chriswailes@google.com
-eholk@google.com
-iam@google.com
-mathieuc@google.com
-yawanng@google.com
+include platform/art:/OWNERS
+keunyoung@google.com
diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java
index e9698ad..0aa4b58 100644
--- a/telephony/java/android/telephony/BarringInfo.java
+++ b/telephony/java/android/telephony/BarringInfo.java
@@ -28,7 +28,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.List;
import java.util.Objects;
/**
@@ -269,42 +268,6 @@
mBarringServiceInfos = barringServiceInfos;
}
- /** @hide */
- public static BarringInfo create(
- @NonNull android.hardware.radio.V1_5.CellIdentity halBarringCellId,
- @NonNull List<android.hardware.radio.V1_5.BarringInfo> halBarringInfos) {
- CellIdentity ci = CellIdentity.create(halBarringCellId);
- SparseArray<BarringServiceInfo> serviceInfos = new SparseArray<>();
-
- for (android.hardware.radio.V1_5.BarringInfo halBarringInfo : halBarringInfos) {
- if (halBarringInfo.barringType
- == android.hardware.radio.V1_5.BarringInfo.BarringType.CONDITIONAL) {
- if (halBarringInfo.barringTypeSpecificInfo.getDiscriminator()
- != android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
- .hidl_discriminator.conditional) {
- // this is an error case where the barring info is conditional but the
- // conditional barring fields weren't included
- continue;
- }
- android.hardware.radio.V1_5.BarringInfo.BarringTypeSpecificInfo
- .Conditional conditionalInfo =
- halBarringInfo.barringTypeSpecificInfo.conditional();
- serviceInfos.put(
- halBarringInfo.serviceType, new BarringServiceInfo(
- halBarringInfo.barringType, // will always be CONDITIONAL here
- conditionalInfo.isBarred,
- conditionalInfo.factor,
- conditionalInfo.timeSeconds));
- } else {
- // Barring type is either NONE or UNCONDITIONAL
- serviceInfos.put(
- halBarringInfo.serviceType, new BarringServiceInfo(
- halBarringInfo.barringType, false, 0, 0));
- }
- }
- return new BarringInfo(ci, serviceInfos);
- }
-
/**
* Get the BarringServiceInfo for a specified service.
*
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8e910c9..73e6c76 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1312,9 +1312,14 @@
/**
* Determines whether a maximum size limit for IMS conference calls is enforced on the device.
* When {@code true}, IMS conference calls will be limited to at most
- * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants. When {@code false}, no attempt is made
- * to limit the number of participants in a conference (the carrier will raise an error when an
- * attempt is made to merge too many participants into a conference).
+ * {@link #KEY_IMS_CONFERENCE_SIZE_LIMIT_INT} participants. When {@code false}, no attempt is
+ * made to limit the number of participants in a conference (the carrier will raise an error
+ * when an attempt is made to merge too many participants into a conference).
+ * <p>
+ * Note: The maximum size of a conference can ONLY be supported where
+ * {@link #KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL} is {@code true} since the platform
+ * needs conference event package data to accurately know the number of participants in the
+ * conference.
*/
public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL =
"is_ims_conference_size_enforced_bool";
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 4b57d71..3e4e244 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,11 +34,6 @@
}
/** @hide */
- public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
- mIsEndcAvailable = cellConfig.isEndcAvailable;
- }
-
- /** @hide */
public CellConfigLte(boolean isEndcAvailable) {
mIsEndcAvailable = isEndcAvailable;
}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 15147da..06cfd67 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -20,7 +20,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.hardware.radio.V1_0.CellInfoType;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -359,104 +358,4 @@
return true;
}
-
- /** @hide */
- public static CellIdentity create(android.hardware.radio.V1_0.CellIdentity cellIdentity) {
- if (cellIdentity == null) return null;
- switch(cellIdentity.cellInfoType) {
- case CellInfoType.GSM: {
- if (cellIdentity.cellIdentityGsm.size() == 1) {
- return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
- }
- break;
- }
- case CellInfoType.WCDMA: {
- if (cellIdentity.cellIdentityWcdma.size() == 1) {
- return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
- }
- break;
- }
- case CellInfoType.TD_SCDMA: {
- if (cellIdentity.cellIdentityTdscdma.size() == 1) {
- return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
- }
- break;
- }
- case CellInfoType.LTE: {
- if (cellIdentity.cellIdentityLte.size() == 1) {
- return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
- }
- break;
- }
- case CellInfoType.CDMA: {
- if (cellIdentity.cellIdentityCdma.size() == 1) {
- return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
- }
- break;
- }
- case CellInfoType.NONE: break;
- default: break;
- }
- return null;
- }
-
- /** @hide */
- public static CellIdentity create(android.hardware.radio.V1_2.CellIdentity cellIdentity) {
- if (cellIdentity == null) return null;
- switch(cellIdentity.cellInfoType) {
- case CellInfoType.GSM: {
- if (cellIdentity.cellIdentityGsm.size() == 1) {
- return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
- }
- break;
- }
- case CellInfoType.WCDMA: {
- if (cellIdentity.cellIdentityWcdma.size() == 1) {
- return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
- }
- break;
- }
- case CellInfoType.TD_SCDMA: {
- if (cellIdentity.cellIdentityTdscdma.size() == 1) {
- return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
- }
- break;
- }
- case CellInfoType.LTE: {
- if (cellIdentity.cellIdentityLte.size() == 1) {
- return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
- }
- break;
- }
- case CellInfoType.CDMA: {
- if (cellIdentity.cellIdentityCdma.size() == 1) {
- return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
- }
- break;
- }
- case CellInfoType.NONE: break;
- default: break;
- }
- return null;
- }
-
- /** @hide */
- public static CellIdentity create(android.hardware.radio.V1_5.CellIdentity ci) {
- if (ci == null) return null;
- switch (ci.getDiscriminator()) {
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.gsm:
- return new CellIdentityGsm(ci.gsm());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.cdma:
- return new CellIdentityCdma(ci.cdma());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.lte:
- return new CellIdentityLte(ci.lte());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.wcdma:
- return new CellIdentityWcdma(ci.wcdma());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.tdscdma:
- return new CellIdentityTdscdma(ci.tdscdma());
- case android.hardware.radio.V1_5.CellIdentity.hidl_discriminator.nr:
- return new CellIdentityNr(ci.nr());
- default: return null;
- }
- }
}
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 58a01e9..ba3a192 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -112,17 +112,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityCdma(@NonNull android.hardware.radio.V1_0.CellIdentityCdma cid) {
- this(cid.networkId, cid.systemId, cid.baseStationId, cid.longitude, cid.latitude, "", "");
- }
-
- /** @hide */
- public CellIdentityCdma(@NonNull android.hardware.radio.V1_2.CellIdentityCdma cid) {
- this(cid.base.networkId, cid.base.systemId, cid.base.baseStationId, cid.base.longitude,
- cid.base.latitude, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
- }
-
private CellIdentityCdma(@NonNull CellIdentityCdma cid) {
this(cid.mNetworkId, cid.mSystemId, cid.mBasestationId, cid.mLongitude, cid.mLatitude,
cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index a3bec33..2516a79 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -101,30 +101,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityGsm(@NonNull android.hardware.radio.V1_0.CellIdentityGsm cid) {
- this(cid.lac, cid.cid, cid.arfcn,
- cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic,
- cid.mcc, cid.mnc, "", "", new ArraySet<>());
- }
-
- /** @hide */
- public CellIdentityGsm(@NonNull android.hardware.radio.V1_2.CellIdentityGsm cid) {
- this(cid.base.lac, cid.base.cid, cid.base.arfcn,
- cid.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.bsic, cid.base.mcc,
- cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
- new ArraySet<>());
- }
-
- /** @hide */
- public CellIdentityGsm(@NonNull android.hardware.radio.V1_5.CellIdentityGsm cid) {
- this(cid.base.base.lac, cid.base.base.cid, cid.base.base.arfcn,
- cid.base.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE
- : cid.base.base.bsic, cid.base.base.mcc,
- cid.base.base.mnc, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns);
- }
-
private CellIdentityGsm(@NonNull CellIdentityGsm cid) {
this(cid.mLac, cid.mCid, cid.mArfcn, cid.mBsic, cid.mMccStr,
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns);
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index bd92d00a..4db00cf 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -136,31 +136,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityLte(@NonNull android.hardware.radio.V1_0.CellIdentityLte cid) {
- this(cid.ci, cid.pci, cid.tac, cid.earfcn, new int[] {},
- CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "", new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityLte(@NonNull android.hardware.radio.V1_2.CellIdentityLte cid) {
- this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, new int[] {},
- cid.bandwidth, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
- cid.operatorNames.alphaShort, new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityLte(@NonNull android.hardware.radio.V1_5.CellIdentityLte cid) {
- this(cid.base.base.ci, cid.base.base.pci, cid.base.base.tac, cid.base.base.earfcn,
- cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.bandwidth,
- cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns,
- cid.optionalCsgInfo.getDiscriminator()
- == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
- ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo())
- : null);
- }
-
private CellIdentityLte(@NonNull CellIdentityLte cid) {
this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBands, cid.mBandwidth, cid.mMccStr,
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 4f50521..6aeb482 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -65,7 +65,6 @@
}
/**
- *
* @param pci Physical Cell Id in range [0, 1007].
* @param tac 24-bit Tracking Area Code.
* @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
@@ -100,21 +99,6 @@
}
/** @hide */
- public CellIdentityNr(@NonNull android.hardware.radio.V1_4.CellIdentityNr cid) {
- this(cid.pci, cid.tac, cid.nrarfcn, new int[] {}, cid.mcc, cid.mnc, cid.nci,
- cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
- new ArraySet<>());
- }
-
- /** @hide */
- public CellIdentityNr(@NonNull android.hardware.radio.V1_5.CellIdentityNr cid) {
- this(cid.base.pci, cid.base.tac, cid.base.nrarfcn,
- cid.bands.stream().mapToInt(Integer::intValue).toArray(), cid.base.mcc,
- cid.base.mnc, cid.base.nci, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns);
- }
-
- /** @hide */
@Override
public @NonNull CellIdentityNr sanitizeLocationInfo() {
return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mNrArfcn,
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index ec07d54..13d9373 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -113,31 +113,6 @@
}
/** @hide */
- public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_0.CellIdentityTdscdma cid) {
- this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "",
- Collections.emptyList(), null);
- }
-
- /** @hide */
- public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_2.CellIdentityTdscdma cid) {
- this(cid.base.mcc, cid.base.mnc, cid.base.lac, cid.base.cid, cid.base.cpid,
- cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
- Collections.emptyList(), null);
- }
-
- /** @hide */
- public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_5.CellIdentityTdscdma cid) {
- this(cid.base.base.mcc, cid.base.base.mnc, cid.base.base.lac, cid.base.base.cid,
- cid.base.base.cpid, cid.base.uarfcn, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort,
- cid.additionalPlmns,
- cid.optionalCsgInfo.getDiscriminator()
- == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
- ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo())
- : null);
- }
-
- /** @hide */
@Override
public @NonNull CellIdentityTdscdma sanitizeLocationInfo() {
return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index b04a51d..9b463da 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -107,30 +107,6 @@
updateGlobalCellId();
}
- /** @hide */
- public CellIdentityWcdma(@NonNull android.hardware.radio.V1_0.CellIdentityWcdma cid) {
- this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "",
- new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityWcdma(@NonNull android.hardware.radio.V1_2.CellIdentityWcdma cid) {
- this(cid.base.lac, cid.base.cid, cid.base.psc, cid.base.uarfcn,
- cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
- cid.operatorNames.alphaShort, new ArraySet<>(), null);
- }
-
- /** @hide */
- public CellIdentityWcdma(@NonNull android.hardware.radio.V1_5.CellIdentityWcdma cid) {
- this(cid.base.base.lac, cid.base.base.cid, cid.base.base.psc, cid.base.base.uarfcn,
- cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong,
- cid.base.operatorNames.alphaShort, cid.additionalPlmns,
- cid.optionalCsgInfo.getDiscriminator()
- == android.hardware.radio.V1_5.OptionalCsgInfo.hidl_discriminator.csgInfo
- ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo())
- : null);
- }
-
private CellIdentityWcdma(@NonNull CellIdentityWcdma cid) {
this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr,
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 189a4b8..2b2df24 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -20,7 +20,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
-import android.hardware.radio.V1_4.CellInfo.Info;
import android.os.Parcel;
import android.os.Parcelable;
@@ -150,6 +149,13 @@
private long mTimeStamp;
/** @hide */
+ protected CellInfo(int cellConnectionStatus, boolean registered, long timestamp) {
+ mCellConnectionStatus = cellConnectionStatus;
+ mRegistered = registered;
+ mTimeStamp = timestamp;
+ }
+
+ /** @hide */
protected CellInfo() {
this.mRegistered = false;
this.mTimeStamp = Long.MAX_VALUE;
@@ -321,131 +327,4 @@
return new CellInfo[size];
}
};
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_0.CellInfo ci) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = ci.timeStamp;
- this.mCellConnectionStatus = CONNECTION_UNKNOWN;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_2.CellInfo ci) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = ci.timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- this.mRegistered = ci.isRegistered;
- this.mTimeStamp = timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- protected CellInfo(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- this.mRegistered = ci.registered;
- this.mTimeStamp = timeStamp;
- this.mCellConnectionStatus = ci.connectionStatus;
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
- if (ci == null) return null;
- switch(ci.cellInfoType) {
- case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
- case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
- case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_2.CellInfo ci) {
- if (ci == null) return null;
- switch(ci.cellInfoType) {
- case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
- case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
- case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
- case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- if (ci == null) return null;
- switch (ci.info.getDiscriminator()) {
- case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci, timeStamp);
- case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci, timeStamp);
- case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp);
- case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp);
- case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp);
- case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- if (ci == null) return null;
- switch (ci.ratSpecificInfo.getDiscriminator()) {
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
- return new CellInfoGsm(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
- return new CellInfoCdma(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.lte:
- return new CellInfoLte(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
- return new CellInfoWcdma(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
- return new CellInfoTdscdma(ci, timeStamp);
- case android.hardware.radio.V1_5.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.nr:
- return new CellInfoNr(ci, timeStamp);
- default: return null;
- }
- }
-
- /** @hide */
- public static CellInfo create(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- if (ci == null) return null;
- switch (ci.ratSpecificInfo.getDiscriminator()) {
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
- return new CellInfoGsm(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
- return new CellInfoCdma(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.lte:
- return new CellInfoLte(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
- return new CellInfoWcdma(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
- return new CellInfoTdscdma(ci, timeStamp);
- case android.hardware.radio.V1_6.CellInfo
- .CellInfoRatSpecificInfo.hidl_discriminator.nr:
- return new CellInfoNr(ci, timeStamp);
- default: return null;
- }
- }
}
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index dbb30d2..aa8cff5 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -52,48 +52,11 @@
}
/** @hide */
- public CellInfoCdma(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoCdma cic = ci.cdma.get(0);
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.cdma.get(0);
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma();
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
- }
-
- /** @hide */
- public CellInfoCdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma();
- mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
- mCellSignalStrengthCdma =
- new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+ public CellInfoCdma(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityCdma cellIdentityCdma, CellSignalStrengthCdma cellSignalStrengthCdma) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityCdma = cellIdentityCdma;
+ mCellSignalStrengthCdma = cellSignalStrengthCdma;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index e1d996e..76e825b 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -51,43 +51,11 @@
}
/** @hide */
- public CellInfoGsm(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoGsm cig = ci.gsm.get(0);
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoGsm cig = ci.gsm.get(0);
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm();
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
- }
-
- /** @hide */
- public CellInfoGsm(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm();
- mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
- mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+ public CellInfoGsm(int cellConnectionStatus, boolean registered, long timeStamp,
+ CellIdentityGsm cellIdentityGsm, CellSignalStrengthGsm cellSignalStrengthGsm) {
+ super(cellConnectionStatus, registered, timeStamp);
+ mCellIdentityGsm = cellIdentityGsm;
+ mCellSignalStrengthGsm = cellSignalStrengthGsm;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 39b320a..2d176d5 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -56,48 +56,13 @@
}
/** @hide */
- public CellInfoLte(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoLte cil = ci.lte.get(0);
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoLte cil = ci.lte.get(0);
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
- mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
- mCellConfig = new CellConfigLte(cil.cellConfig);
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoLte cil = ci.ratSpecificInfo.lte();
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
- }
-
- /** @hide */
- public CellInfoLte(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_6.CellInfoLte cil = ci.ratSpecificInfo.lte();
- mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
- mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
- mCellConfig = new CellConfigLte();
+ public CellInfoLte(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityLte cellIdentityLte, CellSignalStrengthLte cellSignalStrengthLte,
+ CellConfigLte cellConfig) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityLte = cellIdentityLte;
+ mCellSignalStrengthLte = cellSignalStrengthLte;
+ mCellConfig = cellConfig;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index 12e6a38..37fac24 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -53,27 +53,11 @@
}
/** @hide */
- public CellInfoNr(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_4.CellInfoNr cil = ci.info.nr();
- mCellIdentity = new CellIdentityNr(cil.cellidentity);
- mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrength);
- }
-
- /** @hide */
- public CellInfoNr(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoNr cil = ci.ratSpecificInfo.nr();
- mCellIdentity = new CellIdentityNr(cil.cellIdentityNr);
- mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
- }
-
- /** @hide */
- public CellInfoNr(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_6.CellInfoNr cil = ci.ratSpecificInfo.nr();
- mCellIdentity = new CellIdentityNr(cil.cellIdentityNr);
- mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
+ public CellInfoNr(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityNr cellIdentityNr, CellSignalStrengthNr cellSignalStrengthNr) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentity = cellIdentityNr;
+ mCellSignalStrength = cellSignalStrengthNr;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 994b317..d8db429 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -54,43 +54,12 @@
}
/** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoTdscdma cit = ci.tdscdma.get(0);
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.tdscdma.get(0);
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma();
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
- }
-
- /** @hide */
- public CellInfoTdscdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma();
- mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
- mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+ public CellInfoTdscdma(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityTdscdma cellIdentityTdscdma,
+ CellSignalStrengthTdscdma cellSignalStrengthTdscdma) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityTdscdma = cellIdentityTdscdma;
+ mCellSignalStrengthTdscdma = cellSignalStrengthTdscdma;
}
/**
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index 62ac0b8..dc8e1fe 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -49,43 +49,11 @@
}
/** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_0.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_0.CellInfoWcdma ciw = ci.wcdma.get(0);
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_2.CellInfo ci) {
- super(ci);
- final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.wcdma.get(0);
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma();
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
- }
-
- /** @hide */
- public CellInfoWcdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
- super(ci, timeStamp);
- final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma();
- mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
- mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+ public CellInfoWcdma(int connectionStatus, boolean registered, long timeStamp,
+ CellIdentityWcdma cellIdentityWcdma, CellSignalStrengthWcdma cellSignalStrengthWcdma) {
+ super(connectionStatus, registered, timeStamp);
+ mCellIdentityWcdma = cellIdentityWcdma;
+ mCellSignalStrengthWcdma = cellSignalStrengthWcdma;
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index e089657..9727ab7 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -108,7 +108,7 @@
// Range for RSSI in ASU (0-31, 99) as defined in TS 27.007 8.69
/** @hide */
- protected static final int getRssiDbmFromAsu(int asu) {
+ public static final int getRssiDbmFromAsu(int asu) {
if (asu > 31 || asu < 0) return CellInfo.UNAVAILABLE;
return -113 + (2 * asu);
}
@@ -122,7 +122,7 @@
// Range for RSCP in ASU (0-96, 255) as defined in TS 27.007 8.69
/** @hide */
- protected static final int getRscpDbmFromAsu(int asu) {
+ public static final int getRscpDbmFromAsu(int asu) {
if (asu > 96 || asu < 0) return CellInfo.UNAVAILABLE;
return asu - 120;
}
@@ -136,7 +136,7 @@
// Range for SNR in ASU (0-49, 255) as defined in TS 27.007 8.69
/** @hide */
- protected static final int getEcNoDbFromAsu(int asu) {
+ public static final int getEcNoDbFromAsu(int asu) {
if (asu > 49 || asu < 0) return CellInfo.UNAVAILABLE;
return -24 + (asu / 2);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index d00049c..5298e67 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -78,13 +78,6 @@
}
/** @hide */
- public CellSignalStrengthCdma(android.hardware.radio.V1_0.CdmaSignalStrength cdma,
- android.hardware.radio.V1_0.EvdoSignalStrength evdo) {
- // Convert from HAL values as part of construction.
- this(-cdma.dbm, -cdma.ecio, -evdo.dbm, -evdo.ecio, evdo.signalNoiseRatio);
- }
-
- /** @hide */
public CellSignalStrengthCdma(CellSignalStrengthCdma s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 51e1ebc..7b78084 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -67,16 +67,6 @@
}
/** @hide */
- public CellSignalStrengthGsm(android.hardware.radio.V1_0.GsmSignalStrength gsm) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(gsm.signalStrength), gsm.bitErrorRate, gsm.timingAdvance);
-
- if (mRssi == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
public CellSignalStrengthGsm(CellSignalStrengthGsm s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 9211482..e8633dd 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -166,25 +166,6 @@
}
/** @hide */
- public CellSignalStrengthLte(android.hardware.radio.V1_0.LteSignalStrength lte) {
- // Convert from HAL values as part of construction.
- this(convertRssiAsuToDBm(lte.signalStrength),
- lte.rsrp != CellInfo.UNAVAILABLE ? -lte.rsrp : lte.rsrp,
- lte.rsrq != CellInfo.UNAVAILABLE ? -lte.rsrq : lte.rsrq,
- convertRssnrUnitFromTenDbToDB(lte.rssnr), lte.cqi, lte.timingAdvance);
- }
-
- /** @hide */
- public CellSignalStrengthLte(android.hardware.radio.V1_6.LteSignalStrength lte) {
- // Convert from HAL values as part of construction.
- this(convertRssiAsuToDBm(lte.base.signalStrength),
- lte.base.rsrp != CellInfo.UNAVAILABLE ? -lte.base.rsrp : lte.base.rsrp,
- lte.base.rsrq != CellInfo.UNAVAILABLE ? -lte.base.rsrq : lte.base.rsrq,
- convertRssnrUnitFromTenDbToDB(lte.base.rssnr), lte.cqiTableIndex, lte.base.cqi,
- lte.base.timingAdvance);
- }
-
- /** @hide */
public CellSignalStrengthLte(CellSignalStrengthLte s) {
copyFrom(s);
}
@@ -617,11 +598,13 @@
Rlog.w(LOG_TAG, s);
}
- private static int convertRssnrUnitFromTenDbToDB(int rssnr) {
+ /** @hide */
+ public static int convertRssnrUnitFromTenDbToDB(int rssnr) {
return rssnr / 10;
}
- private static int convertRssiAsuToDBm(int rssiAsu) {
+ /** @hide */
+ public static int convertRssiAsuToDBm(int rssiAsu) {
if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) {
return CellInfo.UNAVAILABLE;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 6ada32e..cd22abd 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -202,29 +202,12 @@
}
/**
- * @hide
- * @param ss signal strength from modem.
- */
- public CellSignalStrengthNr(android.hardware.radio.V1_4.NrSignalStrength ss) {
- this(flip(ss.csiRsrp), flip(ss.csiRsrq), ss.csiSinr, flip(ss.ssRsrp), flip(ss.ssRsrq),
- ss.ssSinr);
- }
-
- /**
- * @hide
- * @param ss signal strength from modem.
- */
- public CellSignalStrengthNr(android.hardware.radio.V1_6.NrSignalStrength ss) {
- this(flip(ss.base.csiRsrp), flip(ss.base.csiRsrq), ss.base.csiSinr, ss.csiCqiTableIndex,
- ss.csiCqiReport, flip(ss.base.ssRsrp), flip(ss.base.ssRsrq), ss.base.ssSinr);
- }
-
- /**
* Flip sign cell strength value when taking in the value from hal
* @param val cell strength value
* @return flipped value
+ * @hide
*/
- private static int flip(int val) {
+ public static int flip(int val) {
return val != CellInfo.UNAVAILABLE ? -val : val;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index e96f200..8a7c70e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -75,28 +75,6 @@
}
/** @hide */
- public CellSignalStrengthTdscdma(android.hardware.radio.V1_0.TdScdmaSignalStrength tdscdma) {
- // Convert from HAL values as part of construction.
- this(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
- tdscdma.rscp != CellInfo.UNAVAILABLE ? -tdscdma.rscp : tdscdma.rscp);
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
- public CellSignalStrengthTdscdma(android.hardware.radio.V1_2.TdscdmaSignalStrength tdscdma) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(tdscdma.signalStrength),
- tdscdma.bitErrorRate, getRscpDbmFromAsu(tdscdma.rscp));
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
public CellSignalStrengthTdscdma(CellSignalStrengthTdscdma s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 8b14b74..f30440d 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -95,30 +95,6 @@
}
/** @hide */
- public CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(wcdma.signalStrength), wcdma.bitErrorRate,
- CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE);
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
- public CellSignalStrengthWcdma(android.hardware.radio.V1_2.WcdmaSignalStrength wcdma) {
- // Convert from HAL values as part of construction.
- this(getRssiDbmFromAsu(wcdma.base.signalStrength),
- wcdma.base.bitErrorRate,
- getRscpDbmFromAsu(wcdma.rscp),
- getEcNoDbFromAsu(wcdma.ecno));
-
- if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
- setDefaultValues();
- }
- }
-
- /** @hide */
public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
copyFrom(s);
}
diff --git a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
index e926272..bf418ab 100644
--- a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
+++ b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
@@ -44,12 +44,6 @@
mCsgIdentity = csgIdentity;
}
- /** @hide */
- public ClosedSubscriberGroupInfo(
- @NonNull android.hardware.radio.V1_5.ClosedSubscriberGroupInfo csgInfo) {
- this(csgInfo.csgIndication, csgInfo.homeNodebName, csgInfo.csgIdentity);
- }
-
/**
* Indicates whether the cell is restricted to only CSG members.
*
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index f859857..846e6f3 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -612,7 +612,7 @@
/**
* Get the channel number of the current primary serving cell, or -1 if unknown
*
- * <p>This is EARFCN for LTE, UARFCN for UMTS, and ARFCN for GSM.
+ * <p>This is NRARFCN for NR, EARFCN for LTE, UARFCN for UMTS, and ARFCN for GSM.
*
* @return Channel number of primary serving cell
*/
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index b317c55..b7bc467 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -144,64 +144,6 @@
mTimestampMillis = SystemClock.elapsedRealtime();
}
- /**
- * Constructor for Radio HAL V1.0
- *
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_0.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gw),
- new CellSignalStrengthWcdma(),
- new CellSignalStrengthTdscdma(signalStrength.tdScdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr());
- }
-
- /**
- * Constructor for Radio HAL V1.2
- *
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_2.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gsm),
- new CellSignalStrengthWcdma(signalStrength.wcdma),
- new CellSignalStrengthTdscdma(signalStrength.tdScdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr());
- }
-
- /**
- * Constructor for Radio HAL V1.4.
- *
- * @param signalStrength signal strength reported from modem.
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_4.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gsm),
- new CellSignalStrengthWcdma(signalStrength.wcdma),
- new CellSignalStrengthTdscdma(signalStrength.tdscdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr(signalStrength.nr));
- }
-
- /**
- * Constructor for Radio HAL V1.6.
- *
- * @param signalStrength signal strength reported from modem.
- * @hide
- */
- public SignalStrength(android.hardware.radio.V1_6.SignalStrength signalStrength) {
- this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
- new CellSignalStrengthGsm(signalStrength.gsm),
- new CellSignalStrengthWcdma(signalStrength.wcdma),
- new CellSignalStrengthTdscdma(signalStrength.tdscdma),
- new CellSignalStrengthLte(signalStrength.lte),
- new CellSignalStrengthNr(signalStrength.nr));
- }
-
private CellSignalStrength getPrimary() {
// This behavior is intended to replicate the legacy behavior of getLevel() by prioritizing
// newer faster RATs for default/for display purposes.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 255a612..a1bed29 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2945,7 +2945,12 @@
* currently in use on the device for data transmission.
*
* If this object has been created with {@link #createForSubscriptionId}, applies to the given
- * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ * subId. Otherwise, applies to {@link SubscriptionManager#getActiveDataSubscriptionId()}.
+ *
+ * Note: Before {@link SubscriptionManager#getActiveDataSubscriptionId()} was introduced in API
+ * level 30, it was applied to {@link SubscriptionManager#getDefaultDataSubscriptionId()} which
+ * may be different now from {@link SubscriptionManager#getActiveDataSubscriptionId()}, e.g.
+ * when opportunistic network is providing cellular internet connection to the user.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index e890acb..9572154 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -36,6 +36,7 @@
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -152,16 +153,9 @@
throw new RuntimeException(
"Failed to find NetworkScanInfo with id " + message.arg2);
}
- NetworkScanCallback callback = nsi.mCallback;
- Executor executor = nsi.mExecutor;
- if (callback == null) {
- throw new RuntimeException(
- "Failed to find NetworkScanCallback with id " + message.arg2);
- }
- if (executor == null) {
- throw new RuntimeException(
- "Failed to find Executor with id " + message.arg2);
- }
+
+ final NetworkScanCallback callback = nsi.mCallback;
+ final Executor executor = nsi.mExecutor;
switch (message.what) {
case CALLBACK_RESTRICTED_SCAN_RESULTS:
@@ -246,17 +240,24 @@
NetworkScanRequest request, Executor executor, NetworkScanCallback callback,
String callingPackage, @Nullable String callingFeatureId) {
try {
+ Objects.requireNonNull(request, "Request was null");
+ Objects.requireNonNull(callback, "Callback was null");
+ Objects.requireNonNull(executor, "Executor was null");
final ITelephony telephony = getITelephony();
if (telephony == null) return null;
- int scanId = telephony.requestNetworkScan(
- subId, request, mMessenger, new Binder(), callingPackage,
- callingFeatureId);
- if (scanId == INVALID_SCAN_ID) {
- Rlog.e(TAG, "Failed to initiate network scan");
- return null;
- }
+ // The lock must be taken before calling requestNetworkScan because the resulting
+ // scanId can be invoked asynchronously on another thread at any time after
+ // requestNetworkScan invoked, leaving a critical section between that call and adding
+ // the record to the ScanInfo cache.
synchronized (mScanInfo) {
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage,
+ callingFeatureId);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
// We link to death whenever a scan is started to ensure that we are linked
// at the point that phone process death might matter.
// We never unlink because:
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index ec12040..5b44dba 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -43,6 +43,10 @@
@VisibleForTesting
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";
+
// A table mapping from a number to a hex character for fast encoding hex strings.
private static final char[] HEX_CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
@@ -923,6 +927,9 @@
* Strip all the trailing 'F' characters of a string, e.g., an ICCID.
*/
public static String stripTrailingFs(String s) {
+ if (TEST_ICCID.equals(s)) {
+ return s;
+ }
return s == null ? null : s.replaceAll("(?i)f*$", "");
}
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.bp b/tests/DynamicCodeLoggerIntegrationTests/Android.bp
new file mode 100644
index 0000000..448d46f
--- /dev/null
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.bp
@@ -0,0 +1,60 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// 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 {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_test_helper_library {
+ name: "DynamicCodeLoggerTestLibrary",
+ srcs: ["src/com/android/dcl/**/*.java"],
+
+}
+
+cc_library_shared {
+ name: "DynamicCodeLoggerNativeTestLibrary",
+ srcs: ["src/cpp/com_android_dcl_Jni.cpp"],
+ header_libs: ["jni_headers"],
+ sdk_version: "28",
+ stl: "c++_static",
+}
+
+cc_binary {
+ name: "DynamicCodeLoggerNativeExecutable",
+ srcs: ["src/cpp/test_executable.cpp"],
+}
+
+android_test {
+ name: "DynamicCodeLoggerIntegrationTests",
+
+ sdk_version: "current",
+ test_suites: ["device-tests"],
+ certificate: "shared",
+ srcs: ["src/com/android/server/pm/**/*.java"],
+
+ static_libs: [
+ "androidx.test.rules",
+ "truth-prebuilt",
+ ],
+
+ compile_multilib: "both",
+ jni_libs: ["DynamicCodeLoggerNativeTestLibrary"],
+
+ java_resources: [
+ ":DynamicCodeLoggerTestLibrary",
+ ":DynamicCodeLoggerNativeExecutable",
+ ],
+}
diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
deleted file mode 100644
index dab8304..0000000
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-# Build a tiny library that the test app can dynamically load
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := DynamicCodeLoggerTestLibrary
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl)
-
-include $(BUILD_JAVA_LIBRARY)
-
-dynamiccodeloggertest_jar := $(LOCAL_BUILT_MODULE)
-
-
-# Also build a native library that the test app can dynamically load
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
-LOCAL_HEADER_LIBRARIES := jni_headers
-LOCAL_SDK_VERSION := 28
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_SHARED_LIBRARY)
-
-# And a standalone native executable that we can exec.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := DynamicCodeLoggerNativeExecutable
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-LOCAL_SRC_FILES := src/cpp/test_executable.cpp
-
-include $(BUILD_EXECUTABLE)
-
-dynamiccodeloggertest_executable := $(LOCAL_BUILT_MODULE)
-
-# Build the test app itself
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := DynamicCodeLoggerIntegrationTests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_CERTIFICATE := shared
-LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- androidx.test.rules \
- truth-prebuilt \
-
-# Include both versions of the .so if we have 2 arch
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := \
- DynamicCodeLoggerNativeTestLibrary \
-
-# This gets us the javalib.jar built by DynamicCodeLoggerTestLibrary above as well as the various
-# native binaries.
-LOCAL_JAVA_RESOURCE_FILES := \
- $(dynamiccodeloggertest_jar) \
- $(dynamiccodeloggertest_executable) \
-
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-include $(BUILD_PACKAGE)
diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
index 883c172..5430dee 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
@@ -114,7 +114,8 @@
// Obtained via "echo -n copied.jar | sha256sum"
String expectedNameHash =
"1B6C71DB26F36582867432CCA12FB6A517470C9F9AABE9198DD4C5C030D6DC0C";
- String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile);
+ String expectedContentHash = copyAndHashResource(
+ "/DynamicCodeLoggerTestLibrary.jar", privateCopyFile);
// Feed the jar to a class loader and make sure it contains what we expect.
ClassLoader parentClassLoader = sContext.getClass().getClassLoader();
@@ -135,7 +136,8 @@
File privateCopyFile = privateFile("copied2.jar");
String expectedNameHash =
"202158B6A3169D78F1722487205A6B036B3F2F5653FDCFB4E74710611AC7EB93";
- String expectedContentHash = copyAndHashResource("/javalib.jar", privateCopyFile);
+ String expectedContentHash = copyAndHashResource(
+ "/DynamicCodeLoggerTestLibrary.jar", privateCopyFile);
// This time make sure an unknown class loader is an ancestor of the class loader we use.
ClassLoader knownClassLoader = sContext.getClass().getClassLoader();
diff --git a/tests/LockTaskTests/Android.bp b/tests/LockTaskTests/Android.bp
new file mode 100644
index 0000000..dce681e
--- /dev/null
+++ b/tests/LockTaskTests/Android.bp
@@ -0,0 +1,32 @@
+// 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 {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+ name: "LockTaskTests",
+
+ privileged: true,
+
+ sdk_version: "current",
+ certificate: "platform",
+
+ srcs: [
+ "src/**/I*.aidl",
+ "src/**/*.java",
+ ],
+
+}
diff --git a/tests/LockTaskTests/Android.mk b/tests/LockTaskTests/Android.mk
deleted file mode 100644
index 5406ee1..0000000
--- a/tests/LockTaskTests/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app
-
-LOCAL_PACKAGE_NAME := LockTaskTests
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-LOCAL_SRC_FILES := $(call all-Iaidl-files-under, src) $(call all-java-files-under, src)
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java b/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java
index 7cda977..5d639f6 100644
--- a/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java
+++ b/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java
@@ -409,10 +409,10 @@
sleepIfYouCan(500);
L("Parceling notifications...");
- // we want to be able to use this test on older OSes that do not have getBlobAshmemSize
- Method getBlobAshmemSize = null;
+ // we want to be able to use this test on older OSes that do not have getOpenAshmemSize
+ Method getOpenAshmemSize = null;
try {
- getBlobAshmemSize = Parcel.class.getMethod("getBlobAshmemSize");
+ getOpenAshmemSize = Parcel.class.getMethod("getOpenAshmemSize");
} catch (NoSuchMethodException ex) {
}
for (int i=0; i<mNotifications.size(); i++) {
@@ -424,8 +424,8 @@
time = SystemClock.currentThreadTimeMillis() - time;
L(" %s: write parcel=%dms size=%d ashmem=%s",
summarize(n), time, p.dataPosition(),
- (getBlobAshmemSize != null)
- ? getBlobAshmemSize.invoke(p)
+ (getOpenAshmemSize != null)
+ ? getOpenAshmemSize.invoke(p)
: "???");
p.setDataPosition(0);
}