Merge "Remove route features from RoutingSessionInfo related APIs"
diff --git a/Android.bp b/Android.bp
index 4c983be..b3faef1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -221,7 +221,6 @@
":framework-sax-sources",
":framework-telecomm-sources",
":framework-telephony-common-sources",
- ":framework-telephony-sources",
":framework-wifi-annotations",
":framework-wifi-non-updatable-sources",
":PacProcessor-aidl-sources",
@@ -256,6 +255,9 @@
// etc.
":framework-javastream-protos",
":framework-statslog-gen",
+
+ // telephony annotations
+ ":framework-telephony-annotations",
],
}
@@ -270,6 +272,7 @@
":framework-mediaprovider-sources",
":framework-permission-sources",
":framework-wifi-updatable-sources",
+ ":framework-telephony-sources",
":ike-srcs",
]
}
@@ -303,7 +306,6 @@
"rs/java",
"sax/java",
"telecomm/java",
- "telephony/java",
"wifi/java",
],
},
@@ -383,6 +385,7 @@
"updatable_media_stubs",
"framework_mediaprovider_stubs",
"framework-tethering",
+ "framework-telephony-stubs",
],
jarjar_rules: ":framework-jarjar-rules",
@@ -469,6 +472,7 @@
"//frameworks/base/apex/jobscheduler/framework",
"//frameworks/base/apex/permission/framework",
"//frameworks/base/apex/statsd/service",
+ "//frameworks/base/telephony",
"//frameworks/base/wifi",
"//frameworks/opt/net/wifi/service",
],
@@ -501,6 +505,9 @@
"ike-stubs",
// TODO(b/147200698): should be the stub of framework-tethering
"framework-tethering",
+ // TODO (b/147688669) should be framework-telephony-stubs
+ "framework-telephony",
+ // TODO(jiyong): add stubs for APEXes here
],
sdk_version: "core_platform",
apex_available: ["//apex_available:platform"],
@@ -1226,3 +1233,82 @@
"StubLibraries.bp",
"ApiDocs.bp",
]
+
+// TODO(b/147699819): move to frameworks/base/telephony/ folder
+droidstubs {
+ name: "framework-telephony-stubs-srcs",
+ srcs: [
+ ":framework-telephony-sources",
+ ":framework_native_aidl",
+ ":framework-javastream-protos",
+ ],
+ aidl: {
+ local_include_dirs: [
+ "core/java",
+ "telecomm/java"
+ ],
+ },
+ libs: [
+ "framework-annotations-lib",
+ "android.hardware.radio-V1.5-java",
+ ],
+ defaults: ["framework-module-stubs-defaults-systemapi"],
+ filter_packages: ["android.telephony"],
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "framework-telephony-stubs",
+ srcs: [":framework-telephony-stubs-srcs"],
+ // TODO(b/147699819): move public aidls to a separate folder and potentially remove
+ // below aidl exports.
+ aidl: {
+ export_include_dirs: ["telephony/java"],
+ },
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "framework-telephony",
+ srcs: [
+ ":framework-telephony-sources",
+ ],
+ // TODO: change to framework-system-stub to build against system APIs.
+ libs: [
+ "framework-minus-apex",
+ "unsupportedappusage",
+ ],
+ static_libs: [
+ "libphonenumber-platform",
+ "app-compat-annotations",
+ ],
+ sdk_version: "core_platform",
+ aidl: {
+ export_include_dirs: ["telephony/java"],
+ include_dirs: [
+ "frameworks/native/aidl/binder",
+ "frameworks/native/aidl/gui",
+ ]
+ },
+ jarjar_rules: ":telephony-framework-jarjar-rules",
+ dxflags: [
+ "--core-library",
+ "--multi-dex",
+ ],
+ // This is to break the dependency from boot jars.
+ dex_preopt: {
+ enabled: false,
+ },
+ installable: true,
+}
+
+filegroup {
+ // TODO (b/147690217): move to frameworks/base/telephony/common.
+ name: "framework-telephony-annotations",
+ srcs: ["telephony/java/android/telephony/Annotation.java"],
+}
+
+filegroup {
+ name: "telephony-framework-jarjar-rules",
+ srcs: ["telephony/framework-telephony-jarjar-rules.txt"],
+}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index baa3c61..cdc0d32 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -51,6 +51,10 @@
":core_public_api_files",
":ike-api-srcs",
],
+ // TODO(b/147699819): remove below aidl includes.
+ aidl: {
+ local_include_dirs: ["telephony/java"],
+ },
libs: ["framework-internal-utils"],
installable: false,
annotations_enabled: true,
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 81d732f..8bc14d7 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -1299,78 +1299,6 @@
}
}
- private BatteryStatsHelper getBatteryStatsHelper() {
- if (mBatteryStatsHelper == null) {
- final long callingToken = Binder.clearCallingIdentity();
- try {
- // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
- mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
- mBatteryStatsHelper.create((Bundle) null);
- }
- long currentTime = SystemClock.elapsedRealtime();
- if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
- // Load BatteryStats and do all the calculations.
- mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL);
- // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
- mBatteryStatsHelper.clearStats();
- mBatteryStatsHelperTimestampMs = currentTime;
- }
- return mBatteryStatsHelper;
- }
-
- private long milliAmpHrsToNanoAmpSecs(double mAh) {
- final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
- return (long) (mAh * MILLI_AMP_HR_TO_NANO_AMP_SECS + 0.5);
- }
-
- private void pullDeviceCalculatedPowerUse(int tagId,
- long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
- BatteryStatsHelper bsHelper = getBatteryStatsHelper();
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeLong(milliAmpHrsToNanoAmpSecs(bsHelper.getComputedPower()));
- pulledData.add(e);
- }
-
- private void pullDeviceCalculatedPowerBlameUid(int tagId,
- long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
- final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
- if (sippers == null) {
- return;
- }
- for (BatterySipper bs : sippers) {
- if (bs.drainType != bs.drainType.APP) {
- continue;
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(bs.uidObj.getUid());
- e.writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah));
- pulledData.add(e);
- }
- }
-
- private void pullDeviceCalculatedPowerBlameOther(int tagId,
- long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
- final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
- if (sippers == null) {
- return;
- }
- for (BatterySipper bs : sippers) {
- if (bs.drainType == bs.drainType.APP) {
- continue; // This is a separate atom; see pullDeviceCalculatedPowerBlameUid().
- }
- if (bs.drainType == bs.drainType.USER) {
- continue; // This is not supported. We purposefully calculate over USER_ALL.
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(bs.drainType.ordinal());
- e.writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah));
- pulledData.add(e);
- }
- }
-
private void pullDiskIo(int tagId, long elapsedNanos, final long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead,
@@ -1992,21 +1920,6 @@
break;
}
- case StatsLog.DEVICE_CALCULATED_POWER_USE: {
- pullDeviceCalculatedPowerUse(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.DEVICE_CALCULATED_POWER_BLAME_UID: {
- pullDeviceCalculatedPowerBlameUid(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER: {
- pullDeviceCalculatedPowerBlameOther(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
case StatsLog.TEMPERATURE: {
pullTemperature(tagId, elapsedNanos, wallClockNanos, ret);
break;
diff --git a/api/current.txt b/api/current.txt
index d5ece2e..e27c318 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17289,6 +17289,7 @@
field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
field public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1; // 0x1
field public static final int LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0; // 0x0
+ field public static final int LENS_POSE_REFERENCE_UNDEFINED = 2; // 0x2
field public static final int LENS_STATE_MOVING = 1; // 0x1
field public static final int LENS_STATE_STATIONARY = 0; // 0x0
field public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE = 0; // 0x0
@@ -30810,6 +30811,7 @@
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutoJoinEnabled(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
diff --git a/api/module-app-current.txt b/api/module-app-current.txt
index d802177..4307e67 100644
--- a/api/module-app-current.txt
+++ b/api/module-app-current.txt
@@ -1 +1,9 @@
// Signature format: 2.0
+package android.app {
+
+ public final class NotificationChannel implements android.os.Parcelable {
+ method public void setBlockableSystem(boolean);
+ }
+
+}
+
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index c8253a0..1cb1c20 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -124,3 +124,11 @@
}
+package android.util {
+
+ public final class Log {
+ method public static int logToRadioBuffer(int, @Nullable String, @Nullable String);
+ }
+
+}
+
diff --git a/api/system-current.txt b/api/system-current.txt
index d00bd84..e532a3a 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6246,6 +6246,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
@@ -6595,6 +6596,7 @@
public final class PasspointConfiguration implements android.os.Parcelable {
method public boolean isAutoJoinEnabled();
+ method public boolean isMacRandomizationEnabled();
}
public abstract class ProvisioningCallback {
diff --git a/api/test-current.txt b/api/test-current.txt
index 4e94ef2..28119e3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -73,6 +73,7 @@
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+ method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle);
field public static final int PROCESS_CAPABILITY_ALL = 1; // 0x1
field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
@@ -756,6 +757,7 @@
method public int getUserId();
method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
+ method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
field public static final String BLOB_STORE_SERVICE = "blob_store";
field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
@@ -2512,10 +2514,12 @@
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(@NonNull String, @NonNull String, float);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(@NonNull String, @NonNull String, int);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(@NonNull String, @NonNull String, long);
+ method @NonNull @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static android.provider.DeviceConfig.Properties getProperties(@NonNull String, @NonNull java.lang.String...);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(@NonNull String, @NonNull String);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(@NonNull String, @NonNull String, @Nullable String);
method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
+ method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties) throws android.provider.DeviceConfig.BadConfigException;
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
field public static final String NAMESPACE_ANDROID = "android";
field public static final String NAMESPACE_AUTOFILL = "autofill";
@@ -2527,6 +2531,10 @@
field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
}
+ public static class DeviceConfig.BadConfigException extends java.lang.Exception {
+ ctor public DeviceConfig.BadConfigException();
+ }
+
public static interface DeviceConfig.OnPropertiesChangedListener {
method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
}
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index 6d1f291..603f7a2 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -400,7 +400,7 @@
GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
-
+
GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
@@ -466,7 +466,7 @@
KotlinOperator: android.os.WorkSource#get(int):
KotlinOperator: android.util.SparseArrayMap#get(int, String):
- Method can be invoked with an indexing operator from Kotlin: `get` (this is usually desirable; just make sure it makes sense for this type of object)
+
ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener:
@@ -2059,6 +2059,18 @@
MissingNullability: android.view.KeyEvent#actionToString(int):
+MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #0:
+
+MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #1:
+
+MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #2:
+
+MissingNullability: android.view.SurfaceControlViewHost#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #0:
+
+MissingNullability: android.view.SurfaceControlViewHost#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #1:
+
+MissingNullability: android.view.SurfaceControlViewHost#relayout(android.view.WindowManager.LayoutParams) parameter #0:
+
MissingNullability: android.view.View#getTooltipView():
MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0:
@@ -2079,18 +2091,6 @@
MissingNullability: android.view.WindowManager.LayoutParams#accessibilityTitle:
-MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #0:
-
-MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #1:
-
-MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #2:
-
-MissingNullability: android.view.SurfaceControlViewHost#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #0:
-
-MissingNullability: android.view.SurfaceControlViewHost#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #1:
-
-MissingNullability: android.view.SurfaceControlViewHost#relayout(android.view.WindowManager.LayoutParams) parameter #0:
-
MissingNullability: android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener#onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager) parameter #0:
MissingNullability: android.view.accessibility.AccessibilityNodeInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0:
@@ -2426,11 +2426,13 @@
ProtectedMember: android.view.ViewGroup#resetResolvedDrawables():
-PublicTypedef: android.os.HwParcel.Status: Don't expose @IntDef: @Status must be hidden.
-PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability: Don't expose @IntDef: @MmTelCapability must be hidden.
-
-PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult: Don't expose @IntDef: @ProcessCallResult must be hidden.
+PublicTypedef: android.os.HwParcel.Status:
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability:
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult:
+
RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
@@ -2513,6 +2515,8 @@
SamShouldBeLast: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]):
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
+ SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, java.util.concurrent.Executor, android.location.LocationListener):
SamShouldBeLast: android.os.BugreportManager#startBugreport(android.os.ParcelFileDescriptor, android.os.ParcelFileDescriptor, android.os.BugreportParams, java.util.concurrent.Executor, android.os.BugreportManager.BugreportCallback):
@@ -2593,6 +2597,8 @@
+UserHandle: android.app.ActivityManager#switchUser(android.os.UserHandle):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandle: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle):
UserHandle: android.app.role.RoleManager#addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
@@ -2607,8 +2613,12 @@
UserHandle: android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
-UserHandle: android.companion.CompanionDeviceManager#isDeviceAssociated(String, android.net.MacAddress, android.os.UserHandle):
+UserHandle: android.app.usage.StorageStatsManager#queryCratesForPackage(java.util.UUID, String, android.os.UserHandle):
When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
+UserHandle: android.app.usage.StorageStatsManager#queryCratesForUser(java.util.UUID, android.os.UserHandle):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
+UserHandle: android.companion.CompanionDeviceManager#isDeviceAssociated(String, android.net.MacAddress, android.os.UserHandle):
+
UserHandle: android.content.pm.PackageManager#getInstallReason(String, android.os.UserHandle):
UserHandle: android.content.pm.PackageManager#getPermissionFlags(String, String, android.os.UserHandle):
diff --git a/cmds/incident_helper/Android.bp b/cmds/incident_helper/Android.bp
index d7b6d69..64f4c66 100644
--- a/cmds/incident_helper/Android.bp
+++ b/cmds/incident_helper/Android.bp
@@ -1,3 +1,28 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_binary {
+ name: "incident-helper-cmd",
+ wrapper: "incident_helper_cmd",
+ srcs: [
+ "java/**/*.java",
+ ],
+ proto: {
+ plugin: "javastream",
+ },
+}
+
cc_defaults {
name: "incident_helper_defaults",
diff --git a/cmds/incident_helper/incident_helper_cmd b/cmds/incident_helper/incident_helper_cmd
new file mode 100644
index 0000000..d45f7df
--- /dev/null
+++ b/cmds/incident_helper/incident_helper_cmd
@@ -0,0 +1,6 @@
+#!/system/bin/sh
+# Script to start "incident_helper_cmd" on the device
+#
+base=/system
+export CLASSPATH=$base/framework/incident-helper-cmd.jar
+exec app_process $base/bin com.android.commands.incident.IncidentHelper "$@"
diff --git a/cmds/incident_helper/java/com/android/commands/incident/ExecutionException.java b/cmds/incident_helper/java/com/android/commands/incident/ExecutionException.java
new file mode 100644
index 0000000..d97b17e
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/ExecutionException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.incident;
+
+/**
+ * Thrown when there is an error executing a section.
+ */
+public class ExecutionException extends Exception {
+ /**
+ * Constructs a ExecutionException.
+ *
+ * @param msg the message
+ */
+ public ExecutionException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a ExecutionException from another exception.
+ *
+ * @param e the exception
+ */
+ public ExecutionException(Exception e) {
+ super(e);
+ }
+}
diff --git a/cmds/incident_helper/java/com/android/commands/incident/IncidentHelper.java b/cmds/incident_helper/java/com/android/commands/incident/IncidentHelper.java
new file mode 100644
index 0000000..e5874e0
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/IncidentHelper.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.incident;
+
+import android.util.Log;
+
+import com.android.commands.incident.sections.PersistLogSection;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * Helper command runner for incidentd to run customized command to gather data for a non-standard
+ * section.
+ */
+public class IncidentHelper {
+ private static final String TAG = "IncidentHelper";
+ private static boolean sLog = false;
+ private final List<String> mArgs;
+ private ListIterator<String> mArgsIterator;
+
+ private IncidentHelper(String[] args) {
+ mArgs = Collections.unmodifiableList(Arrays.asList(args));
+ mArgsIterator = mArgs.listIterator();
+ }
+
+ private static void showUsage(PrintStream out) {
+ out.println("This command is not designed to be run manually.");
+ out.println("Usage:");
+ out.println(" run [sectionName]");
+ }
+
+ private void run(String[] args) throws ExecutionException {
+ Section section = null;
+ List<String> sectionArgs = new ArrayList<>();
+ while (mArgsIterator.hasNext()) {
+ String arg = mArgsIterator.next();
+ if ("-l".equals(arg)) {
+ sLog = true;
+ Log.i(TAG, "Args: [" + String.join(",", args) + "]");
+ } else if ("run".equals(arg)) {
+ section = getSection(nextArgRequired());
+ mArgsIterator.forEachRemaining(sectionArgs::add);
+ break;
+ } else {
+ log(Log.WARN, TAG, "Error: Unknown argument: " + arg);
+ return;
+ }
+ }
+ section.run(System.in, System.out, sectionArgs);
+ }
+
+ private static Section getSection(String name) throws IllegalArgumentException {
+ if ("persisted_logs".equals(name)) {
+ return new PersistLogSection();
+ }
+ throw new IllegalArgumentException("Section not found: " + name);
+ }
+
+ private String nextArgRequired() {
+ if (!mArgsIterator.hasNext()) {
+ throw new IllegalArgumentException(
+ "Arg required after \"" + mArgs.get(mArgsIterator.previousIndex()) + "\"");
+ }
+ return mArgsIterator.next();
+ }
+
+ /**
+ * Print the given message to stderr, also log it if asked to (set by -l cmd arg).
+ */
+ public static void log(int priority, String tag, String msg) {
+ System.err.println(tag + ": " + msg);
+ if (sLog) {
+ Log.println(priority, tag, msg);
+ }
+ }
+
+ /**
+ * Command-line entry point.
+ *
+ * @param args The command-line arguments
+ */
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ showUsage(System.err);
+ System.exit(0);
+ }
+ IncidentHelper incidentHelper = new IncidentHelper(args);
+ try {
+ incidentHelper.run(args);
+ } catch (IllegalArgumentException e) {
+ showUsage(System.err);
+ System.err.println();
+ e.printStackTrace(System.err);
+ if (sLog) {
+ Log.e(TAG, "Error: ", e);
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ if (sLog) {
+ Log.e(TAG, "Error: ", e);
+ }
+ System.exit(1);
+ }
+ }
+}
diff --git a/cmds/incident_helper/java/com/android/commands/incident/Section.java b/cmds/incident_helper/java/com/android/commands/incident/Section.java
new file mode 100644
index 0000000..1c8c6578
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/Section.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.incident;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+/** Section interface used by {@link IncidentHelper}. */
+public interface Section {
+ /**
+ * Writes protobuf wire format to out, optionally reads data from in, with supplied args.
+ */
+ void run(InputStream in, OutputStream out, List<String> args) throws ExecutionException;
+}
diff --git a/cmds/incident_helper/java/com/android/commands/incident/sections/PersistLogSection.java b/cmds/incident_helper/java/com/android/commands/incident/sections/PersistLogSection.java
new file mode 100644
index 0000000..f9d2e79
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/sections/PersistLogSection.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.incident.sections;
+
+import android.util.Log;
+import android.util.PersistedLogProto;
+import android.util.TextLogEntry;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.commands.incident.ExecutionException;
+import com.android.commands.incident.IncidentHelper;
+import com.android.commands.incident.Section;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+/** PersistLogSection reads persisted logs and parses them into a PersistedLogProto. */
+public class PersistLogSection implements Section {
+ private static final String TAG = "IH_PersistLog";
+ private static final String LOG_DIR = "/data/misc/logd/";
+ // Persist log files are named logcat, logcat.001, logcat.002, logcat.003, ...
+ private static final Pattern LOG_FILE_RE = Pattern.compile("logcat(\\.\\d+)?");
+ private static final Pattern BUFFER_BEGIN_RE =
+ Pattern.compile("--------- (?:beginning of|switch to) (.*)");
+ private static final Map<String, Long> SECTION_NAME_TO_ID = new HashMap<>();
+ private static final Map<Character, Integer> LOG_PRIORITY_MAP = new HashMap<>();
+ private static final String DEFAULT_BUFFER = "main";
+
+ static {
+ SECTION_NAME_TO_ID.put("main", PersistedLogProto.MAIN_LOGS);
+ SECTION_NAME_TO_ID.put("radio", PersistedLogProto.RADIO_LOGS);
+ SECTION_NAME_TO_ID.put("events", PersistedLogProto.EVENTS_LOGS);
+ SECTION_NAME_TO_ID.put("system", PersistedLogProto.SYSTEM_LOGS);
+ SECTION_NAME_TO_ID.put("crash", PersistedLogProto.CRASH_LOGS);
+ SECTION_NAME_TO_ID.put("kernel", PersistedLogProto.KERNEL_LOGS);
+ }
+
+ static {
+ LOG_PRIORITY_MAP.put('V', TextLogEntry.LOG_VERBOSE);
+ LOG_PRIORITY_MAP.put('D', TextLogEntry.LOG_DEBUG);
+ LOG_PRIORITY_MAP.put('I', TextLogEntry.LOG_INFO);
+ LOG_PRIORITY_MAP.put('W', TextLogEntry.LOG_WARN);
+ LOG_PRIORITY_MAP.put('E', TextLogEntry.LOG_ERROR);
+ LOG_PRIORITY_MAP.put('F', TextLogEntry.LOG_FATAL);
+ LOG_PRIORITY_MAP.put('S', TextLogEntry.LOG_SILENT);
+ }
+
+ /**
+ * Caches dates at 00:00:00 to epoch second elapsed conversion. There are only a few different
+ * dates in persisted logs in one device, and constructing DateTime object is relatively
+ * expensive.
+ */
+ private Map<Integer, Long> mEpochTimeCache = new HashMap<>();
+ private ProtoOutputStream mProto;
+ private long mCurrFieldId;
+ private long mMaxBytes = Long.MAX_VALUE;
+
+ @Override
+ public void run(InputStream in, OutputStream out, List<String> args) throws ExecutionException {
+ parseArgs(args);
+ Path logDirPath = Paths.get(LOG_DIR);
+ if (!Files.exists(logDirPath)) {
+ IncidentHelper.log(Log.WARN, TAG, "Skip dump. " + logDirPath + " does not exist.");
+ return;
+ }
+ if (!Files.isReadable(logDirPath)) {
+ IncidentHelper.log(Log.WARN, TAG, "Skip dump. " + logDirPath + " is not readable.");
+ return;
+ }
+ mProto = new ProtoOutputStream(out);
+ setCurrentSection(DEFAULT_BUFFER);
+ final Matcher logFileRe = LOG_FILE_RE.matcher("");
+ // Need to process older log files first and write logs to proto in chronological order
+ // But we want to process only the latest ones if there is a size limit
+ try (Stream<File> stream = Files.list(logDirPath).map(Path::toFile)
+ .filter(f -> !f.isDirectory() && match(logFileRe, f.getName()) != null)
+ .sorted(Comparator.comparingLong(File::lastModified).reversed())) {
+ Iterator<File> iter = stream.iterator();
+ List<File> filesToProcess = new ArrayList<>();
+ long sumBytes = 0;
+ while (iter.hasNext()) {
+ File file = iter.next();
+ sumBytes += file.length();
+ if (sumBytes > mMaxBytes) {
+ break;
+ }
+ filesToProcess.add(file);
+ }
+ IncidentHelper.log(Log.INFO, TAG, "Limit # log files to " + filesToProcess.size());
+ filesToProcess.stream()
+ .sorted(Comparator.comparingLong(File::lastModified))
+ .forEachOrdered(this::processFile);
+ } catch (IOException e) {
+ throw new ExecutionException(e);
+ } finally {
+ mProto.flush();
+ }
+ IncidentHelper.log(Log.DEBUG, TAG, "Bytes written: " + mProto.getBytes().length);
+ }
+
+ private void parseArgs(List<String> args) {
+ Iterator<String> iter = args.iterator();
+ while (iter.hasNext()) {
+ String arg = iter.next();
+ if ("--limit".equals(arg) && iter.hasNext()) {
+ String sizeStr = iter.next().toLowerCase();
+ if (sizeStr.endsWith("mb")) {
+ mMaxBytes = Long.parseLong(sizeStr.replace("mb", "")) * 1024 * 1024;
+ } else if (sizeStr.endsWith("kb")) {
+ mMaxBytes = Long.parseLong(sizeStr.replace("kb", "")) * 1024;
+ } else {
+ mMaxBytes = Long.parseLong(sizeStr);
+ }
+ } else {
+ throw new IllegalArgumentException("Unknown argument: " + arg);
+ }
+ }
+ }
+
+ private void processFile(File file) {
+ final Matcher bufferBeginRe = BUFFER_BEGIN_RE.matcher("");
+ try (BufferedReader reader = Files.newBufferedReader(file.toPath(),
+ StandardCharsets.UTF_8)) {
+ String line;
+ Matcher m;
+ while ((line = reader.readLine()) != null) {
+ if ((m = match(bufferBeginRe, line)) != null) {
+ setCurrentSection(m.group(1));
+ continue;
+ }
+ parseLine(line);
+ }
+ } catch (IOException e) {
+ // Non-fatal error. We can skip and still process other files.
+ IncidentHelper.log(Log.WARN, TAG, "Error reading \"" + file + "\": " + e.getMessage());
+ }
+ IncidentHelper.log(Log.DEBUG, TAG, "Finished reading " + file);
+ }
+
+ private void setCurrentSection(String sectionName) {
+ Long sectionId = SECTION_NAME_TO_ID.get(sectionName);
+ if (sectionId == null) {
+ IncidentHelper.log(Log.WARN, TAG, "Section does not exist: " + sectionName);
+ sectionId = SECTION_NAME_TO_ID.get(DEFAULT_BUFFER);
+ }
+ mCurrFieldId = sectionId;
+ }
+
+ /**
+ * Parse a log line in the following format:
+ * 01-01 15:01:47.723501 2738 2895 I Exp_TAG: example log line
+ *
+ * It does not use RegExp for performance reasons. Using this RegExp "(\\d{2})-(\\d{2})\\s
+ * (\\d{2}):(\\d{2}):(\\d{2}).(\\d{6})\\s+(\\d+)\\s+(\\d+)\\s+(.)\\s+(.*?):\\s(.*)" is twice as
+ * slow as the current approach.
+ */
+ private void parseLine(String line) {
+ long token = mProto.start(mCurrFieldId);
+ try {
+ mProto.write(TextLogEntry.SEC, getEpochSec(line));
+ // Nanosec is 15th to 20th digits of "10-01 02:57:27.710652" times 1000
+ mProto.write(TextLogEntry.NANOSEC, parseInt(line, 15, 21) * 1000L);
+
+ int start = nextNonBlank(line, 21);
+ int end = line.indexOf(' ', start + 1);
+ mProto.write(TextLogEntry.PID, parseInt(line, start, end));
+
+ start = nextNonBlank(line, end);
+ end = line.indexOf(' ', start + 1);
+ mProto.write(TextLogEntry.TID, parseInt(line, start, end));
+
+ start = nextNonBlank(line, end);
+ char priority = line.charAt(start);
+ mProto.write(TextLogEntry.PRIORITY,
+ LOG_PRIORITY_MAP.getOrDefault(priority, TextLogEntry.LOG_DEFAULT));
+
+ start = nextNonBlank(line, start + 1);
+ end = line.indexOf(": ", start);
+ mProto.write(TextLogEntry.TAG, line.substring(start, end).trim());
+ mProto.write(TextLogEntry.LOG, line.substring(Math.min(end + 2, line.length())));
+ } catch (RuntimeException e) {
+ // Error reporting is likely piped to /dev/null. Inserting it into the proto to make
+ // it more useful.
+ mProto.write(TextLogEntry.SEC, System.currentTimeMillis() / 1000);
+ mProto.write(TextLogEntry.PRIORITY, TextLogEntry.LOG_ERROR);
+ mProto.write(TextLogEntry.TAG, TAG);
+ mProto.write(TextLogEntry.LOG,
+ "Error parsing \"" + line + "\"" + ": " + e.getMessage());
+ }
+ mProto.end(token);
+ }
+
+ // ============== Below are util methods to parse log lines ==============
+
+ private static int nextNonBlank(String line, int start) {
+ for (int i = start; i < line.length(); i++) {
+ if (line.charAt(i) != ' ') {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the epoch second from the line string. Line starts with a fixed-length timestamp like
+ * "10-01 02:57:27.710652"
+ */
+ private long getEpochSec(String line) {
+ int month = getDigit(line, 0) * 10 + getDigit(line, 1);
+ int day = getDigit(line, 3) * 10 + getDigit(line, 4);
+
+ int mmdd = month * 100 + day;
+ long epochSecBase = mEpochTimeCache.computeIfAbsent(mmdd, (key) -> {
+ final GregorianCalendar calendar = new GregorianCalendar();
+ calendar.set(Calendar.MONTH, (month + 12 - 1) % 12);
+ calendar.set(Calendar.DAY_OF_MONTH, day);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ // Date in log entries can never be in the future. If it happens, it means we are off
+ // by one year.
+ if (calendar.getTimeInMillis() > System.currentTimeMillis()) {
+ calendar.roll(Calendar.YEAR, /*amount=*/-1);
+ }
+ return calendar.getTimeInMillis() / 1000;
+ });
+
+ int hh = getDigit(line, 6) * 10 + getDigit(line, 7);
+ int mm = getDigit(line, 9) * 10 + getDigit(line, 10);
+ int ss = getDigit(line, 12) * 10 + getDigit(line, 13);
+ return epochSecBase + hh * 3600 + mm * 60 + ss;
+ }
+
+ private static int parseInt(String line, /*inclusive*/ int start, /*exclusive*/ int end) {
+ int num = 0;
+ for (int i = start; i < end; i++) {
+ num = num * 10 + getDigit(line, i);
+ }
+ return num;
+ }
+
+ private static int getDigit(String str, int pos) {
+ int digit = str.charAt(pos) - '0';
+ if (digit < 0 || digit > 9) {
+ throw new NumberFormatException("'" + str.charAt(pos) + "' is not a digit.");
+ }
+ return digit;
+ }
+
+ private static Matcher match(Matcher matcher, String text) {
+ matcher.reset(text);
+ return matcher.matches() ? matcher : null;
+ }
+}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9424862..4372e22 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -53,6 +53,7 @@
import "frameworks/base/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto";
import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
+import "frameworks/base/core/proto/android/stats/sysui/notification_enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
import "frameworks/base/core/proto/android/view/enums.proto";
@@ -337,6 +338,9 @@
BootTimeEventUtcTime boot_time_event_utc_time_reported = 241;
BootTimeEventErrorCode boot_time_event_error_code_reported = 242;
UserspaceRebootReported userspace_reboot_reported = 243;
+ NotificationReported notification_reported = 244;
+ NotificationPanelReported notification_panel_reported = 245;
+ NotificationChannelModified notification_panel_modified = 246;
}
// Pulled events will start at field 10000.
@@ -3287,6 +3291,10 @@
* this button" or "this dialog was displayed".
* Keep the UI event stream clean: don't use for system or background events.
* Log using the UiEventLogger wrapper - don't write with the StatsLog API directly.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/
+ * frameworks/base/packages/SystemUI/src/com/android/systemui/
*/
message UiEventReported {
// The event_id.
@@ -3298,6 +3306,122 @@
}
/**
+ * Reports a notification was created or updated.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/notification/
+ */
+message NotificationReported {
+ // The event_id (as for UiEventReported).
+ optional int32 event_id = 1;
+ // The notifying app's uid and package.
+ optional int32 uid = 2 [(is_uid) = true];
+ optional string package_name = 3;
+ // A small system-assigned identifier for the notification.
+ // Locally probably-unique, but expect collisions across users and/or days.
+ optional int32 instance_id = 4;
+ // The app-assigned notification ID and tag
+ optional int32 notification_id = 5;
+ optional string notification_tag = 6;
+ optional string channel_id = 7; // App-assigned channel ID
+
+ // Grouping information
+ optional string group_id = 8; // Group the notification currently belongs to
+ optional int32 group_instance_id = 9; // Instance_id of the group-summary notification
+ optional bool is_group_summary = 10; // Tags the group-summary notification
+
+ // Attributes
+ optional string category = 11; // App-assigned notification category (API-defined strings)
+ optional int32 style = 12; // App-assigned notification style
+ optional int32 num_people = 13; // Number of Person records attached to the notification
+
+ // Ordering, importance and interruptiveness
+
+ optional int32 position = 14; // Position in NotificationManager's list
+
+ optional android.stats.sysui.NotificationImportance importance = 15;
+ optional int32 alerting = 16; // Bitfield, 1=buzz 2=beep 4=blink
+
+ enum NotificationImportanceExplanation {
+ IMPORTANCE_EXPLANATION_UNKNOWN = 0;
+ IMPORTANCE_EXPLANATION_APP = 1; // App-specified channel importance.
+ IMPORTANCE_EXPLANATION_USER = 2; // User-specified channel importance.
+ IMPORTANCE_EXPLANATION_ASST = 3; // Notification Assistant override.
+ IMPORTANCE_EXPLANATION_SYSTEM = 4; // System override.
+ // Like _APP, but based on pre-channels priority signal.
+ IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS = 5;
+ }
+
+ optional NotificationImportanceExplanation importance_source = 17;
+ optional android.stats.sysui.NotificationImportance importance_initial = 18;
+ optional NotificationImportanceExplanation importance_initial_source = 19;
+ optional android.stats.sysui.NotificationImportance importance_asst = 20;
+ optional int32 assistant_hash = 21;
+ optional float assistant_ranking_score = 22;
+}
+
+message Notification {
+ // The notifying app's uid and package.
+ optional int32 uid = 1 [(is_uid) = true];
+ optional string package_name = 2;
+ // A small system-assigned identifier for the notification.
+ optional int32 instance_id = 3;
+
+ // Grouping information.
+ optional int32 group_instance_id = 4;
+ optional bool is_group_summary = 5;
+
+ // The section of the shade that the notification is in.
+ // See NotificationSectionsManager.PriorityBucket.
+ enum NotificationSection {
+ SECTION_UNKNOWN = 0;
+ SECTION_PEOPLE = 1;
+ SECTION_ALERTING = 2;
+ SECTION_SILENT = 3;
+ }
+ optional NotificationSection section = 6;
+}
+
+message NotificationList {
+ repeated Notification notifications = 1; // An ordered sequence of notifications.
+}
+
+/**
+ * Reports a notification panel was displayed, e.g. from the lockscreen or status bar.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/
+ */
+message NotificationPanelReported {
+ // The event_id (as for UiEventReported).
+ optional int32 event_id = 1;
+ optional int32 num_notifications = 2;
+ // The notifications in the panel, in the order that they appear there.
+ optional NotificationList notifications = 3 [(log_mode) = MODE_BYTES];
+}
+
+/**
+ * Reports a notification channel, or channel group, was created, updated, or deleted.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/notification/
+ */
+message NotificationChannelModified {
+ // The event_id (as for UiEventReported).
+ optional int32 event_id = 1;
+ // The notifying app's uid and package.
+ optional int32 uid = 2 [(is_uid) = true];
+ optional string package_name = 3;
+ // App-assigned notification channel ID or channel-group ID
+ optional string channel_id = 4;
+ // Previous importance setting, if applicable
+ optional android.stats.sysui.NotificationImportance old_importance = 5;
+ // New importance setting
+ optional android.stats.sysui.NotificationImportance importance = 6;
+}
+
+
+/**
* Logs when a biometric acquire event occurs.
*
* Logged from:
@@ -3485,12 +3609,14 @@
INSTALL_FAILURE_DOWNLOAD = 23;
INSTALL_FAILURE_STATE_MISMATCH = 24;
INSTALL_FAILURE_COMMIT = 25;
+ REBOOT_TRIGGERED = 26;
}
optional State state = 6;
// Possible experiment ids for monitoring this push.
optional TrainExperimentIds experiment_ids = 7 [(log_mode) = MODE_BYTES];
// user id
optional int32 user_id = 8;
+ optional int32 reason = 9;
}
/* Test atom, is not logged anywhere */
@@ -6782,6 +6908,7 @@
INSTALL_FAILURE_DOWNLOAD = 23;
INSTALL_FAILURE_STATE_MISMATCH = 24;
INSTALL_FAILURE_COMMIT = 25;
+ REBOOT_TRIGGERED = 26;
}
optional Status status = 4;
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index b9f7a0b..591d727 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -185,20 +185,6 @@
{.additiveFields = {7, 9, 11, 13, 15, 17, 19, 21},
.puller = new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}},
- // DeviceCalculatedPowerUse.
- {{.atomTag = android::util::DEVICE_CALCULATED_POWER_USE},
- {.puller = new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}},
-
- // DeviceCalculatedPowerBlameUid.
- {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_UID},
- {.puller = new StatsCompanionServicePuller(
- android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}},
-
- // DeviceCalculatedPowerBlameOther.
- {{.atomTag = android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER},
- {.puller = new StatsCompanionServicePuller(
- android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}},
-
// DebugElapsedClock.
{{.atomTag = android::util::DEBUG_ELAPSED_CLOCK},
{.additiveFields = {1, 2, 3, 4},
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c3b07c8..2010cc98 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4064,6 +4064,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
public boolean switchUser(@NonNull UserHandle user) {
if (user == null) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 70262b0..0c5e67c 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -464,6 +464,9 @@
|| appDir.equals(instrumentedAppDir)) {
outZipPaths.clear();
outZipPaths.add(instrumentationAppDir);
+ if (!instrumentationAppDir.equals(instrumentedAppDir)) {
+ outZipPaths.add(instrumentedAppDir);
+ }
// Only add splits if the app did not request isolated split loading.
if (!aInfo.requestsIsolatedSplitLoading()) {
@@ -472,7 +475,6 @@
}
if (!instrumentationAppDir.equals(instrumentedAppDir)) {
- outZipPaths.add(instrumentedAppDir);
if (instrumentedSplitAppDirs != null) {
Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index bdc7b99..5a4622e 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,6 +15,8 @@
*/
package android.app;
+import static android.annotation.SystemApi.Client.MODULE_APPS;
+
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -105,6 +107,7 @@
private static final String ATT_ORIG_IMP = "orig_imp";
private static final String ATT_PARENT_CHANNEL = "parent";
private static final String ATT_CONVERSATION_ID = "conv_id";
+ private static final String ATT_DEMOTE = "dem";
private static final String DELIMITER = ",";
/**
@@ -194,6 +197,7 @@
private boolean mImportanceLockedDefaultApp;
private String mParentId = null;
private String mConversationId = null;
+ private boolean mDemoted = false;
/**
* Creates a notification channel.
@@ -260,6 +264,7 @@
mOriginalImportance = in.readInt();
mParentId = in.readString();
mConversationId = in.readString();
+ mDemoted = in.readBoolean();
}
@Override
@@ -317,6 +322,7 @@
dest.writeInt(mOriginalImportance);
dest.writeString(mParentId);
dest.writeString(mConversationId);
+ dest.writeBoolean(mDemoted);
}
/**
@@ -350,9 +356,13 @@
}
/**
+ * Allows users to block notifications sent through this channel, if this channel belongs to
+ * a package that is signed with the system signature. If the channel does not belong to a
+ * package that is signed with the system signature, this method does nothing.
+ * @param blockableSystem if {@code true}, allows users to block notifications on this channel.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi(client = MODULE_APPS)
@TestApi
public void setBlockableSystem(boolean blockableSystem) {
mBlockableSystem = blockableSystem;
@@ -386,8 +396,6 @@
return input;
}
- // Modifiable by apps on channel creation.
-
/**
* @hide
*/
@@ -395,6 +403,8 @@
mId = id;
}
+ // Modifiable by apps on channel creation.
+
/**
* Sets what group this channel belongs to.
*
@@ -767,6 +777,20 @@
}
/**
+ * @hide
+ */
+ public void setDemoted(boolean demoted) {
+ mDemoted = demoted;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean isDemoted() {
+ return mDemoted;
+ }
+
+ /**
* Returns whether the user has chosen the importance of this channel, either to affirm the
* initial selection from the app, or changed it to be higher or lower.
* @see #getImportance()
@@ -829,6 +853,7 @@
setOriginalImportance(safeInt(parser, ATT_ORIG_IMP, DEFAULT_IMPORTANCE));
setConversationId(parser.getAttributeValue(null, ATT_PARENT_CHANNEL),
parser.getAttributeValue(null, ATT_CONVERSATION_ID));
+ setDemoted(safeBool(parser, ATT_DEMOTE, false));
}
@Nullable
@@ -959,6 +984,9 @@
if (getConversationId() != null) {
out.attribute(null, ATT_CONVERSATION_ID, getConversationId());
}
+ if (isDemoted()) {
+ out.attribute(null, ATT_DEMOTE, Boolean.toString(isDemoted()));
+ }
// mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
// truth and so aren't written to this xml file
@@ -1118,7 +1146,8 @@
&& mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp
&& mOriginalImportance == that.mOriginalImportance
&& Objects.equals(getParentChannelId(), that.getParentChannelId())
- && Objects.equals(getConversationId(), that.getConversationId());
+ && Objects.equals(getConversationId(), that.getConversationId())
+ && isDemoted() == that.isDemoted();
}
@Override
@@ -1129,7 +1158,7 @@
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
mImportanceLockedByOEM, mImportanceLockedDefaultApp, mOriginalImportance,
- mParentId, mConversationId);
+ mParentId, mConversationId, mDemoted);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
}
@@ -1176,7 +1205,8 @@
+ ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
+ ", mOriginalImp=" + mOriginalImportance
+ ", mParent=" + mParentId
- + ", mConversationId=" + mConversationId;
+ + ", mConversationId=" + mConversationId
+ + ", mDemoted=" + mDemoted;
}
/** @hide */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3860508..679de8a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1827,6 +1827,7 @@
*/
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
@SystemApi
+ @TestApi
public void startActivityAsUser(@RequiresPermission @NonNull Intent intent,
@NonNull UserHandle user) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a45648f..7bddc1d 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1539,10 +1539,15 @@
* <p><code>p' = Rp</code></p>
* <p>where <code>p</code> is in the device sensor coordinate system, and
* <code>p'</code> is in the camera-oriented coordinate system.</p>
+ * <p>If {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, the quaternion rotation cannot
+ * be accurately represented by the camera device, and will be represented by
+ * default values matching its default facing.</p>
* <p><b>Units</b>:
* Quaternion coefficients</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
* <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
+ *
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
*/
@PublicKey
@NonNull
@@ -1577,6 +1582,8 @@
* <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
* the center of the primary gyroscope on the device. The axis definitions are the same as
* with PRIMARY_CAMERA.</p>
+ * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately
+ * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
* <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
@@ -1714,20 +1721,24 @@
new Key<float[]>("android.lens.radialDistortion", float[].class);
/**
- * <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
+ * <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, and the accuracy of
+ * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} and {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p>
* <p>Different calibration methods and use cases can produce better or worse results
* depending on the selected coordinate origin.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #LENS_POSE_REFERENCE_PRIMARY_CAMERA PRIMARY_CAMERA}</li>
* <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
+ * <li>{@link #LENS_POSE_REFERENCE_UNDEFINED UNDEFINED}</li>
* </ul></p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
* <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
*
+ * @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
* @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA
* @see #LENS_POSE_REFERENCE_GYROSCOPE
+ * @see #LENS_POSE_REFERENCE_UNDEFINED
*/
@PublicKey
@NonNull
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ec13a36..2377ccd 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -366,6 +366,20 @@
*/
public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1;
+ /**
+ * <p>The camera device cannot represent the values of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}
+ * and {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} accurately enough. One such example is a camera device
+ * on the cover of a foldable phone: in order to measure the pose translation and rotation,
+ * some kind of hinge position sensor would be needed.</p>
+ * <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} must be all zeros, and
+ * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} must be values matching its default facing.</p>
+ *
+ * @see CameraCharacteristics#LENS_POSE_ROTATION
+ * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
+ */
+ public static final int LENS_POSE_REFERENCE_UNDEFINED = 2;
+
//
// Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
//
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 9b305b32..6f0d135 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3027,10 +3027,15 @@
* <p><code>p' = Rp</code></p>
* <p>where <code>p</code> is in the device sensor coordinate system, and
* <code>p'</code> is in the camera-oriented coordinate system.</p>
+ * <p>If {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, the quaternion rotation cannot
+ * be accurately represented by the camera device, and will be represented by
+ * default values matching its default facing.</p>
* <p><b>Units</b>:
* Quaternion coefficients</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
* <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
+ *
+ * @see CameraCharacteristics#LENS_POSE_REFERENCE
*/
@PublicKey
@NonNull
@@ -3065,6 +3070,8 @@
* <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to
* the center of the primary gyroscope on the device. The axis definitions are the same as
* with PRIMARY_CAMERA.</p>
+ * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately
+ * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
* <p><b>Units</b>: Meters</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
* <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6650cf2..53f4615 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -424,6 +424,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@NonNull
@RequiresPermission(READ_DEVICE_CONFIG)
public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) {
@@ -593,6 +594,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(WRITE_DEVICE_CONFIG)
public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
@@ -817,6 +819,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static class BadConfigException extends Exception {}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 96a4a2f..f6633201 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2746,6 +2746,8 @@
public ArrayMap<String, String> getStringsForPrefix(ContentResolver cr, String prefix,
List<String> names) {
+ String namespace = prefix.substring(0, prefix.length() - 1);
+ DeviceConfig.enforceReadPermission(ActivityThread.currentApplication(), namespace);
ArrayMap<String, String> keyValues = new ArrayMap<>();
int currentGeneration = -1;
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index c9d3b92..a4fe6aa 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -985,7 +985,7 @@
* TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
*/
public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn,
- @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) {
+ int domain, int causeCode, int additionalCauseCode) {
// default implementation empty
}
@@ -1277,7 +1277,7 @@
}
public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
- @NonNull String chosenPlmn, @NetworkRegistrationInfo.Domain int domain,
+ @NonNull String chosenPlmn, int domain,
int causeCode, int additionalCauseCode) {
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 4dffa62..e25826c 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -701,7 +701,7 @@
*/
public void notifyRegistrationFailed(int slotIndex, int subId,
@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn,
- @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) {
+ int domain, int causeCode, int additionalCauseCode) {
try {
sRegistry.notifyRegistrationFailed(slotIndex, subId, cellIdentity,
chosenPlmn, domain, causeCode, additionalCauseCode);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c191a0d..eb4af1c 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -61,7 +61,7 @@
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "false");
DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
DEFAULT_FLAGS.put("settings_conditionals", "false");
- DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
}
/**
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index f324113..9921bf0 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.DeadSystemException;
@@ -400,7 +401,7 @@
* @param message The message you would like logged.
* @hide
*/
- // @SystemApi(client= SystemApi.Client.MODULE_LIBRARIES) // TODO Uncomment once http://ag/9956147 is in.
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static int logToRadioBuffer(@Level int priority, @Nullable String tag,
@Nullable String message) {
return println_native(LOG_ID_RADIO, priority, tag, message);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ff8455a..cc4278b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -122,6 +122,8 @@
private static native void nativeSetColor(long transactionObj, long nativeObject, float[] color);
private static native void nativeSetFlags(long transactionObj, long nativeObject,
int flags, int mask);
+ private static native void nativeSetFrameRateSelectionPriority(long transactionObj,
+ long nativeObject, int priority);
private static native void nativeSetWindowCrop(long transactionObj, long nativeObject,
int l, int t, int r, int b);
private static native void nativeSetCornerRadius(long transactionObj, long nativeObject,
@@ -2245,6 +2247,19 @@
}
/**
+ * This information is passed to SurfaceFlinger to decide which window should have a
+ * priority when deciding about the refresh rate of the display. All windows have the
+ * lowest priority by default.
+ * @hide
+ */
+ @NonNull
+ public Transaction setFrameRateSelectionPriority(@NonNull SurfaceControl sc, int priority) {
+ sc.checkNotReleased();
+ nativeSetFrameRateSelectionPriority(mNativeObject, sc.mNativeObject, priority);
+ return this;
+ }
+
+ /**
* Request that a given surface and it's sub-tree be shown.
*
* @param sc The surface to show.
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b47080f..573f378 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -423,6 +423,14 @@
transaction->setFlags(ctrl, flags, mask);
}
+static void nativeSetFrameRateSelectionPriority(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jint priority) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ transaction->setFrameRateSelectionPriority(ctrl, priority);
+}
+
static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject, jobject regionObj) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -1362,6 +1370,8 @@
(void*)nativeSetColorSpaceAgnostic },
{"nativeSetFlags", "(JJII)V",
(void*)nativeSetFlags },
+ {"nativeSetFrameRateSelectionPriority", "(JJI)V",
+ (void*)nativeSetFrameRateSelectionPriority },
{"nativeSetWindowCrop", "(JJIIII)V",
(void*)nativeSetWindowCrop },
{"nativeSetCornerRadius", "(JJF)V",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 39ea45a..05b573a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -174,6 +174,8 @@
static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;
+static constexpr const char* kCurProfileDirPath = "/data/misc/profiles/cur";
+
/**
* The maximum value that the gUSAPPoolSizeMax variable may take. This value
* is a mirror of ZygoteServer.USAP_POOL_SIZE_MAX_LIMIT
@@ -1382,6 +1384,49 @@
freecon(dataDataContext);
}
+/**
+ * Like isolateAppData(), isolate jit profile directories, so apps don't see what
+ * other apps are installed by reading content inside /data/misc/profiles/cur.
+ *
+ * The implementation is similar to isolateAppData(), it creates a tmpfs
+ * on /data/misc/profiles/cur, and bind mounts related package profiles to it.
+ */
+static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list,
+ uid_t uid, const char* process_name, jstring managed_nice_name,
+ fail_fn_t fail_fn) {
+
+ auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+ const userid_t user_id = multiuser_get_user_id(uid);
+
+ int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
+ // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
+ if ((size % 3) != 0) {
+ fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
+ }
+
+ // Mount (namespace) tmpfs on profile directory, so apps no longer access
+ // the original profile directory anymore.
+ MountAppDataTmpFs(kCurProfileDirPath, fail_fn);
+
+ // Create profile directory for this user.
+ std::string actualCurUserProfile = StringPrintf("%s/%d", kCurProfileDirPath, user_id);
+ PrepareDir(actualCurUserProfile.c_str(), DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+ fail_fn);
+
+ for (int i = 0; i < size; i += 3) {
+ jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
+ std::string packageName = extract_fn(package_str).value();
+
+ std::string actualCurPackageProfile = StringPrintf("%s/%s", actualCurUserProfile.c_str(),
+ packageName.c_str());
+ std::string mirrorCurPackageProfile = StringPrintf("/data_mirror/cur_profiles/%d/%s",
+ user_id, packageName.c_str());
+
+ PrepareDir(actualCurPackageProfile, DEFAULT_DATA_DIR_PERMISSION, uid, uid, fail_fn);
+ BindMount(mirrorCurPackageProfile, actualCurPackageProfile, fail_fn);
+ }
+}
+
// Utility routine to specialize a zygote child process.
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
@@ -1432,8 +1477,8 @@
// so they can't even traverse CE / DE directories.
if (pkg_data_info_list != nullptr
&& GetBoolProperty(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) {
- isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name,
- fail_fn);
+ isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+ isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
// If this zygote isn't root, it won't be able to create a process group,
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 8f9c041..da8c944 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -165,6 +165,11 @@
(section).args = "security -L"
];
+ optional android.util.PersistedLogProto persisted_logs = 1116 [
+ (section).type = SECTION_COMMAND,
+ (section).args = "/system/bin/sh /system/bin/incident-helper-cmd -l run persisted_logs --limit 10MB"
+ ];
+
// Stack dumps
optional android.os.BackTraceProto native_traces = 1200 [
(section).type = SECTION_TOMBSTONE,
diff --git a/core/proto/android/stats/sysui/notification_enums.proto b/core/proto/android/stats/sysui/notification_enums.proto
new file mode 100644
index 0000000..0983702
--- /dev/null
+++ b/core/proto/android/stats/sysui/notification_enums.proto
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+syntax = "proto2";
+
+package android.stats.sysui;
+
+// Enum used in NotificationReported and NotificationChannelModified atoms
+enum NotificationImportance { // Constants from NotificationManager.java
+ IMPORTANCE_UNSPECIFIED = -1000; // Should not occur for real notifications.
+ IMPORTANCE_NONE = 0; // No importance: does not show in the shade.
+ IMPORTANCE_MIN = 1; // Minimum to show in the shade.
+ IMPORTANCE_LOW = 2; // Shows in shade, maybe status bar, no buzz/beep.
+ IMPORTANCE_DEFAULT = 3; // Shows everywhere, makes noise, no heads-up.
+ IMPORTANCE_HIGH = 4; // Shows everywhere, makes noise, heads-up, may full-screen.
+}
diff --git a/core/proto/android/util/log.proto b/core/proto/android/util/log.proto
index 09870ae..a214a1a 100644
--- a/core/proto/android/util/log.proto
+++ b/core/proto/android/util/log.proto
@@ -94,3 +94,16 @@
repeated BinaryLogEntry binary_logs = 2;
}
+message PersistedLogProto {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ repeated TextLogEntry main_logs = 1;
+ repeated TextLogEntry radio_logs = 2;
+ repeated TextLogEntry events_logs = 3;
+ repeated TextLogEntry system_logs = 4;
+ repeated TextLogEntry crash_logs = 5;
+ repeated TextLogEntry stats_logs = 6;
+ repeated TextLogEntry security_logs = 7;
+ repeated TextLogEntry kernel_logs = 8;
+}
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0bc16a3..f8c5166 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -362,7 +362,6 @@
<protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
- <protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
<protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
@@ -377,6 +376,7 @@
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
<protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
+ <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABLE" />
<protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
<protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
<protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
diff --git a/core/tests/overlaytests/remount/host/AndroidTest.xml b/core/tests/overlaytests/remount/host/AndroidTest.xml
index 11eadf1a..087b731 100644
--- a/core/tests/overlaytests/remount/host/AndroidTest.xml
+++ b/core/tests/overlaytests/remount/host/AndroidTest.xml
@@ -19,9 +19,6 @@
<option name="test-tag" value="OverlayRemountedTest" />
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="remount" />
- </target_preparer>
<test class="com.android.tradefed.testtype.HostTest">
<option name="jar" value="OverlayRemountedTest.jar" />
diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlayHostTest.java b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlayHostTest.java
deleted file mode 100644
index 84af187..0000000
--- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlayHostTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.overlaytest.remounted;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-
-import org.junit.Rule;
-import org.junit.rules.RuleChain;
-import org.junit.rules.TemporaryFolder;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class OverlayHostTest extends BaseHostJUnit4Test {
- private static final long TIME_OUT_MS = 30000;
- private static final String RES_INSTRUMENTATION_ARG = "res";
- private static final String OVERLAY_INSTRUMENTATION_ARG = "overlays";
- private static final String RESOURCES_TYPE_SUFFIX = "_type";
- private static final String RESOURCES_DATA_SUFFIX = "_data";
-
- public final TemporaryFolder mTemporaryFolder = new TemporaryFolder();
- public final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder, this::getDevice);
-
- @Rule
- public final RuleChain ruleChain = RuleChain.outerRule(mTemporaryFolder).around(mPreparer);
- private Map<String, String> mLastResults;
-
- /**
- * Retrieves the values of the resources in the test package. The test package must use the
- * {@link com.android.overlaytest.remounted.target.ResourceRetrievalRunner} instrumentation.
- **/
- void retrieveResource(String testPackageName, List<String> requiredOverlayPaths,
- String... resourceNames) throws DeviceNotAvailableException {
- final HashMap<String, String> args = new HashMap<>();
- if (!requiredOverlayPaths.isEmpty()) {
- // Enclose the require overlay paths in quotes so the arguments will be string arguments
- // rather than file arguments.
- args.put(OVERLAY_INSTRUMENTATION_ARG,
- String.format("\"%s\"", String.join(" ", requiredOverlayPaths)));
- }
-
- if (resourceNames.length == 0) {
- throw new IllegalArgumentException("Must specify at least one resource to retrieve.");
- }
-
- // Pass the names of the resources to retrieve into the test as one string.
- args.put(RES_INSTRUMENTATION_ARG,
- String.format("\"%s\"", String.join(" ", resourceNames)));
-
- runDeviceTests(getDevice(), null, testPackageName, null, null, null, TIME_OUT_MS,
- TIME_OUT_MS, TIME_OUT_MS, false, false, args);
-
- // Retrieve the results of the most recently run test.
- mLastResults = (getLastDeviceRunResults().getRunMetrics() == mLastResults) ? null :
- getLastDeviceRunResults().getRunMetrics();
- }
-
- /** Returns the base resource directories of the specified packages. */
- List<String> getPackagePaths(String... packageNames)
- throws DeviceNotAvailableException {
- final ArrayList<String> paths = new ArrayList<>();
- for (String packageName : packageNames) {
- // Use the package manager shell command to find the path of the package.
- final String result = getDevice().executeShellCommand(
- String.format("pm dump %s | grep \"resourcePath=\"", packageName));
- assertNotNull("Failed to find path for package " + packageName, result);
- int splitIndex = result.indexOf('=');
- assertTrue(splitIndex >= 0);
- paths.add(result.substring(splitIndex + 1).trim());
- }
- return paths;
- }
-
- /** Builds the full name of a resource in the form package:type/entry. */
- String resourceName(String pkg, String type, String entry) {
- return String.format("%s:%s/%s", pkg, type, entry);
- }
-
- /**
- * Asserts that the type and data of a a previously retrieved is the same as expected.
- * @param resourceName the full name of the resource in the form package:type/entry
- * @param type the expected {@link android.util.TypedValue} type of the resource
- * @param data the expected value of the resource when coerced to a string using
- * {@link android.util.TypedValue#coerceToString()}
- **/
- void assertResource(String resourceName, int type, String data) {
- assertNotNull("Failed to get test results", mLastResults);
- assertNotEquals("No resource values were retrieved", mLastResults.size(), 0);
- assertEquals("" + type, mLastResults.get(resourceName + RESOURCES_TYPE_SUFFIX));
- assertEquals("" + data, mLastResults.get(resourceName + RESOURCES_DATA_SUFFIX));
- }
-}
diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
index 4939e16..06b2ac8 100644
--- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
+++ b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
@@ -16,17 +16,21 @@
package com.android.overlaytest.remounted;
+import static org.junit.Assert.assertTrue;
+
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
-import java.util.Collections;
-import java.util.List;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class OverlaySharedLibraryTest extends OverlayHostTest {
+public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
private static final String TARGET_APK = "OverlayRemountedTest_Target.apk";
private static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target";
private static final String SHARED_LIBRARY_APK =
@@ -38,6 +42,17 @@
private static final String SHARED_LIBRARY_OVERLAY_PACKAGE =
"com.android.overlaytest.remounted.shared_library.overlay";
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+ public final SystemPreparer preparer = new SystemPreparer(temporaryFolder, this::getDevice);
+
+ @Rule
+ public final RuleChain ruleChain = RuleChain.outerRule(temporaryFolder).around(preparer);
+
+ @Before
+ public void startBefore() throws DeviceNotAvailableException {
+ getDevice().waitForDeviceAvailable();
+ }
+
@Test
public void testSharedLibrary() throws Exception {
final String targetResource = resourceName(TARGET_PACKAGE, "bool",
@@ -45,23 +60,20 @@
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
"shared_library_overlaid");
- mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
+ preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
.reboot()
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, false)
.installResourceApk(TARGET_APK, TARGET_PACKAGE);
// The shared library resource is not currently overlaid.
- retrieveResource(Collections.emptyList(), targetResource, libraryResource);
- assertResource(targetResource, 0x12 /* TYPE_INT_BOOLEAN */, "false");
- assertResource(libraryResource, 0x12 /* TYPE_INT_BOOLEAN */, "false");
+ assertResource(targetResource, "false");
+ assertResource(libraryResource, "false");
// Overlay the shared library resource.
- mPreparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
- retrieveResource(getPackagePaths(SHARED_LIBRARY_OVERLAY_PACKAGE), targetResource,
- libraryResource);
- assertResource(targetResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
- assertResource(libraryResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
+ preparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
+ assertResource(targetResource, "true");
+ assertResource(libraryResource, "true");
}
@Test
@@ -71,20 +83,27 @@
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
"shared_library_overlaid");
- mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
+ preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true)
.reboot()
.installResourceApk(TARGET_APK, TARGET_PACKAGE);
- retrieveResource(getPackagePaths(SHARED_LIBRARY_OVERLAY_PACKAGE), targetResource,
- libraryResource);
- assertResource(targetResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
- assertResource(libraryResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
+ assertResource(targetResource, "true");
+ assertResource(libraryResource, "true");
}
- private void retrieveResource(List<String> requiredOverlayPaths, String... resourceNames)
+ /** Builds the full name of a resource in the form package:type/entry. */
+ String resourceName(String pkg, String type, String entry) {
+ return String.format("%s:%s/%s", pkg, type, entry);
+ }
+
+ void assertResource(String resourceName, String expectedValue)
throws DeviceNotAvailableException {
- retrieveResource(TARGET_PACKAGE, requiredOverlayPaths, resourceNames);
+ final String result = getDevice().executeShellCommand(
+ String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName));
+ assertTrue(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result),
+ result.equals(expectedValue + "\n") ||
+ result.endsWith("-> " + expectedValue + "\n"));
}
}
diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java
index 7028f2f..8696091 100644
--- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java
+++ b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java
@@ -38,8 +38,7 @@
import java.util.concurrent.TimeoutException;
class SystemPreparer extends ExternalResource {
- private static final long REBOOT_SLEEP_MS = 30000;
- private static final long OVERLAY_ENABLE_TIMEOUT_MS = 20000;
+ private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
// The paths of the files pushed onto the device through this rule.
private ArrayList<String> mPushedFiles = new ArrayList<>();
@@ -59,6 +58,7 @@
SystemPreparer pushResourceFile(String resourcePath,
String outputPath) throws DeviceNotAvailableException, IOException {
final ITestDevice device = mDeviceProvider.getDevice();
+ device.executeAdbCommand("remount");
assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath));
mPushedFiles.add(outputPath);
return this;
@@ -77,7 +77,7 @@
/** Sets the enable state of an overlay pacakage. */
SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
- throws ExecutionException, TimeoutException {
+ throws ExecutionException, DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
// Wait for the overlay to change its enabled state.
@@ -86,8 +86,10 @@
device.executeShellCommand(String.format("cmd overlay %s %s",
enabled ? "enable" : "disable", packageName));
- final String pattern = (enabled ? "[x]" : "[ ]") + " " + packageName;
- if (device.executeShellCommand("cmd overlay list").contains(pattern)) {
+ final String result = device.executeShellCommand("cmd overlay dump " + packageName);
+ final int startIndex = result.indexOf("mIsEnabled");
+ final int endIndex = result.indexOf('\n', startIndex);
+ if (result.substring(startIndex, endIndex).contains((enabled) ? "true" : "false")) {
return true;
}
}
@@ -98,6 +100,8 @@
try {
enabledListener.get(OVERLAY_ENABLE_TIMEOUT_MS, MILLISECONDS);
} catch (InterruptedException ignored) {
+ } catch (TimeoutException e) {
+ throw new IllegalStateException(device.executeShellCommand("cmd overlay list"));
}
return this;
@@ -106,14 +110,7 @@
/** Restarts the device and waits until after boot is completed. */
SystemPreparer reboot() throws DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
- device.executeShellCommand("stop");
- device.executeShellCommand("start");
- try {
- // Sleep until the device is ready for test execution.
- Thread.sleep(REBOOT_SLEEP_MS);
- } catch (InterruptedException ignored) {
- }
-
+ device.reboot();
return this;
}
@@ -141,12 +138,14 @@
protected void after() {
final ITestDevice device = mDeviceProvider.getDevice();
try {
+ device.executeAdbCommand("remount");
for (final String file : mPushedFiles) {
device.deleteFile(file);
}
for (final String packageName : mInstalledPackages) {
device.uninstallPackage(packageName);
}
+ device.reboot();
} catch (DeviceNotAvailableException e) {
Assert.fail(e.toString());
}
diff --git a/core/tests/overlaytests/remount/target/AndroidManifest.xml b/core/tests/overlaytests/remount/target/AndroidManifest.xml
index 32fec43..dc07dca 100644
--- a/core/tests/overlaytests/remount/target/AndroidManifest.xml
+++ b/core/tests/overlaytests/remount/target/AndroidManifest.xml
@@ -23,8 +23,4 @@
<uses-library android:name="com.android.overlaytest.remounted.shared_library"
android:required="true" />
</application>
-
- <instrumentation android:name="com.android.overlaytest.remounted.target.ResourceRetrievalRunner"
- android:targetPackage="com.android.overlaytest.remounted.target"
- android:label="Remounted system RRO tests" />
</manifest>
diff --git a/core/tests/overlaytests/remount/target/src/com/android/overlaytest/remounted/target/ResourceRetrievalRunner.java b/core/tests/overlaytests/remount/target/src/com/android/overlaytest/remounted/target/ResourceRetrievalRunner.java
deleted file mode 100644
index 2e4c211..0000000
--- a/core/tests/overlaytests/remount/target/src/com/android/overlaytest/remounted/target/ResourceRetrievalRunner.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.overlaytest.remounted.target;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.TypedValue;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.Executor;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An {@link Instrumentation} that retrieves the value of specified resources within the
- * application.
- **/
-public class ResourceRetrievalRunner extends Instrumentation {
- private static final String TAG = ResourceRetrievalRunner.class.getSimpleName();
-
- // A list of whitespace separated resource names of which to retrieve the resource values.
- private static final String RESOURCE_LIST_TAG = "res";
-
- // A list of whitespace separated overlay package paths that must be present before retrieving
- // resource values.
- private static final String REQUIRED_OVERLAYS_LIST_TAG = "overlays";
-
- // The suffixes of the keys returned from the instrumentation. To retrieve the type of a
- // resource looked up with the instrumentation, append the {@link #RESOURCES_TYPE_SUFFIX} suffix
- // to the end of the name of the resource. For the value of a resource, use
- // {@link #RESOURCES_DATA_SUFFIX} instead.
- private static final String RESOURCES_TYPE_SUFFIX = "_type";
- private static final String RESOURCES_DATA_SUFFIX = "_data";
-
- // The amount of time in seconds to wait for the overlays to be present in the AssetManager.
- private static final int OVERLAY_PATH_TIMEOUT = 60;
-
- private final ArrayList<String> mResourceNames = new ArrayList<>();
- private final ArrayList<String> mOverlayPaths = new ArrayList<>();
- private final Bundle mResult = new Bundle();
-
- /**
- * Receives the instrumentation arguments and runs the resource retrieval.
- * The entry with key {@link #RESOURCE_LIST_TAG} in the {@link Bundle} arguments is a
- * whitespace separated string of resource names of which to retrieve the resource values.
- * The entry with key {@link #REQUIRED_OVERLAYS_LIST_TAG} in the {@link Bundle} arguments is a
- * whitespace separated string of overlay package paths prefixes that must be present before
- * retrieving the resource values.
- */
- @Override
- public void onCreate(Bundle arguments) {
- super.onCreate(arguments);
- mResourceNames.addAll(Arrays.asList(arguments.getString(RESOURCE_LIST_TAG).split(" ")));
- if (arguments.containsKey(REQUIRED_OVERLAYS_LIST_TAG)) {
- mOverlayPaths.addAll(Arrays.asList(
- arguments.getString(REQUIRED_OVERLAYS_LIST_TAG).split(" ")));
- }
- start();
- }
-
- @Override
- public void onStart() {
- final Resources res = getContext().getResources();
- res.getAssets().setResourceResolutionLoggingEnabled(true);
-
- if (!mOverlayPaths.isEmpty()) {
- Log.d(TAG, String.format("Waiting for overlay paths [%s]",
- String.join(",", mOverlayPaths)));
-
- // Wait for all required overlays to be present in the AssetManager.
- final FutureTask<Boolean> overlayListener = new FutureTask<>(() -> {
- while (!mOverlayPaths.isEmpty()) {
- final String[] apkPaths = res.getAssets().getApkPaths();
- for (String path : apkPaths) {
- for (String overlayPath : mOverlayPaths) {
- if (path.startsWith(overlayPath)) {
- mOverlayPaths.remove(overlayPath);
- break;
- }
- }
- }
- }
- return true;
- });
-
- try {
- final Executor executor = (t) -> new Thread(t).start();
- executor.execute(overlayListener);
- overlayListener.get(OVERLAY_PATH_TIMEOUT, TimeUnit.SECONDS);
- } catch (Exception e) {
- Log.e(TAG, String.format("Failed to wait for required overlays [%s]",
- String.join(",", mOverlayPaths)), e);
- finish(Activity.RESULT_CANCELED, mResult);
- }
- }
-
- // Retrieve the values for each resource passed in.
- final TypedValue typedValue = new TypedValue();
- for (final String resourceName : mResourceNames) {
- try {
- final int resId = res.getIdentifier(resourceName, null, null);
- res.getValue(resId, typedValue, true);
- Log.d(TAG, String.format("Resolution for 0x%s: %s", Integer.toHexString(resId),
- res.getAssets().getLastResourceResolution()));
- } catch (Resources.NotFoundException e) {
- Log.e(TAG, "Failed to retrieve value for resource " + resourceName, e);
- finish(Activity.RESULT_CANCELED, mResult);
- }
-
- putValue(resourceName, typedValue);
- }
-
- finish(Activity.RESULT_OK, mResult);
- }
-
- private void putValue(String resourceName, TypedValue value) {
- mResult.putInt(resourceName + RESOURCES_TYPE_SUFFIX, value.type);
- final CharSequence textValue = value.coerceToString();
- mResult.putString(resourceName + RESOURCES_DATA_SUFFIX,
- textValue == null ? "null" : textValue.toString());
- }
-}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0574775..877ef26 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -180,7 +180,6 @@
<assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
<assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
- <assign-permission name="android.permission.BATTERY_STATS" uid="statsd" />
<assign-permission name="android.permission.DUMP" uid="statsd" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
<assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index b93759f..c445885 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -108,10 +108,26 @@
}
}
+// FIXME: Share with the version in android_bitmap.cpp?
+// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut
+// matches the white point used by ColorSpace.Named.DCIP3.
+static constexpr skcms_Matrix3x3 kDCIP3 = {{
+ {0.486143, 0.323835, 0.154234},
+ {0.226676, 0.710327, 0.0629966},
+ {0.000800549, 0.0432385, 0.78275},
+}};
+
sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
if (dataspace == HAL_DATASPACE_UNKNOWN) {
return SkColorSpace::MakeSRGB();
}
+ if (dataspace == HAL_DATASPACE_DCI_P3) {
+ // This cannot be handled by the switch statements below because it
+ // needs to use the locally-defined kDCIP3 gamut, rather than the one in
+ // Skia (SkNamedGamut), which is used for other data spaces with
+ // HAL_DATASPACE_STANDARD_DCI_P3 (e.g. HAL_DATASPACE_DISPLAY_P3).
+ return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, kDCIP3);
+ }
skcms_Matrix3x3 gamut;
switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
@@ -152,10 +168,12 @@
return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_GAMMA2_8:
return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
return nullptr;
- case HAL_DATASPACE_TRANSFER_SMPTE_170M:
- case HAL_DATASPACE_TRANSFER_ST2084:
case HAL_DATASPACE_TRANSFER_HLG:
default:
ALOGV("Unsupported Gamma: %d", dataspace);
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 5a72b22..18969ae 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -16,6 +16,7 @@
package android.media.tv.tuner;
+import android.annotation.BytesLong;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,6 +28,8 @@
import android.media.tv.tuner.TunerConstants.FrontendScanType;
import android.media.tv.tuner.TunerConstants.Result;
import android.media.tv.tuner.dvr.Dvr;
+import android.media.tv.tuner.dvr.DvrCallback;
+import android.media.tv.tuner.dvr.DvrSettings;
import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
import android.media.tv.tuner.filter.FilterEvent;
import android.media.tv.tuner.filter.TimeFilter;
@@ -88,6 +91,31 @@
nativeSetup();
}
+ /**
+ * Constructs a Tuner instance.
+ *
+ * @param context the context of the caller.
+ * @param tvInputSessionId the session ID of the TV input.
+ * @param useCase the use case of this Tuner instance.
+ *
+ * @hide
+ * TODO: replace the other constructor
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ public Tuner(@NonNull Context context, @NonNull String tvInputSessionId, int useCase) {
+ mContext = context;
+ }
+
+ /**
+ * Shares the frontend resource with another Tuner instance
+ *
+ * @param tuner the Tuner instance to share frontend resource with.
+ *
+ * @hide
+ */
+ public void shareFrontend(@NonNull Tuner tuner) { }
+
+
private long mNativeContext; // used by native jMediaTuner
/** @hide */
@@ -125,7 +153,7 @@
private native int nativeConnectCiCam(int ciCamId);
private native int nativeDisconnectCiCam();
private native FrontendInfo nativeGetFrontendInfo(int id);
- private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
+ private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
private native TimeFilter nativeOpenTimeFilter();
private native List<Integer> nativeGetLnbIds();
@@ -133,7 +161,7 @@
private native Descrambler nativeOpenDescrambler();
- private native Dvr nativeOpenDvr(int type, int bufferSize);
+ private native Dvr nativeOpenDvr(int type, long bufferSize);
private static native DemuxCapabilities nativeGetDemuxCapabilities();
@@ -159,6 +187,21 @@
void onFilterStatusChanged(@NonNull Filter filter, @FilterStatus int status);
}
+
+ /**
+ * Listener for resource lost.
+ *
+ * @hide
+ */
+ public interface OnResourceLostListener {
+ /**
+ * Invoked when resource lost.
+ *
+ * @param tuner the tuner instance whose resource is being reclaimed.
+ */
+ void onResourceLost(@NonNull Tuner tuner);
+ }
+
@Nullable
private EventHandler createEventHandler() {
Looper looper;
@@ -221,23 +264,32 @@
/**
* Stops a previous tuning.
*
- * If the method completes successfully the frontend is no longer tuned and no data
+ * <p>If the method completes successfully, the frontend is no longer tuned and no data
* will be sent to attached filters.
*
* @return result status of the operation.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Result
public int stopTune() {
+ TunerUtils.checkTunerPermission(mContext);
return nativeStopTune();
}
/**
* Scan channels.
+ *
+ * @param settings A {@link FrontendSettings} to configure the frontend.
+ * @param scanType The scan type.
+ *
* @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType,
@NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
+ TunerUtils.checkTunerPermission(mContext);
mScanCallback = scanCallback;
mScanCallbackExecutor = executor;
return nativeScan(settings.getType(), settings, scanType);
@@ -255,6 +307,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Result
public int stopScan() {
TunerUtils.checkTunerPermission(mContext);
int retVal = nativeStopScan();
@@ -266,37 +319,44 @@
/**
* Sets Low-Noise Block downconverter (LNB) for satellite frontend.
*
- * This assigns a hardware LNB resource to the satellite tuner. It can be
+ * <p>This assigns a hardware LNB resource to the satellite tuner. It can be
* called multiple times to update LNB assignment.
*
* @param lnb the LNB instance.
*
* @return result status of the operation.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Result
public int setLnb(@NonNull Lnb lnb) {
+ TunerUtils.checkTunerPermission(mContext);
return nativeSetLnb(lnb.mId);
}
/**
* Enable or Disable Low Noise Amplifier (LNA).
*
- * @param enable true to activate LNA module; false to deactivate LNA
+ * @param enable {@code true} to activate LNA module; {@code false} to deactivate LNA.
*
* @return result status of the operation.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Result
public int setLna(boolean enable) {
+ TunerUtils.checkTunerPermission(mContext);
return nativeSetLna(enable);
}
/**
* Gets the statuses of the frontend.
*
- * This retrieve the statuses of the frontend for given status types.
+ * <p>This retrieve the statuses of the frontend for given status types.
*
- * @param statusTypes an array of status type which the caller request.
- *
+ * @param statusTypes an array of status types which the caller requests.
* @return statuses which response the caller's requests.
* @hide
*/
@@ -310,59 +370,77 @@
*
* @param filter the filter instance for the hardware sync ID.
* @return the id of hardware A/V sync.
+ *
* @hide
*/
- public int getAvSyncHwId(Filter filter) {
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ public int getAvSyncHwId(@NonNull Filter filter) {
+ TunerUtils.checkTunerPermission(mContext);
return nativeGetAvSyncHwId(filter);
}
+
/**
- * Gets the current timestamp for A/V sync
+ * Gets the current timestamp for Audio/Video sync
*
- * The timestamp is maintained by hardware. The timestamp based on 90KHz, and it's format is the
- * same as PTS (Presentation Time Stamp).
+ * <p>The timestamp is maintained by hardware. The timestamp based on 90KHz, and it's format is
+ * the same as PTS (Presentation Time Stamp).
*
* @param avSyncHwId the hardware id of A/V sync.
* @return the current timestamp of hardware A/V sync.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
public long getAvSyncTime(int avSyncHwId) {
+ TunerUtils.checkTunerPermission(mContext);
return nativeGetAvSyncTime(avSyncHwId);
}
-
/**
* Connects Conditional Access Modules (CAM) through Common Interface (CI)
*
- * The demux uses the output from the frontend as the input by default, and must change to use
- * the output from CI-CAM as the input after this call.
+ * <p>The demux uses the output from the frontend as the input by default, and must change to
+ * use the output from CI-CAM as the input after this call.
*
* @param ciCamId specify CI-CAM Id to connect.
* @return result status of the operation.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Result
public int connectCiCam(int ciCamId) {
+ TunerUtils.checkTunerPermission(mContext);
return nativeConnectCiCam(ciCamId);
}
/**
* Disconnects Conditional Access Modules (CAM)
*
- * The demux will use the output from the frontend as the input after this call.
+ * <p>The demux will use the output from the frontend as the input after this call.
*
* @return result status of the operation.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Result
public int disconnectCiCam() {
+ TunerUtils.checkTunerPermission(mContext);
return nativeDisconnectCiCam();
}
/**
- * Retrieve the frontend information.
+ * Gets the frontend information.
+ *
+ * @return The frontend information. {@code null} if the operation failed.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Nullable
public FrontendInfo getFrontendInfo() {
+ TunerUtils.checkTunerPermission(mContext);
if (mFrontend == null) {
throw new IllegalStateException("frontend is not initialized");
}
@@ -370,10 +448,13 @@
}
/**
- * Gets frontend ID.
+ * Gets the frontend ID.
+ *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
public int getFrontendId() {
+ TunerUtils.checkTunerPermission(mContext);
if (mFrontend == null) {
throw new IllegalStateException("frontend is not initialized");
}
@@ -382,6 +463,7 @@
/**
* Gets Demux capabilities.
+ *
* @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@@ -424,8 +506,26 @@
private Filter() {}
}
- private Filter openFilter(@FilterType int mainType, @FilterSubtype int subType, int bufferSize,
- FilterCallback cb) {
+ /**
+ * Opens a filter object based on the given types and buffer size.
+ *
+ * @param mainType the main type of the filter.
+ * @param subType the subtype of the filter.
+ * @param bufferSize the buffer size of the filter to be opened in bytes. The buffer holds the
+ * data output from the filter.
+ * @param cb the callback to receive notifications from filter.
+ * @param executor the executor on which callback will be invoked. The default event handler
+ * executor is used if it's {@code null}.
+ * @return the opened filter. {@code null} if the operation failed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Nullable
+ public Filter openFilter(@FilterType int mainType, @FilterSubtype int subType,
+ @BytesLong long bufferSize, @Nullable FilterCallback cb,
+ @CallbackExecutor @Nullable Executor executor) {
+ TunerUtils.checkTunerPermission(mContext);
Filter filter = nativeOpenFilter(
mainType, TunerUtils.getFilterSubtype(mainType, subType), bufferSize);
if (filter != null) {
@@ -437,6 +537,24 @@
return filter;
}
+ /**
+ * Opens an LNB (low-noise block downconverter) object.
+ *
+ * @param cb the callback to receive notifications from LNB.
+ * @param executor the executor on which callback will be invoked. The default event handler
+ * executor is used if it's {@code null}.
+ * @return the opened LNB object. {@code null} if the operation failed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Nullable
+ public Lnb openLnb(LnbCallback cb, @CallbackExecutor @Nullable Executor executor) {
+ TunerUtils.checkTunerPermission(mContext);
+ // TODO: use resource manager to get LNB ID.
+ return new Lnb(0);
+ }
+
private List<Integer> getLnbIds() {
mLnbIds = nativeGetLnbIds();
return mLnbIds;
@@ -484,7 +602,24 @@
return nativeOpenDescrambler();
}
- private Dvr openDvr(int type, int bufferSize) {
+ /**
+ * Open a DVR (Digital Video Record) instance.
+ *
+ * @param type the DVR type to be opened.
+ * @param bufferSize the buffer size of the output in bytes. It's used to hold output data of
+ * the attached filters.
+ * @param cb the callback to receive notifications from DVR.
+ * @param executor the executor on which callback will be invoked. The default event handler
+ * executor is used if it's {@code null}.
+ * @return the opened DVR object. {@code null} if the operation failed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Nullable
+ public Dvr openDvr(@DvrSettings.Type int type, @BytesLong long bufferSize, DvrCallback cb,
+ @CallbackExecutor @Nullable Executor executor) {
+ TunerUtils.checkTunerPermission(mContext);
Dvr dvr = nativeOpenDvr(type, bufferSize);
return dvr;
}
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index 19cfa32..fa8f550 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -129,93 +129,29 @@
*/
public static final int FILTER_STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW;
- /**
- * Indexes can be tagged through TS (Transport Stream) header.
- *
- * @hide
- */
- @IntDef(flag = true, value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
- TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
- TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
- TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR, TS_INDEX_PCR_FLAG,
- TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG, TS_INDEX_PRIVATE_DATA,
- TS_INDEX_ADAPTATION_EXTENSION_FLAG})
+
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
- public @interface TsIndex {}
+ @IntDef(prefix = "INDEX_TYPE_", value =
+ {INDEX_TYPE_NONE, INDEX_TYPE_SC, INDEX_TYPE_SC_HEVC})
+ public @interface ScIndexType {}
/**
- * TS index FIRST_PACKET.
+ * Start Code Index is not used.
* @hide
*/
- public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
+ public static final int INDEX_TYPE_NONE = Constants.DemuxRecordScIndexType.NONE;
/**
- * TS index PAYLOAD_UNIT_START_INDICATOR.
+ * Start Code index.
* @hide
*/
- public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR =
- Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR;
+ public static final int INDEX_TYPE_SC = Constants.DemuxRecordScIndexType.SC;
/**
- * TS index CHANGE_TO_NOT_SCRAMBLED.
+ * Start Code index for HEVC.
* @hide
*/
- public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED =
- Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED;
- /**
- * TS index CHANGE_TO_EVEN_SCRAMBLED.
- * @hide
- */
- public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED =
- Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED;
- /**
- * TS index CHANGE_TO_ODD_SCRAMBLED.
- * @hide
- */
- public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED =
- Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED;
- /**
- * TS index DISCONTINUITY_INDICATOR.
- * @hide
- */
- public static final int TS_INDEX_DISCONTINUITY_INDICATOR =
- Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR;
- /**
- * TS index RANDOM_ACCESS_INDICATOR.
- * @hide
- */
- public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR =
- Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR;
- /**
- * TS index PRIORITY_INDICATOR.
- * @hide
- */
- public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR;
- /**
- * TS index PCR_FLAG.
- * @hide
- */
- public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG;
- /**
- * TS index OPCR_FLAG.
- * @hide
- */
- public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG;
- /**
- * TS index SPLICING_POINT_FLAG.
- * @hide
- */
- public static final int TS_INDEX_SPLICING_POINT_FLAG =
- Constants.DemuxTsIndex.SPLICING_POINT_FLAG;
- /**
- * TS index PRIVATE_DATA.
- * @hide
- */
- public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA;
- /**
- * TS index ADAPTATION_EXTENSION_FLAG.
- * @hide
- */
- public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
- Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+ public static final int INDEX_TYPE_SC_HEVC = Constants.DemuxRecordScIndexType.SC_HEVC;
+
/**
* Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index f0fe533..fcca6a1 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -16,20 +16,123 @@
package android.media.tv.tuner.filter;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Filter configuration for a ALP filter.
* @hide
*/
public class AlpFilterConfiguration extends FilterConfiguration {
- private int mPacketType;
- private int mLengthType;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "LENGTH_TYPE_", value =
+ {LENGTH_TYPE_UNDEFINED, LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER,
+ LENGTH_TYPE_WITH_ADDITIONAL_HEADER})
+ public @interface LengthType {}
- public AlpFilterConfiguration(Settings settings) {
+ /**
+ * Length type not defined.
+ */
+ public static final int LENGTH_TYPE_UNDEFINED = Constants.DemuxAlpLengthType.UNDEFINED;
+ /**
+ * Length does NOT include additional header.
+ */
+ public static final int LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER =
+ Constants.DemuxAlpLengthType.WITHOUT_ADDITIONAL_HEADER;
+ /**
+ * Length includes additional header.
+ */
+ public static final int LENGTH_TYPE_WITH_ADDITIONAL_HEADER =
+ Constants.DemuxAlpLengthType.WITH_ADDITIONAL_HEADER;
+
+
+ private final int mPacketType;
+ private final int mLengthType;
+
+ public AlpFilterConfiguration(Settings settings, int packetType, int lengthType) {
super(settings);
+ mPacketType = packetType;
+ mLengthType = lengthType;
}
@Override
public int getType() {
return FilterConfiguration.FILTER_TYPE_ALP;
}
+
+ /**
+ * Gets packet type.
+ */
+ @FilterConfiguration.PacketType
+ public int getPacketType() {
+ return mPacketType;
+ }
+ /**
+ * Gets length type.
+ */
+ @LengthType
+ public int getLengthType() {
+ return mLengthType;
+ }
+
+ /**
+ * Creates a builder for {@link AlpFilterConfiguration}.
+ *
+ * @param context the context of the caller.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link AlpFilterConfiguration}.
+ */
+ public static class Builder extends FilterConfiguration.Builder<Builder> {
+ private int mPacketType;
+ private int mLengthType;
+
+ private Builder() {
+ }
+
+ /**
+ * Sets packet type.
+ */
+ @NonNull
+ public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+ mPacketType = packetType;
+ return this;
+ }
+ /**
+ * Sets length type.
+ */
+ @NonNull
+ public Builder setLengthType(@LengthType int lengthType) {
+ mLengthType = lengthType;
+ return this;
+ }
+
+ /**
+ * Builds a {@link AlpFilterConfiguration} object.
+ */
+ @NonNull
+ public AlpFilterConfiguration build() {
+ return new AlpFilterConfiguration(mSettings, mPacketType, mLengthType);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index a7c49d5..940b5ae 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -16,21 +16,84 @@
package android.media.tv.tuner.filter;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Filter Settings for a Video and Audio.
+ *
* @hide
*/
public class AvSettings extends Settings {
- private boolean mIsPassthrough;
+ private final boolean mIsPassthrough;
- private AvSettings(int mainType, boolean isAudio) {
+ private AvSettings(int mainType, boolean isAudio, boolean isPassthrough) {
super(TunerUtils.getFilterSubtype(
mainType,
isAudio
? TunerConstants.FILTER_SUBTYPE_AUDIO
: TunerConstants.FILTER_SUBTYPE_VIDEO));
+ mIsPassthrough = isPassthrough;
+ }
+
+ /**
+ * Checks whether it's passthrough.
+ */
+ public boolean isPassthrough() {
+ return mIsPassthrough;
+ }
+
+ /**
+ * Creates a builder for {@link AvSettings}.
+ *
+ * @param context the context of the caller.
+ * @param mainType the filter main type.
+ * @param isAudio {@code true} if it's audio settings; {@code false} if it's video settings.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(
+ @NonNull Context context, @FilterType int mainType, boolean isAudio) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder(mainType, isAudio);
+ }
+
+ /**
+ * Builder for {@link AvSettings}.
+ */
+ public static class Builder extends Settings.Builder<Builder> {
+ private final boolean mIsAudio;
+ private boolean mIsPassthrough;
+
+ private Builder(int mainType, boolean isAudio) {
+ super(mainType);
+ mIsAudio = isAudio;
+ }
+
+ /**
+ * Sets whether it's passthrough.
+ */
+ @NonNull
+ public Builder setPassthrough(boolean isPassthrough) {
+ mIsPassthrough = isPassthrough;
+ return this;
+ }
+
+ /**
+ * Builds a {@link AvSettings} object.
+ */
+ @NonNull
+ public AvSettings build() {
+ return new AvSettings(mMainType, mIsAudio, mIsPassthrough);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/DownloadSettings.java b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
index 0742b11..e3e1df0 100644
--- a/media/java/android/media/tv/tuner/filter/DownloadSettings.java
+++ b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
@@ -16,17 +16,75 @@
package android.media.tv.tuner.filter;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Filter Settings for a Download.
* @hide
*/
public class DownloadSettings extends Settings {
- private int mDownloadId;
+ private final int mDownloadId;
- public DownloadSettings(int mainType) {
+ private DownloadSettings(int mainType, int downloadId) {
super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD));
+ mDownloadId = downloadId;
+ }
+
+ /**
+ * Gets download ID.
+ */
+ public int getDownloadId() {
+ return mDownloadId;
+ }
+
+ /**
+ * Creates a builder for {@link DownloadSettings}.
+ *
+ * @param context the context of the caller.
+ * @param mainType the filter main type.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder(mainType);
+ }
+
+ /**
+ * Builder for {@link DownloadSettings}.
+ */
+ public static class Builder extends Settings.Builder<Builder> {
+ private int mDownloadId;
+
+ private Builder(int mainType) {
+ super(mainType);
+ }
+
+ /**
+ * Sets download ID.
+ */
+ @NonNull
+ public Builder setDownloadId(int downloadId) {
+ mDownloadId = downloadId;
+ return this;
+ }
+
+ /**
+ * Builds a {@link DownloadSettings} object.
+ */
+ @NonNull
+ public DownloadSettings build() {
+ return new DownloadSettings(mMainType, mDownloadId);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index 6496627..68c722f 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -33,7 +33,8 @@
public abstract class FilterConfiguration {
/** @hide */
- @IntDef({FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP})
+ @IntDef(prefix = "FILTER_TYPE_", value =
+ {FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP})
@Retention(RetentionPolicy.SOURCE)
public @interface FilterType {}
@@ -58,6 +59,30 @@
*/
public static final int FILTER_TYPE_ALP = Constants.DemuxFilterMainType.ALP;
+
+ /** @hide */
+ @IntDef(prefix = "PACKET_TYPE_", value =
+ {PACKET_TYPE_IPV4, PACKET_TYPE_COMPRESSED, PACKET_TYPE_SIGNALING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PacketType {}
+
+ /**
+ * IP v4 packet type.
+ * @hide
+ */
+ public static final int PACKET_TYPE_IPV4 = 0;
+ /**
+ * Compressed packet type.
+ * @hide
+ */
+ public static final int PACKET_TYPE_COMPRESSED = 2;
+ /**
+ * Signaling packet type.
+ * @hide
+ */
+ public static final int PACKET_TYPE_SIGNALING = 4;
+
+
@Nullable
/* package */ final Settings mSettings;
@@ -77,4 +102,27 @@
public Settings getSettings() {
return mSettings;
}
+
+ /**
+ * Builder for {@link FilterConfiguration}.
+ *
+ * @param <T> The subclass to be built.
+ * @hide
+ */
+ public abstract static class Builder<T extends Builder<T>> {
+ /* package */ Settings mSettings;
+
+ /* package */ Builder() {
+ }
+
+ /**
+ * Sets filter settings.
+ */
+ @Nullable
+ public T setFrequency(Settings settings) {
+ mSettings = settings;
+ return self();
+ }
+ /* package */ abstract T self();
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index c896368..98edf10 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -16,23 +16,152 @@
package android.media.tv.tuner.filter;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.Size;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+
/**
* Filter configuration for a IP filter.
* @hide
*/
public class IpFilterConfiguration extends FilterConfiguration {
- private byte[] mSrcIpAddress;
- private byte[] mDstIpAddress;
- private int mSrcPort;
- private int mDstPort;
- private boolean mPassthrough;
+ private final byte[] mSrcIpAddress;
+ private final byte[] mDstIpAddress;
+ private final int mSrcPort;
+ private final int mDstPort;
+ private final boolean mPassthrough;
- public IpFilterConfiguration(Settings settings) {
+ public IpFilterConfiguration(Settings settings, byte[] srcAddr, byte[] dstAddr, int srcPort,
+ int dstPort, boolean passthrough) {
super(settings);
+ mSrcIpAddress = srcAddr;
+ mDstIpAddress = dstAddr;
+ mSrcPort = srcPort;
+ mDstPort = dstPort;
+ mPassthrough = passthrough;
}
@Override
public int getType() {
return FilterConfiguration.FILTER_TYPE_IP;
}
+
+ /**
+ * Gets source IP address.
+ */
+ @Size(min = 4, max = 16)
+ public byte[] getSrcIpAddress() {
+ return mSrcIpAddress;
+ }
+ /**
+ * Gets destination IP address.
+ */
+ @Size(min = 4, max = 16)
+ public byte[] getDstIpAddress() {
+ return mDstIpAddress;
+ }
+ /**
+ * Gets source port.
+ */
+ public int getSrcPort() {
+ return mSrcPort;
+ }
+ /**
+ * Gets destination port.
+ */
+ public int getDstPort() {
+ return mDstPort;
+ }
+ /**
+ * Checks whether the filter is passthrough.
+ *
+ * @return {@code true} if the data from IP subtype go to next filter directly;
+ * {@code false} otherwise.
+ */
+ public boolean isPassthrough() {
+ return mPassthrough;
+ }
+
+ /**
+ * Creates a builder for {@link IpFilterConfiguration}.
+ *
+ * @param context the context of the caller.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link IpFilterConfiguration}.
+ */
+ public static class Builder extends FilterConfiguration.Builder<Builder> {
+ private byte[] mSrcIpAddress;
+ private byte[] mDstIpAddress;
+ private int mSrcPort;
+ private int mDstPort;
+ private boolean mPassthrough;
+
+ private Builder() {
+ }
+
+ /**
+ * Sets source IP address.
+ */
+ @NonNull
+ public Builder setSrcIpAddress(byte[] srcIpAddress) {
+ mSrcIpAddress = srcIpAddress;
+ return this;
+ }
+ /**
+ * Sets destination IP address.
+ */
+ @NonNull
+ public Builder setDstIpAddress(byte[] dstIpAddress) {
+ mDstIpAddress = dstIpAddress;
+ return this;
+ }
+ /**
+ * Sets source port.
+ */
+ @NonNull
+ public Builder setSrcPort(int srcPort) {
+ mSrcPort = srcPort;
+ return this;
+ }
+ /**
+ * Sets destination port.
+ */
+ @NonNull
+ public Builder setDstPort(int dstPort) {
+ mDstPort = dstPort;
+ return this;
+ }
+ /**
+ * Sets passthrough.
+ */
+ @NonNull
+ public Builder setPassthrough(boolean passthrough) {
+ mPassthrough = passthrough;
+ return this;
+ }
+
+ /**
+ * Builds a {@link IpFilterConfiguration} object.
+ */
+ @NonNull
+ public IpFilterConfiguration build() {
+ return new IpFilterConfiguration(
+ mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
index 9045ce6..83246e5 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -16,19 +16,78 @@
package android.media.tv.tuner.filter;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+
/**
* Filter configuration for a MMTP filter.
* @hide
*/
public class MmtpFilterConfiguration extends FilterConfiguration {
- private int mMmtpPid;
+ private final int mMmtpPid;
- public MmtpFilterConfiguration(Settings settings) {
+ public MmtpFilterConfiguration(Settings settings, int mmtpPid) {
super(settings);
+ mMmtpPid = mmtpPid;
}
@Override
public int getType() {
return FilterConfiguration.FILTER_TYPE_MMTP;
}
+
+ /**
+ * Gets MMPT PID.
+ *
+ * <p>Packet ID is used to specify packets in MMTP.
+ */
+ public int getMmtpPid() {
+ return mMmtpPid;
+ }
+
+ /**
+ * Creates a builder for {@link IpFilterConfiguration}.
+ *
+ * @param context the context of the caller.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link IpFilterConfiguration}.
+ */
+ public static class Builder extends FilterConfiguration.Builder<Builder> {
+ private int mMmtpPid;
+
+ private Builder() {
+ }
+
+ /**
+ * Sets MMPT PID.
+ */
+ @NonNull
+ public Builder setMmtpPid(int mmtpPid) {
+ mMmtpPid = mmtpPid;
+ return this;
+ }
+
+ /**
+ * Builds a {@link IpFilterConfiguration} object.
+ */
+ @NonNull
+ public MmtpFilterConfiguration build() {
+ return new MmtpFilterConfiguration(mSettings, mMmtpPid);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index 701868a..4833709 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -16,18 +16,231 @@
package android.media.tv.tuner.filter;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerConstants;
+import android.media.tv.tuner.TunerConstants.ScIndexType;
import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* The Settings for the record in DVR.
* @hide
*/
public class RecordSettings extends Settings {
- private int mIndexType;
- private int mIndexMask;
+ /**
+ * Indexes can be tagged through TS (Transport Stream) header.
+ *
+ * @hide
+ */
+ @IntDef(flag = true,
+ prefix = "TS_INDEX_",
+ value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
+ TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
+ TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
+ TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR,
+ TS_INDEX_PCR_FLAG, TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG,
+ TS_INDEX_PRIVATE_DATA, TS_INDEX_ADAPTATION_EXTENSION_FLAG})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TsIndexMask {}
- public RecordSettings(int mainType) {
+ /**
+ * TS index FIRST_PACKET.
+ * @hide
+ */
+ public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
+ /**
+ * TS index PAYLOAD_UNIT_START_INDICATOR.
+ * @hide
+ */
+ public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR =
+ Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR;
+ /**
+ * TS index CHANGE_TO_NOT_SCRAMBLED.
+ * @hide
+ */
+ public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED =
+ Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED;
+ /**
+ * TS index CHANGE_TO_EVEN_SCRAMBLED.
+ * @hide
+ */
+ public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED =
+ Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED;
+ /**
+ * TS index CHANGE_TO_ODD_SCRAMBLED.
+ * @hide
+ */
+ public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED =
+ Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED;
+ /**
+ * TS index DISCONTINUITY_INDICATOR.
+ * @hide
+ */
+ public static final int TS_INDEX_DISCONTINUITY_INDICATOR =
+ Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR;
+ /**
+ * TS index RANDOM_ACCESS_INDICATOR.
+ * @hide
+ */
+ public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR =
+ Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR;
+ /**
+ * TS index PRIORITY_INDICATOR.
+ * @hide
+ */
+ public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR;
+ /**
+ * TS index PCR_FLAG.
+ * @hide
+ */
+ public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG;
+ /**
+ * TS index OPCR_FLAG.
+ * @hide
+ */
+ public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG;
+ /**
+ * TS index SPLICING_POINT_FLAG.
+ * @hide
+ */
+ public static final int TS_INDEX_SPLICING_POINT_FLAG =
+ Constants.DemuxTsIndex.SPLICING_POINT_FLAG;
+ /**
+ * TS index PRIVATE_DATA.
+ * @hide
+ */
+ public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA;
+ /**
+ * TS index ADAPTATION_EXTENSION_FLAG.
+ * @hide
+ */
+ public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
+ Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+ /**
+ * @hide
+ */
+ @IntDef(flag = true,
+ prefix = "SC_",
+ value = {
+ TunerConstants.SC_INDEX_I_FRAME,
+ TunerConstants.SC_INDEX_P_FRAME,
+ TunerConstants.SC_INDEX_B_FRAME,
+ TunerConstants.SC_INDEX_SEQUENCE,
+ TunerConstants.SC_HEVC_INDEX_SPS,
+ TunerConstants.SC_HEVC_INDEX_AUD,
+ TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
+ TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL,
+ TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP,
+ TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL,
+ TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP,
+ TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScIndexMask {}
+
+
+ private final int mTsIndexMask;
+ private final int mScIndexType;
+ private final int mScIndexMask;
+
+ private RecordSettings(int mainType, int tsIndexType, int scIndexType, int scIndexMask) {
super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD));
+ mTsIndexMask = tsIndexType;
+ mScIndexType = scIndexType;
+ mScIndexMask = scIndexMask;
}
+
+ /**
+ * Gets TS index mask.
+ */
+ @TsIndexMask
+ public int getTsIndexMask() {
+ return mTsIndexMask;
+ }
+ /**
+ * Gets Start Code index type.
+ */
+ @ScIndexType
+ public int getScIndexType() {
+ return mScIndexType;
+ }
+ /**
+ * Gets Start Code index mask.
+ */
+ @ScIndexMask
+ public int getScIndexMask() {
+ return mScIndexMask;
+ }
+
+ /**
+ * Creates a builder for {@link RecordSettings}.
+ *
+ * @param context the context of the caller.
+ * @param mainType the filter main type.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder(mainType);
+ }
+
+ /**
+ * Builder for {@link RecordSettings}.
+ */
+ public static class Builder extends Settings.Builder<Builder> {
+ private int mTsIndexMask;
+ private int mScIndexType;
+ private int mScIndexMask;
+
+ private Builder(int mainType) {
+ super(mainType);
+ }
+
+ /**
+ * Sets TS index mask.
+ */
+ @NonNull
+ public Builder setTsIndexMask(@TsIndexMask int indexMask) {
+ mTsIndexMask = indexMask;
+ return this;
+ }
+ /**
+ * Sets index type.
+ */
+ @NonNull
+ public Builder setScIndexType(@ScIndexType int indexType) {
+ mScIndexType = indexType;
+ return this;
+ }
+ /**
+ * Sets Start Code index mask.
+ */
+ @NonNull
+ public Builder setScIndexMask(@ScIndexMask int indexMask) {
+ mScIndexMask = indexMask;
+ return this;
+ }
+
+ /**
+ * Builds a {@link RecordSettings} object.
+ */
+ @NonNull
+ public RecordSettings build() {
+ return new RecordSettings(mMainType, mTsIndexMask, mScIndexType, mScIndexMask);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
+
}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
index 414ea67..0fa982e 100644
--- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
@@ -16,18 +16,116 @@
package android.media.tv.tuner.filter;
-import java.util.List;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
- * Bits Settings for Section Filter.
+ * Bits Settings for Section Filters.
* @hide
*/
public class SectionSettingsWithSectionBits extends SectionSettings {
- private List<Byte> mFilter;
- private List<Byte> mMask;
- private List<Byte> mMode;
+ private final byte[] mFilter;
+ private final byte[] mMask;
+ private final byte[] mMode;
- private SectionSettingsWithSectionBits(int mainType) {
+
+ private SectionSettingsWithSectionBits(int mainType, byte[] filter, byte[] mask, byte[] mode) {
super(mainType);
+ mFilter = filter;
+ mMask = mask;
+ mMode = mode;
+ }
+
+ /**
+ * Gets the bytes configured for Section Filter
+ */
+ public byte[] getFilterBytes() {
+ return mFilter;
+ }
+ /**
+ * Gets bit mask.
+ *
+ * <p>The bits in the bytes are used for filtering.
+ */
+ public byte[] getMask() {
+ return mMask;
+ }
+ /**
+ * Gets mode.
+ *
+ * <p>Do positive match at the bit position of the configured bytes when the bit at same
+ * position of the mode is 0.
+ * <p>Do negative match at the bit position of the configured bytes when the bit at same
+ * position of the mode is 1.
+ */
+ public byte[] getMode() {
+ return mMode;
+ }
+
+ /**
+ * Creates a builder for {@link SectionSettingsWithSectionBits}.
+ *
+ * @param context the context of the caller.
+ * @param mainType the filter main type.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder(mainType);
+ }
+
+ /**
+ * Builder for {@link SectionSettingsWithSectionBits}.
+ */
+ public static class Builder extends Settings.Builder<Builder> {
+ private byte[] mFilter;
+ private byte[] mMask;
+ private byte[] mMode;
+
+ private Builder(int mainType) {
+ super(mainType);
+ }
+
+ /**
+ * Sets filter bytes.
+ */
+ @NonNull
+ public Builder setFilter(byte[] filter) {
+ mFilter = filter;
+ return this;
+ }
+ /**
+ * Sets bit mask.
+ */
+ @NonNull
+ public Builder setMask(byte[] mask) {
+ mMask = mask;
+ return this;
+ }
+ /**
+ * Sets mode.
+ */
+ @NonNull
+ public Builder setMode(byte[] mode) {
+ mMode = mode;
+ return this;
+ }
+
+ /**
+ * Builds a {@link SectionSettingsWithSectionBits} object.
+ */
+ @NonNull
+ public SectionSettingsWithSectionBits build() {
+ return new SectionSettingsWithSectionBits(mMainType, mFilter, mMask, mMode);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
index 0df1d73..6542b89 100644
--- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
@@ -16,15 +16,92 @@
package android.media.tv.tuner.filter;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
+
/**
* Table information for Section Filter.
* @hide
*/
public class SectionSettingsWithTableInfo extends SectionSettings {
- private int mTableId;
- private int mVersion;
+ private final int mTableId;
+ private final int mVersion;
- private SectionSettingsWithTableInfo(int mainType) {
+ private SectionSettingsWithTableInfo(int mainType, int tableId, int version) {
super(mainType);
+ mTableId = tableId;
+ mVersion = version;
}
+
+ /**
+ * Gets table ID.
+ */
+ public int getTableId() {
+ return mTableId;
+ }
+ /**
+ * Gets version.
+ */
+ public int getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Creates a builder for {@link SectionSettingsWithTableInfo}.
+ *
+ * @param context the context of the caller.
+ * @param mainType the filter main type.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder(mainType);
+ }
+
+ /**
+ * Builder for {@link SectionSettingsWithTableInfo}.
+ */
+ public static class Builder extends Settings.Builder<Builder> {
+ private int mTableId;
+ private int mVersion;
+
+ private Builder(int mainType) {
+ super(mainType);
+ }
+
+ /**
+ * Sets table ID.
+ */
+ @NonNull
+ public Builder setTableId(int tableId) {
+ mTableId = tableId;
+ return this;
+ }
+ /**
+ * Sets version.
+ */
+ @NonNull
+ public Builder setVersion(int version) {
+ mVersion = version;
+ return this;
+ }
+
+ /**
+ * Builds a {@link SectionSettingsWithTableInfo} object.
+ */
+ @NonNull
+ public SectionSettingsWithTableInfo build() {
+ return new SectionSettingsWithTableInfo(mMainType, mTableId, mVersion);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
+
}
diff --git a/media/java/android/media/tv/tuner/filter/Settings.java b/media/java/android/media/tv/tuner/filter/Settings.java
index 9155926..d697280 100644
--- a/media/java/android/media/tv/tuner/filter/Settings.java
+++ b/media/java/android/media/tv/tuner/filter/Settings.java
@@ -39,4 +39,20 @@
public int getType() {
return mType;
}
+
+
+ /**
+ * Builder for {@link Settings}.
+ *
+ * @param <T> The subclass to be built.
+ * @hide
+ */
+ public abstract static class Builder<T extends Builder<T>> {
+ /* package */ final int mMainType;
+
+ /* package */ Builder(int mainType) {
+ mMainType = mainType;
+ }
+ /* package */ abstract T self();
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index de8ee75..eb97fc0 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -16,21 +16,118 @@
package android.media.tv.tuner.filter;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.media.tv.tuner.TunerUtils;
+
/**
* Filter configuration for a TLV filter.
* @hide
*/
public class TlvFilterConfiguration extends FilterConfiguration {
- private int mPacketType;
- private boolean mIsCompressedIpPacket;
- private boolean mPassthrough;
+ private final int mPacketType;
+ private final boolean mIsCompressedIpPacket;
+ private final boolean mPassthrough;
- public TlvFilterConfiguration(Settings settings) {
+ public TlvFilterConfiguration(Settings settings, int packetType, boolean isCompressed,
+ boolean passthrough) {
super(settings);
+ mPacketType = packetType;
+ mIsCompressedIpPacket = isCompressed;
+ mPassthrough = passthrough;
}
@Override
public int getType() {
return FilterConfiguration.FILTER_TYPE_TLV;
}
+
+ /**
+ * Gets packet type.
+ */
+ @FilterConfiguration.PacketType
+ public int getPacketType() {
+ return mPacketType;
+ }
+ /**
+ * Checks whether the data is compressed IP packet.
+ *
+ * @return {@code true} if the filtered data is compressed IP packet; {@code false} otherwise.
+ */
+ public boolean isCompressedIpPacket() {
+ return mIsCompressedIpPacket;
+ }
+ /**
+ * Checks whether it's passthrough.
+ *
+ * @return {@code true} if the data from TLV subtype go to next filter directly;
+ * {@code false} otherwise.
+ */
+ public boolean isPassthrough() {
+ return mPassthrough;
+ }
+
+ /**
+ * Creates a builder for {@link TlvFilterConfiguration}.
+ *
+ * @param context the context of the caller.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @NonNull
+ public static Builder builder(@NonNull Context context) {
+ TunerUtils.checkTunerPermission(context);
+ return new Builder();
+ }
+
+ /**
+ * Builder for {@link TlvFilterConfiguration}.
+ */
+ public static class Builder extends FilterConfiguration.Builder<Builder> {
+ private int mPacketType;
+ private boolean mIsCompressedIpPacket;
+ private boolean mPassthrough;
+
+ private Builder() {
+ }
+
+ /**
+ * Sets packet type.
+ */
+ @NonNull
+ public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+ mPacketType = packetType;
+ return this;
+ }
+ /**
+ * Sets whether the data is compressed IP packet.
+ */
+ @NonNull
+ public Builder setIsCompressedIpPacket(boolean isCompressedIpPacket) {
+ mIsCompressedIpPacket = isCompressedIpPacket;
+ return this;
+ }
+ /**
+ * Sets whether it's passthrough.
+ */
+ @NonNull
+ public Builder setPassthrough(boolean passthrough) {
+ mPassthrough = passthrough;
+ return this;
+ }
+
+ /**
+ * Builds a {@link TlvFilterConfiguration} object.
+ */
+ @NonNull
+ public TlvFilterConfiguration build() {
+ return new TlvFilterConfiguration(
+ mSettings, mPacketType, mIsCompressedIpPacket, mPassthrough);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
index fa4dd72..1b8485e 100644
--- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
@@ -16,12 +16,8 @@
package android.media.tv.tuner.filter;
-import android.annotation.IntDef;
import android.media.tv.tuner.Tuner.Filter;
-import android.media.tv.tuner.TunerConstants;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
/**
* Filter event sent from {@link Filter} objects for TS record data.
@@ -29,47 +25,17 @@
* @hide
*/
public class TsRecordEvent extends FilterEvent {
- /**
- * @hide
- */
- @IntDef(flag = true, value = {
- TunerConstants.TS_INDEX_FIRST_PACKET,
- TunerConstants.TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
- TunerConstants.TS_INDEX_CHANGE_TO_NOT_SCRAMBLED,
- TunerConstants.TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
- TunerConstants.TS_INDEX_CHANGE_TO_ODD_SCRAMBLED,
- TunerConstants.TS_INDEX_DISCONTINUITY_INDICATOR,
- TunerConstants.TS_INDEX_RANDOM_ACCESS_INDICATOR,
- TunerConstants.TS_INDEX_PRIORITY_INDICATOR,
- TunerConstants.TS_INDEX_PCR_FLAG,
- TunerConstants.TS_INDEX_OPCR_FLAG,
- TunerConstants.TS_INDEX_SPLICING_POINT_FLAG,
- TunerConstants.TS_INDEX_PRIVATE_DATA,
- TunerConstants.TS_INDEX_ADAPTATION_EXTENSION_FLAG,
- TunerConstants.SC_INDEX_I_FRAME,
- TunerConstants.SC_INDEX_P_FRAME,
- TunerConstants.SC_INDEX_B_FRAME,
- TunerConstants.SC_INDEX_SEQUENCE,
- TunerConstants.SC_HEVC_INDEX_SPS,
- TunerConstants.SC_HEVC_INDEX_AUD,
- TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
- TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL,
- TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP,
- TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL,
- TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP,
- TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface IndexMask {}
private final int mPid;
- private final int mIndexMask;
+ private final int mTsIndexMask;
+ private final int mScIndexMask;
private final long mByteNumber;
// This constructor is used by JNI code only
- private TsRecordEvent(int pid, int indexMask, long byteNumber) {
+ private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long byteNumber) {
mPid = pid;
- mIndexMask = indexMask;
+ mTsIndexMask = tsIndexMask;
+ mScIndexMask = scIndexMask;
mByteNumber = byteNumber;
}
@@ -81,13 +47,20 @@
}
/**
- * Gets index mask.
- *
- * <p>The index type is one of TS, SC, and SC-HEVC, and is set when configuring the filter.
+ * Gets TS index mask.
*/
- @IndexMask
- public int getIndexMask() {
- return mIndexMask;
+ @RecordSettings.TsIndexMask
+ public int getTsIndexMask() {
+ return mTsIndexMask;
+ }
+ /**
+ * Gets SC index mask.
+ *
+ * <p>The index type is SC or SC-HEVC, and is set when configuring the filter.
+ */
+ @RecordSettings.ScIndexMask
+ public int getScIndexMask() {
+ return mScIndexMask;
}
/**
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 41a9b24..5054281 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -49,7 +49,6 @@
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.TrafficStatsConstants;
@@ -207,7 +206,7 @@
if (TextUtils.isEmpty(url)) url = mCm.getCaptivePortalServerUrl();
final CarrierConfigManager configManager = getApplicationContext()
.getSystemService(CarrierConfigManager.class);
- final int subId = getIntent().getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ final int subId = getIntent().getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.getDefaultVoiceSubscriptionId());
final String[] portalURLs = configManager.getConfigForSubId(subId).getStringArray(
CarrierConfigManager.KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a58e3d7..65fc215 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -31,8 +31,8 @@
import static android.os.BatteryManager.EXTRA_PLUGGED;
import static android.os.BatteryManager.EXTRA_STATUS;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
+import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
-import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -92,7 +92,6 @@
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.WirelessUtils;
@@ -446,7 +445,7 @@
*/
public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
- if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+ if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
SubscriptionInfo info1 = subscriptions.get(0);
SubscriptionInfo info2 = subscriptions.get(1);
if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
@@ -1074,7 +1073,7 @@
mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
} else if (Intent.ACTION_SERVICE_STATE.equals(action)) {
ServiceState serviceState = ServiceState.newFromBundle(intent.getExtras());
- int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (DEBUG) {
Log.v(TAG, "action " + action + " serviceState=" + serviceState + " subId="
@@ -1236,8 +1235,8 @@
throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
}
String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
- int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
- int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+ int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
final String absentReason = intent
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
index 820c042..f7fe064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection
+import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_MIN
import android.service.notification.NotificationListenerService.Ranking
@@ -191,9 +192,9 @@
}
private fun NotificationEntry.isPeopleNotification() =
- sbn.isPeopleNotification()
- private fun StatusBarNotification.isPeopleNotification() =
- peopleNotificationIdentifier.isPeopleNotification(this)
+ sbn.isPeopleNotification(channel)
+ private fun StatusBarNotification.isPeopleNotification(channel: NotificationChannel) =
+ peopleNotificationIdentifier.isPeopleNotification(this, channel)
private fun NotificationEntry.isHighPriority() =
highPriorityProvider.isHighPriority(this)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
index 2c6a165..2eec68b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coalescer;
+import androidx.annotation.Nullable;
+
import java.util.ArrayList;
import java.util.List;
@@ -35,6 +37,8 @@
*/
final List<CoalescedEvent> mMembers = new ArrayList<>();
+ @Nullable Runnable mCancelShortTimeout;
+
EventBatch(long createdTimestamp, String groupKey) {
mCreatedTimestamp = createdTimestamp;
this.mGroupKey = groupKey;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
index 8076616..f589038 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.coalescer;
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.BATCH_MAX_TIMEOUT;
import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT;
import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT;
import static com.android.systemui.statusbar.notification.logging.NotifEvent.EMIT_EVENT_BATCH;
@@ -71,7 +72,8 @@
private final DelayableExecutor mMainExecutor;
private final SystemClock mClock;
private final NotifLog mLog;
- private final long mGroupLingerDuration;
+ private final long mMinGroupLingerDuration;
+ private final long mMaxGroupLingerDuration;
private BatchableNotificationHandler mHandler;
@@ -82,22 +84,28 @@
public GroupCoalescer(
@Main DelayableExecutor mainExecutor,
SystemClock clock, NotifLog log) {
- this(mainExecutor, clock, log, GROUP_LINGER_DURATION);
+ this(mainExecutor, clock, log, MIN_GROUP_LINGER_DURATION, MAX_GROUP_LINGER_DURATION);
}
/**
- * @param groupLingerDuration How long, in ms, that notifications that are members of a group
- * are delayed within the GroupCoalescer before being posted
+ * @param minGroupLingerDuration How long, in ms, to wait for another notification from the same
+ * group to arrive before emitting all pending events for that
+ * group. Each subsequent arrival of a group member resets the
+ * timer for that group.
+ * @param maxGroupLingerDuration The maximum time, in ms, that a group can linger in the
+ * coalescer before it's force-emitted.
*/
GroupCoalescer(
@Main DelayableExecutor mainExecutor,
SystemClock clock,
NotifLog log,
- long groupLingerDuration) {
+ long minGroupLingerDuration,
+ long maxGroupLingerDuration) {
mMainExecutor = mainExecutor;
mClock = clock;
mLog = log;
- mGroupLingerDuration = groupLingerDuration;
+ mMinGroupLingerDuration = minGroupLingerDuration;
+ mMaxGroupLingerDuration = maxGroupLingerDuration;
}
/**
@@ -115,7 +123,7 @@
private final NotificationHandler mListener = new NotificationHandler() {
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
- maybeEmitBatch(sbn.getKey());
+ maybeEmitBatch(sbn);
applyRanking(rankingMap);
final boolean shouldCoalesce = handleNotificationPosted(sbn, rankingMap);
@@ -130,7 +138,7 @@
@Override
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
- maybeEmitBatch(sbn.getKey());
+ maybeEmitBatch(sbn);
applyRanking(rankingMap);
mHandler.onNotificationRemoved(sbn, rankingMap);
}
@@ -140,7 +148,7 @@
StatusBarNotification sbn,
RankingMap rankingMap,
int reason) {
- maybeEmitBatch(sbn.getKey());
+ maybeEmitBatch(sbn);
applyRanking(rankingMap);
mHandler.onNotificationRemoved(sbn, rankingMap, reason);
}
@@ -152,13 +160,20 @@
}
};
- private void maybeEmitBatch(String memberKey) {
- CoalescedEvent event = mCoalescedEvents.get(memberKey);
+ private void maybeEmitBatch(StatusBarNotification sbn) {
+ final CoalescedEvent event = mCoalescedEvents.get(sbn.getKey());
+ final EventBatch batch = mBatches.get(sbn.getGroupKey());
if (event != null) {
mLog.log(EARLY_BATCH_EMIT,
String.format("Modification of %s triggered early emit of batched group %s",
- memberKey, requireNonNull(event.getBatch()).mGroupKey));
+ sbn.getKey(), requireNonNull(event.getBatch()).mGroupKey));
emitBatch(requireNonNull(event.getBatch()));
+ } else if (batch != null
+ && mClock.uptimeMillis() - batch.mCreatedTimestamp >= mMaxGroupLingerDuration) {
+ mLog.log(BATCH_MAX_TIMEOUT,
+ String.format("Modification of %s triggered timeout emit of batched group %s",
+ sbn.getKey(), batch.mGroupKey));
+ emitBatch(batch);
}
}
@@ -175,7 +190,8 @@
}
if (sbn.isGroup()) {
- EventBatch batch = startBatchingGroup(sbn.getGroupKey());
+ final EventBatch batch = getOrBuildBatch(sbn.getGroupKey());
+
CoalescedEvent event =
new CoalescedEvent(
sbn.getKey(),
@@ -183,10 +199,10 @@
sbn,
requireRanking(rankingMap, sbn.getKey()),
batch);
+ mCoalescedEvents.put(event.getKey(), event);
batch.mMembers.add(event);
-
- mCoalescedEvents.put(event.getKey(), event);
+ resetShortTimeout(batch);
return true;
} else {
@@ -194,27 +210,39 @@
}
}
- private EventBatch startBatchingGroup(final String groupKey) {
+ private EventBatch getOrBuildBatch(final String groupKey) {
EventBatch batch = mBatches.get(groupKey);
if (batch == null) {
- final EventBatch newBatch = new EventBatch(mClock.uptimeMillis(), groupKey);
- mBatches.put(groupKey, newBatch);
- mMainExecutor.executeDelayed(() -> emitBatch(newBatch), mGroupLingerDuration);
-
- batch = newBatch;
+ batch = new EventBatch(mClock.uptimeMillis(), groupKey);
+ mBatches.put(groupKey, batch);
}
return batch;
}
+ private void resetShortTimeout(EventBatch batch) {
+ if (batch.mCancelShortTimeout != null) {
+ batch.mCancelShortTimeout.run();
+ }
+ batch.mCancelShortTimeout =
+ mMainExecutor.executeDelayed(
+ () -> {
+ batch.mCancelShortTimeout = null;
+ emitBatch(batch);
+ },
+ mMinGroupLingerDuration);
+ }
+
private void emitBatch(EventBatch batch) {
if (batch != mBatches.get(batch.mGroupKey)) {
- // If we emit a batch early, we don't want to emit it a second time when its timeout
- // expires.
- return;
+ throw new IllegalStateException("Cannot emit out-of-date batch " + batch.mGroupKey);
}
if (batch.mMembers.isEmpty()) {
throw new IllegalStateException("Batch " + batch.mGroupKey + " cannot be empty");
}
+ if (batch.mCancelShortTimeout != null) {
+ batch.mCancelShortTimeout.run();
+ batch.mCancelShortTimeout = null;
+ }
mBatches.remove(batch.mGroupKey);
@@ -299,5 +327,6 @@
void onNotificationBatchPosted(List<CoalescedEvent> events);
}
- private static final int GROUP_LINGER_DURATION = 500;
+ private static final int MIN_GROUP_LINGER_DURATION = 50;
+ private static final int MAX_GROUP_LINGER_DURATION = 500;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index 3cc5e62..ccd7fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -99,7 +99,8 @@
}
private boolean isPeopleNotification(NotificationEntry entry) {
- return mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn());
+ return mPeopleNotificationIdentifier.isPeopleNotification(
+ entry.getSbn(), entry.getChannel());
}
private boolean hasUserSetImportance(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index 2374cde..9adceb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -156,7 +156,8 @@
// GroupCoalescer labels:
"CoalescedEvent",
"EarlyBatchEmit",
- "EmitEventBatch"
+ "EmitEventBatch",
+ "BatchMaxTimeout"
};
private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length;
@@ -206,5 +207,6 @@
public static final int COALESCED_EVENT = COALESCER_EVENT_START_INDEX;
public static final int EARLY_BATCH_EMIT = COALESCER_EVENT_START_INDEX + 1;
public static final int EMIT_EVENT_BATCH = COALESCER_EVENT_START_INDEX + 2;
+ public static final int BATCH_MAX_TIMEOUT = COALESCER_EVENT_START_INDEX + 3;
private static final int TOTAL_COALESCER_EVENT_TYPES = 3;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 452d1eb..5c90211 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -18,13 +18,14 @@
import android.app.Notification
import android.content.Context
+import android.app.NotificationChannel
import android.service.notification.StatusBarNotification
import android.util.FeatureFlagUtils
import javax.inject.Inject
import javax.inject.Singleton
interface PeopleNotificationIdentifier {
- fun isPeopleNotification(sbn: StatusBarNotification): Boolean
+ fun isPeopleNotification(sbn: StatusBarNotification, channel: NotificationChannel): Boolean
}
@Singleton
@@ -33,12 +34,13 @@
private val context: Context
) : PeopleNotificationIdentifier {
- override fun isPeopleNotification(sbn: StatusBarNotification) =
- (sbn.notification.notificationStyle == Notification.MessagingStyle::class.java &&
+ override fun isPeopleNotification(sbn: StatusBarNotification, channel: NotificationChannel) =
+ ((sbn.notification.notificationStyle == Notification.MessagingStyle::class.java &&
(sbn.notification.shortcutId != null ||
FeatureFlagUtils.isEnabled(
context,
FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ
))) ||
- personExtractor.isPersonNotification(sbn)
+ personExtractor.isPersonNotification(sbn)) &&
+ !channel.isDemoted
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index ec420f3..3b106cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -25,6 +25,7 @@
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_BUBBLE;
+import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_DEMOTE;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_FAVORITE;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_HOME;
import static com.android.systemui.statusbar.notification.row.NotificationConversationInfo.UpdateChannelRunnable.ACTION_MUTE;
@@ -61,6 +62,7 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Button;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -151,6 +153,11 @@
closeControls(v, true);
};
+ private OnClickListener mOnDemoteClick = v -> {
+ mSelectedAction = ACTION_DEMOTE;
+ closeControls(v, true);
+ };
+
public NotificationConversationInfo(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -295,6 +302,8 @@
mContext.getDrawable(R.drawable.ic_notifications_alert), null, null, null);
}
+ ImageButton demote = findViewById(R.id.demote);
+ demote.setOnClickListener(mOnDemoteClick);
}
private void bindHeader() {
@@ -609,7 +618,7 @@
}
break;
case ACTION_DEMOTE:
- // TODO: when demotion status field exists on notificationchannel
+ mChannelToUpdate.setDemoted(!mChannelToUpdate.isDemoted());
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index f05b585..cca100f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -26,6 +26,7 @@
import android.os.Looper;
import android.os.Message;
import android.provider.Settings.Global;
+import android.telephony.Annotation;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrengthCdma;
import android.telephony.NetworkRegistrationInfo;
@@ -37,7 +38,6 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
-import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.TelephonyIntents;
@@ -53,7 +53,9 @@
import java.io.PrintWriter;
import java.util.BitSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.regex.Matcher;
@@ -77,12 +79,14 @@
final SubscriptionInfo mSubscriptionInfo;
// @VisibleForDemoMode
- final SparseArray<MobileIconGroup> mNetworkToIconLookup;
+ final Map<String, MobileIconGroup> mNetworkToIconLookup;
// Since some pieces of the phone state are interdependent we store it locally,
// this could potentially become part of MobileState for simplification/complication
// of code.
private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ private boolean mCA = false;
+ private boolean mCAPlus = false;
private int mDataState = TelephonyManager.DATA_DISCONNECTED;
private ServiceState mServiceState;
private SignalStrength mSignalStrength;
@@ -93,9 +97,6 @@
boolean mInflateSignalStrengths = false;
@VisibleForTesting
boolean mIsShowingIconGracefully = false;
- // Some specific carriers have 5GE network which is special LTE CA network.
- private static final int NETWORK_TYPE_LTE_CA_5GE =
- TelephonyManager.getAllNetworkTypes().length + 1;
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
@@ -106,7 +107,7 @@
super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
networkController);
- mNetworkToIconLookup = new SparseArray<>();
+ mNetworkToIconLookup = new HashMap<>();
mConfig = config;
mPhone = phone;
mDefaults = defaults;
@@ -213,29 +214,38 @@
private void mapIconSets() {
mNetworkToIconLookup.clear();
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_TD_SCDMA, TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EVDO_0),
+ TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EVDO_A),
+ TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EVDO_B),
+ TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EHRPD),
+ TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_UMTS),
+ TelephonyIcons.THREE_G);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_TD_SCDMA),
+ TelephonyIcons.THREE_G);
if (!mConfig.showAtLeast3G) {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_UNKNOWN),
TelephonyIcons.UNKNOWN);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EDGE),
+ TelephonyIcons.E);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_CDMA),
+ TelephonyIcons.ONE_X);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_1xRTT),
+ TelephonyIcons.ONE_X);
mDefaultIcons = TelephonyIcons.G;
} else {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_UNKNOWN),
TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE,
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_EDGE),
TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA,
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_CDMA),
TelephonyIcons.THREE_G);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT,
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_1xRTT),
TelephonyIcons.THREE_G);
mDefaultIcons = TelephonyIcons.THREE_G;
}
@@ -250,33 +260,59 @@
hPlusGroup = TelephonyIcons.H_PLUS;
}
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hPlusGroup);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSDPA), hGroup);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSUPA), hGroup);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSPA), hGroup);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_HSPAP), hPlusGroup);
if (mConfig.show4gForLte) {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_LTE),
+ TelephonyIcons.FOUR_G);
if (mConfig.hideLtePlus) {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+ mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
TelephonyIcons.FOUR_G);
} else {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+ mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
TelephonyIcons.FOUR_G_PLUS);
}
} else {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_LTE),
+ TelephonyIcons.LTE);
if (mConfig.hideLtePlus) {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+ mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
TelephonyIcons.LTE);
} else {
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA,
+ mNetworkToIconLookup.put(toIconKeyCA(TelephonyManager.NETWORK_TYPE_LTE),
TelephonyIcons.LTE_PLUS);
}
}
- mNetworkToIconLookup.put(NETWORK_TYPE_LTE_CA_5GE,
+ mNetworkToIconLookup.put(toIconKeyCAPlus(TelephonyManager.NETWORK_TYPE_LTE),
TelephonyIcons.LTE_CA_5G_E);
- mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
+ mNetworkToIconLookup.put(toIconKey(TelephonyManager.NETWORK_TYPE_IWLAN),
+ TelephonyIcons.WFC);
+ }
+
+ private String getIconKey() {
+ if (mCA) {
+ return toIconKeyCA(mDataNetType);
+ } else if (mCAPlus) {
+ return toIconKeyCAPlus(mDataNetType);
+ } else {
+ return toIconKey(mDataNetType);
+ }
+ }
+
+ // Some specific carriers have 5GE network which is special CA network.
+ private String toIconKeyCAPlus(@Annotation.NetworkType int networkType) {
+ return toIconKeyCA(networkType) + "_Plus";
+ }
+
+ private String toIconKeyCA(@Annotation.NetworkType int networkType) {
+ return toIconKey(networkType) + "_CA";
+ }
+
+ private String toIconKey(@Annotation.NetworkType int networkType) {
+ return Integer.toString(networkType);
}
private void updateInflateSignalStrength() {
@@ -523,10 +559,11 @@
nr5GIconGroup = adjustNr5GIconGroupByDisplayGraceTime(nr5GIconGroup);
}
+ String iconKey = getIconKey();
if (nr5GIconGroup != null) {
mCurrentState.iconGroup = nr5GIconGroup;
- } else if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
- mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
+ } else if (mNetworkToIconLookup.get(iconKey) != null) {
+ mCurrentState.iconGroup = mNetworkToIconLookup.get(iconKey);
} else {
mCurrentState.iconGroup = mDefaultIcons;
}
@@ -679,6 +716,8 @@
pw.println(" mSignalStrength=" + mSignalStrength + ",");
pw.println(" mDataState=" + mDataState + ",");
pw.println(" mDataNetType=" + mDataNetType + ",");
+ pw.println(" mCA=" + mCA + ",");
+ pw.println(" mCAPlus=" + mCAPlus + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
pw.println(" mIsShowingIconGracefully=" + mIsShowingIconGracefully + ",");
@@ -729,11 +768,13 @@
private void updateDataNetType(int networkType) {
mDataNetType = networkType;
+ mCA = false;
+ mCAPlus = false;
if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) {
if (isCarrierSpecificDataIcon()) {
- mDataNetType = NETWORK_TYPE_LTE_CA_5GE;
+ mCAPlus = true;
} else if (mServiceState != null && mServiceState.isUsingCarrierAggregation()) {
- mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
+ mCA = true;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 679fa7e..6b3c5dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -22,8 +22,7 @@
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-
-import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
+import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -57,7 +56,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.DemoMode;
@@ -547,7 +545,7 @@
mReceiverHandler.post(this::handleConfigurationChanged);
break;
default:
- int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (SubscriptionManager.isValidSubscriptionId(subId)) {
if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
@@ -582,7 +580,7 @@
}
private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
- if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+ if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
SubscriptionInfo info1 = subscriptions.get(0);
SubscriptionInfo info2 = subscriptions.get(1);
if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 2e0fb3b..12da006 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -57,7 +57,6 @@
import android.testing.TestableContext;
import android.testing.TestableLooper;
-import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.DumpController;
import com.android.systemui.SysuiTestCase;
@@ -524,9 +523,9 @@
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
if (data != null) intent.putExtras(data);
- intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
- intent.putExtra("subscription", subscription);
- intent.putExtra("slot", 0/* SLOT 1 */);
+
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subscription);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
return intent;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index cc5514f..d852fa1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -571,7 +571,7 @@
}
private NotificationEntry createNotification() {
- Notification.Builder n = new Notification.Builder(mContext, "")
+ Notification.Builder n = new Notification.Builder(mContext, "id")
.setSmallIcon(R.drawable.ic_person)
.setContentTitle("Title")
.setContentText("Text");
@@ -582,6 +582,7 @@
.setUid(TEST_UID)
.setId(mId++)
.setNotification(n.build())
+ .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
.setUser(new UserHandle(ActivityManager.getCurrentUser()))
.build();
}
@@ -616,7 +617,7 @@
@Test
public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() {
Assert.sMainLooper = TestableLooper.get(this).getLooper();
- Notification.Builder n = new Notification.Builder(mContext, "")
+ Notification.Builder n = new Notification.Builder(mContext, "di")
.setSmallIcon(R.drawable.ic_person)
.setContentTitle("Title")
.setContentText("Text");
@@ -628,6 +629,7 @@
.setId(mId++)
.setNotification(n.build())
.setUser(new UserHandle(ActivityManager.getCurrentUser()))
+ .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT))
.build();
mEntryManager.addActiveNotificationForTest(mEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 93909dc..7c3665b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -60,7 +60,8 @@
final NotificationEntry entry = new NotificationEntryBuilder()
.setImportance(IMPORTANCE_HIGH)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+ .thenReturn(false);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -75,7 +76,8 @@
.setNotification(notification)
.setImportance(IMPORTANCE_LOW)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+ .thenReturn(true);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -90,7 +92,8 @@
final NotificationEntry entry = new NotificationEntryBuilder()
.setNotification(notification)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+ .thenReturn(false);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -106,7 +109,8 @@
.setNotification(notification)
.setImportance(IMPORTANCE_LOW)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+ .thenReturn(false);
// THEN it has high priority
assertTrue(mHighPriorityProvider.isHighPriority(entry));
@@ -122,7 +126,8 @@
.setNotification(notification)
.setImportance(IMPORTANCE_MIN)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(false);
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+ .thenReturn(false);
// THEN it does NOT have high priority
assertFalse(mHighPriorityProvider.isHighPriority(entry));
@@ -144,7 +149,8 @@
.setNotification(notification)
.setChannel(channel)
.build();
- when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn())).thenReturn(true);
+ when(mPeopleNotificationIdentifier.isPeopleNotification(entry.getSbn(), entry.getChannel()))
+ .thenReturn(true);
// THEN it does NOT have high priority
assertFalse(mHighPriorityProvider.isHighPriority(entry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index e273191..7ab4846 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection
import android.app.Notification
+import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_LOW
@@ -81,6 +82,7 @@
.setNotification(
Notification.Builder(mContext, "test")
.build())
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -94,6 +96,7 @@
.setNotification(
Notification.Builder(mContext, "test")
.build())
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -116,6 +119,7 @@
.setOpPkg("pkg")
.setTag("tag")
.setNotification(aN)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -130,6 +134,7 @@
.setOpPkg("pkg2")
.setTag("tag")
.setNotification(bN)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setUser(mContext.getUser())
.setOverrideGroupKey("")
.build()
@@ -149,6 +154,7 @@
.setTag("tag")
.setNotification(notif)
.setUser(mContext.user)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setOverrideGroupKey("")
.build()
@@ -168,6 +174,7 @@
.setTag("tag")
.setNotification(notif)
.setUser(mContext.user)
+ .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT))
.setOverrideGroupKey("")
.build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
index 5e0baf2..86c1eb97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
@@ -80,7 +80,8 @@
mExecutor,
mClock,
mLog,
- LINGER_DURATION);
+ MIN_LINGER_DURATION,
+ MAX_LINGER_DURATION);
mCoalescer.setNotificationHandler(mListener);
mCoalescer.attach(mListenerService);
@@ -96,7 +97,7 @@
new NotificationEntryBuilder()
.setId(0)
.setPkg(TEST_PACKAGE_A));
- mClock.advanceTime(LINGER_DURATION);
+ mClock.advanceTime(MIN_LINGER_DURATION);
// THEN the event is passed through to the handler
verify(mListener).onNotificationPosted(notif1.sbn, notif1.rankingMap);
@@ -144,12 +145,16 @@
.setId(1)
.setGroup(mContext, GROUP_1));
+ mClock.advanceTime(2);
+
NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
.setPkg(TEST_PACKAGE_A)
.setId(2)
.setGroup(mContext, GROUP_1)
.setGroupSummary(mContext, true));
+ mClock.advanceTime(3);
+
NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
.setPkg(TEST_PACKAGE_A)
.setId(3)
@@ -161,7 +166,7 @@
verify(mListener, never()).onNotificationBatchPosted(anyList());
// WHEN enough time passes
- mClock.advanceTime(LINGER_DURATION);
+ mClock.advanceTime(MIN_LINGER_DURATION);
// THEN the coalesced notifs are applied. The summary is sorted to the front.
verify(mListener).onNotificationBatchPosted(Arrays.asList(
@@ -212,7 +217,7 @@
// WHEN the time runs out on the remainder of the group
clearInvocations(mListener);
- mClock.advanceTime(LINGER_DURATION);
+ mClock.advanceTime(MIN_LINGER_DURATION);
// THEN no lingering batch is applied
verify(mListener, never()).onNotificationBatchPosted(anyList());
@@ -225,11 +230,13 @@
.setPkg(TEST_PACKAGE_A)
.setId(1)
.setGroup(mContext, GROUP_1));
+ mClock.advanceTime(2);
NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder()
.setPkg(TEST_PACKAGE_A)
.setId(2)
.setContentTitle(mContext, "Version 1")
.setGroup(mContext, GROUP_1));
+ mClock.advanceTime(4);
// WHEN one of them gets updated
NotifEvent notif2b = mNoMan.postNotif(new NotificationEntryBuilder()
@@ -248,7 +255,7 @@
any(RankingMap.class));
// THEN second, the update is emitted
- mClock.advanceTime(LINGER_DURATION);
+ mClock.advanceTime(MIN_LINGER_DURATION);
verify(mListener).onNotificationBatchPosted(Collections.singletonList(
new CoalescedEvent(notif2b.key, 0, notif2b.sbn, notif2b.ranking, null)
));
@@ -308,14 +315,61 @@
.setId(17));
// THEN they have the new rankings when they are eventually emitted
- mClock.advanceTime(LINGER_DURATION);
+ mClock.advanceTime(MIN_LINGER_DURATION);
verify(mListener).onNotificationBatchPosted(Arrays.asList(
new CoalescedEvent(notif1.key, 0, notif1.sbn, ranking1b, null),
new CoalescedEvent(notif2.key, 1, notif2.sbn, ranking2b, null)
));
}
- private static final long LINGER_DURATION = 4700;
+ @Test
+ public void testMaxLingerDuration() {
+ // GIVEN five coalesced notifications that have collectively taken 20ms to arrive, 2ms
+ // longer than the max linger duration
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1)
+ .setGroup(mContext, GROUP_1));
+ mClock.advanceTime(4);
+ NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(2)
+ .setGroup(mContext, GROUP_1));
+ mClock.advanceTime(4);
+ NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(3)
+ .setGroup(mContext, GROUP_1));
+ mClock.advanceTime(4);
+ NotifEvent notif4 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(4)
+ .setGroup(mContext, GROUP_1));
+ mClock.advanceTime(4);
+ NotifEvent notif5 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(5)
+ .setGroup(mContext, GROUP_1));
+ mClock.advanceTime(4);
+
+ // WHEN a sixth notification arrives
+ NotifEvent notif6 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(6)
+ .setGroup(mContext, GROUP_1));
+
+ // THEN the first five notifications are emitted in a batch
+ verify(mListener).onNotificationBatchPosted(Arrays.asList(
+ new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+ new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null),
+ new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null),
+ new CoalescedEvent(notif4.key, 3, notif4.sbn, notif4.ranking, null),
+ new CoalescedEvent(notif5.key, 4, notif5.sbn, notif5.ranking, null)
+ ));
+ }
+
+ private static final long MIN_LINGER_DURATION = 5;
+ private static final long MAX_LINGER_DURATION = 18;
private static final String TEST_PACKAGE_A = "com.test.package_a";
private static final String TEST_PACKAGE_B = "com.test.package_b";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 0bf458c..61f0b26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -62,6 +62,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
@@ -684,6 +685,34 @@
}
@Test
+ public void testDemote() throws Exception {
+ mNotificationInfo.bindNotification(
+ mShortcutManager,
+ mLauncherApps,
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ null,
+ null,
+ null,
+ true);
+
+
+ ImageButton demote = mNotificationInfo.findViewById(R.id.demote);
+ demote.performClick();
+ mTestableLooper.processAllMessages();
+
+ ArgumentCaptor<NotificationChannel> captor =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), anyInt(), captor.capture());
+ assertTrue(captor.getValue().isDemoted());
+ }
+
+ @Test
public void testMute_mute() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mConversationChannel.setImportance(IMPORTANCE_DEFAULT);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index dc393d1..e9db9c8 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
@@ -83,6 +85,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -459,8 +462,10 @@
Log.d(TAG, "[u" + userId + "] location enabled = " + isLocationEnabledForUser(userId));
}
- Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
- intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId));
+ Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId))
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
for (LocationProviderManager manager : mProviderManagers) {
@@ -929,9 +934,11 @@
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
mSettingsStore.setLocationProviderAllowed(mName, useable, userId);
- Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
- intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
- intent.putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable);
+ Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
+ .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
@@ -1396,20 +1403,19 @@
private String getResolutionPermission(int resolutionLevel) {
switch (resolutionLevel) {
case RESOLUTION_LEVEL_FINE:
- return android.Manifest.permission.ACCESS_FINE_LOCATION;
+ return ACCESS_FINE_LOCATION;
case RESOLUTION_LEVEL_COARSE:
- return android.Manifest.permission.ACCESS_COARSE_LOCATION;
+ return ACCESS_COARSE_LOCATION;
default:
return null;
}
}
private int getAllowedResolutionLevel(int pid, int uid) {
- if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
- pid, uid) == PERMISSION_GRANTED) {
+ if (mContext.checkPermission(ACCESS_FINE_LOCATION, pid, uid) == PERMISSION_GRANTED) {
return RESOLUTION_LEVEL_FINE;
- } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
- pid, uid) == PERMISSION_GRANTED) {
+ } else if (mContext.checkPermission(ACCESS_COARSE_LOCATION, pid, uid)
+ == PERMISSION_GRANTED) {
return RESOLUTION_LEVEL_COARSE;
} else {
return RESOLUTION_LEVEL_NONE;
@@ -1420,59 +1426,28 @@
return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
}
- private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
- if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
- throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
- }
+ private boolean checkCallingOrSelfLocationPermission() {
+ return mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
+ || mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PERMISSION_GRANTED;
}
- @GuardedBy("mLock")
- private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
- if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
- // gps and passive providers require FINE permission
- return RESOLUTION_LEVEL_FINE;
- } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
- // network and fused providers are ok with COARSE or FINE
- return RESOLUTION_LEVEL_COARSE;
- } else {
- for (LocationProviderManager lp : mProviderManagers) {
- if (!lp.getName().equals(provider)) {
- continue;
- }
-
- ProviderProperties properties = lp.getProperties();
- if (properties != null) {
- if (properties.mRequiresSatellite) {
- // provider requiring satellites require FINE permission
- return RESOLUTION_LEVEL_FINE;
- } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
- // provider requiring network and or cell require COARSE or FINE
- return RESOLUTION_LEVEL_COARSE;
- }
- }
- }
+ private void enforceCallingOrSelfLocationPermission() {
+ if (checkCallingOrSelfLocationPermission()) {
+ return;
}
- return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
+ throw new SecurityException("uid " + Binder.getCallingUid() + " does not have "
+ + ACCESS_COARSE_LOCATION + " or " + ACCESS_FINE_LOCATION + ".");
}
- @GuardedBy("mLock")
- private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
- String providerName) {
- int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
- if (allowedResolutionLevel < requiredResolutionLevel) {
- switch (requiredResolutionLevel) {
- case RESOLUTION_LEVEL_FINE:
- throw new SecurityException("\"" + providerName + "\" location provider " +
- "requires ACCESS_FINE_LOCATION permission.");
- case RESOLUTION_LEVEL_COARSE:
- throw new SecurityException("\"" + providerName + "\" location provider " +
- "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
- default:
- throw new SecurityException("Insufficient permission for \"" + providerName +
- "\" location provider.");
- }
+ private void enforceCallingOrSelfPackageName(String packageName) {
+ int uid = Binder.getCallingUid();
+ if (ArrayUtils.contains(mPackageManager.getPackagesForUid(uid), packageName)) {
+ return;
}
+
+ throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid);
}
public static int resolutionLevelToOp(int allowedResolutionLevel) {
@@ -1548,7 +1523,10 @@
*/
@Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
- int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+ if (!checkCallingOrSelfLocationPermission()) {
+ return Collections.emptyList();
+ }
+
synchronized (mLock) {
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
for (LocationProviderManager manager : mProviderManagers) {
@@ -1556,9 +1534,6 @@
if (FUSED_PROVIDER.equals(name)) {
continue;
}
- if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
- continue;
- }
if (enabledOnly && !manager.isUseable()) {
continue;
}
@@ -2002,33 +1977,18 @@
return sanitizedRequest;
}
- private void checkPackageName(String packageName) {
- if (packageName == null) {
- throw new SecurityException("invalid package name: " + null);
- }
- int uid = Binder.getCallingUid();
- String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages == null) {
- throw new SecurityException("invalid UID " + uid);
- }
- for (String pkg : packages) {
- if (packageName.equals(pkg)) return;
- }
- throw new SecurityException("invalid package name: " + packageName);
- }
-
@Override
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
PendingIntent intent, String packageName, String featureId,
String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
+ enforceCallingOrSelfLocationPermission();
+ enforceCallingOrSelfPackageName(packageName);
+
synchronized (mLock) {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
- checkPackageName(packageName);
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
- request.getProvider());
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
@@ -2135,7 +2095,7 @@
@Override
public void removeUpdates(ILocationListener listener, PendingIntent intent,
String packageName) {
- checkPackageName(packageName);
+ enforceCallingOrSelfPackageName(packageName);
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
@@ -2197,12 +2157,12 @@
@Override
public Location getLastLocation(LocationRequest r, String packageName, String featureId) {
+ enforceCallingOrSelfLocationPermission();
+ enforceCallingOrSelfPackageName(packageName);
+
synchronized (mLock) {
LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkPackageName(packageName);
- checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
- request.getProvider());
// no need to sanitize this request, as only the provider name is used
final int pid = Binder.getCallingPid();
@@ -2348,7 +2308,7 @@
public boolean injectLocation(Location location) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to inject location");
- mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
+ mContext.enforceCallingPermission(ACCESS_FINE_LOCATION,
"Access Fine Location permission not granted to inject Location");
synchronized (mLock) {
@@ -2374,17 +2334,14 @@
String packageName, String featureId, String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
+ mContext.enforceCallingOrSelfPermission(ACCESS_FINE_LOCATION, null);
+ enforceCallingOrSelfPackageName(packageName);
+
if (request == null) request = DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
if (intent == null) {
throw new IllegalArgumentException("invalid pending intent: " + null);
}
- checkPackageName(packageName);
- synchronized (mLock) {
- checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
- request.getProvider());
- }
// Require that caller can manage given document
boolean callerHasLocationHardwarePermission =
mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
@@ -2430,7 +2387,7 @@
if (intent == null) {
throw new IllegalArgumentException("invalid pending intent: " + null);
}
- checkPackageName(packageName);
+ enforceCallingOrSelfPackageName(packageName);
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
@@ -2517,36 +2474,30 @@
@Override
public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
- if (providerName == null) {
- // throw NullPointerException to remain compatible with previous implementation
- throw new NullPointerException();
- }
+ Objects.requireNonNull(providerName);
+ Objects.requireNonNull(command);
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null);
+ enforceCallingOrSelfLocationPermission();
- synchronized (mLock) {
- checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
- providerName);
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_STARTED,
+ LocationStatsEnums.API_SEND_EXTRA_COMMAND,
+ providerName);
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- LocationStatsEnums.API_SEND_EXTRA_COMMAND,
- providerName);
-
- LocationProviderManager manager = getLocationProviderManager(providerName);
- if (manager != null) {
- manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command,
- extras);
- }
-
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_ENDED,
- LocationStatsEnums.API_SEND_EXTRA_COMMAND,
- providerName);
-
- return true;
+ LocationProviderManager manager = getLocationProviderManager(providerName);
+ if (manager != null) {
+ manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command,
+ extras);
}
+
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_ENDED,
+ LocationStatsEnums.API_SEND_EXTRA_COMMAND,
+ providerName);
+
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 396b977..bcc3bdb 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -44,6 +44,7 @@
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
+import static com.android.server.storage.StorageUserConnection.REMOTE_TIMEOUT_SECONDS;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -1985,16 +1986,28 @@
Slog.i(TAG, "Mounting volume " + vol);
mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
@Override
- public boolean onVolumeChecking(FileDescriptor deviceFd, String path,
+ public boolean onVolumeChecking(FileDescriptor fd, String path,
String internalPath) {
vol.path = path;
vol.internalPath = internalPath;
+ ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
try {
- mStorageSessionController.onVolumeMount(deviceFd, vol);
+ mStorageSessionController.onVolumeMount(pfd, vol);
return true;
} catch (ExternalStorageServiceException e) {
- Slog.i(TAG, "Failed to mount volume " + vol, e);
+ Slog.e(TAG, "Failed to mount volume " + vol, e);
+
+ Slog.i(TAG, "Scheduling reset in one minute");
+ mHandler.removeMessages(H_RESET);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(H_RESET),
+ TimeUnit.SECONDS.toMillis(REMOTE_TIMEOUT_SECONDS * 2));
return false;
+ } finally {
+ try {
+ pfd.close();
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to close FUSE device fd", e);
+ }
}
}
});
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 37026fd..a98b83b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -402,7 +402,7 @@
}
public ParcelFileDescriptor getStatisticsStream() {
- mContext.enforceCallingPermission(
+ mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BATTERY_STATS, null);
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
diff --git a/services/core/java/com/android/server/integrity/model/IndexingFileConstants.java b/services/core/java/com/android/server/integrity/model/IndexingFileConstants.java
index d21febb..0c4052a 100644
--- a/services/core/java/com/android/server/integrity/model/IndexingFileConstants.java
+++ b/services/core/java/com/android/server/integrity/model/IndexingFileConstants.java
@@ -18,9 +18,9 @@
/** A helper class containing special indexing file constants. */
public final class IndexingFileConstants {
- // We empirically experimented with different block sizes and identified that 250 is in the
+ // We empirically experimented with different block sizes and identified that 50 is in the
// optimal range of efficient computation.
- public static final int INDEXING_BLOCK_SIZE = 250;
+ public static final int INDEXING_BLOCK_SIZE = 50;
public static final String START_INDEXING_KEY = "START_KEY";
public static final String END_INDEXING_KEY = "END_KEY";
diff --git a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
index 03392ab..87eee4e 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleIndexingController.java
@@ -28,9 +28,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.TreeSet;
import java.util.stream.Collectors;
/** Helper class to identify the necessary indexes that needs to be read. */
@@ -93,19 +93,28 @@
return keyToIndexMap;
}
- private RuleIndexRange searchIndexingKeysRangeContainingKey(
+ private static RuleIndexRange searchIndexingKeysRangeContainingKey(
LinkedHashMap<String, Integer> indexMap, String searchedKey) {
- TreeSet<String> keyTreeSet =
- indexMap.keySet().stream()
- .filter(key -> !key.matches(START_INDEXING_KEY) && !key.matches(
- END_INDEXING_KEY))
- .collect(Collectors.toCollection(TreeSet::new));
-
- String minIndex = keyTreeSet.floor(searchedKey);
- String maxIndex = keyTreeSet.higher(searchedKey);
-
+ List<String> keys = indexMap.keySet().stream().collect(Collectors.toList());
+ List<String> identifiedKeyRange =
+ searchKeysRangeContainingKey(keys, searchedKey, 0, keys.size() - 1);
return new RuleIndexRange(
- indexMap.get(minIndex == null ? START_INDEXING_KEY : minIndex),
- indexMap.get(maxIndex == null ? END_INDEXING_KEY : maxIndex));
+ indexMap.get(identifiedKeyRange.get(0)), indexMap.get(identifiedKeyRange.get(1)));
+ }
+
+ private static List<String> searchKeysRangeContainingKey(
+ List<String> sortedKeyList, String key, int startIndex, int endIndex) {
+ if (endIndex - startIndex == 1) {
+ return Arrays.asList(sortedKeyList.get(startIndex), sortedKeyList.get(endIndex));
+ }
+
+ int midKeyIndex = startIndex + ((endIndex - startIndex) / 2);
+ String midKey = sortedKeyList.get(midKeyIndex);
+
+ if (key.compareTo(midKey) >= 0) {
+ return searchKeysRangeContainingKey(sortedKeyList, key, midKeyIndex, endIndex);
+ } else {
+ return searchKeysRangeContainingKey(sortedKeyList, key, startIndex, midKeyIndex);
+ }
}
}
diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/StatsPullAtomService.java
index 03bada4..f78330e 100644
--- a/services/core/java/com/android/server/stats/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/StatsPullAtomService.java
@@ -1214,28 +1214,119 @@
// No op.
}
- private void registerDeviceCalculatedPowerUse() {
- // No op.
+ // TODO: move to top of file when all migrations are complete
+ private BatteryStatsHelper mBatteryStatsHelper = null;
+ private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000;
+ private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS;
+ private static final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
+
+ private BatteryStatsHelper getBatteryStatsHelper() {
+ if (mBatteryStatsHelper == null) {
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
+ mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ mBatteryStatsHelper.create((Bundle) null);
+ }
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
+ // Load BatteryStats and do all the calculations.
+ mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL);
+ // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
+ mBatteryStatsHelper.clearStats();
+ mBatteryStatsHelperTimestampMs = currentTime;
+ }
+ return mBatteryStatsHelper;
}
- private void pullDeviceCalculatedPowerUse() {
- // No op.
+ private long milliAmpHrsToNanoAmpSecs(double mAh) {
+ return (long) (mAh * MILLI_AMP_HR_TO_NANO_AMP_SECS + 0.5);
+ }
+
+ private void registerDeviceCalculatedPowerUse() {
+ int tagId = StatsLog.DEVICE_CALCULATED_POWER_USE;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullDeviceCalculatedPowerUse(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
+ }
+
+ private int pullDeviceCalculatedPowerUse(int atomTag, List<StatsEvent> pulledData) {
+ BatteryStatsHelper bsHelper = getBatteryStatsHelper();
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeLong(milliAmpHrsToNanoAmpSecs(bsHelper.getComputedPower()))
+ .build();
+ pulledData.add(e);
+ return StatsManager.PULL_SUCCESS;
}
private void registerDeviceCalculatedPowerBlameUid() {
- // No op.
+ int tagId = StatsLog.DEVICE_CALCULATED_POWER_BLAME_UID;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullDeviceCalculatedPowerBlameUid(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullDeviceCalculatedPowerBlameUid() {
- // No op.
+ private int pullDeviceCalculatedPowerBlameUid(int atomTag, List<StatsEvent> pulledData) {
+ final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
+ if (sippers == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ for (BatterySipper bs : sippers) {
+ if (bs.drainType != bs.drainType.APP) {
+ continue;
+ }
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(bs.uidObj.getUid())
+ .writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah))
+ .build();
+ pulledData.add(e);
+ }
+ return StatsManager.PULL_SUCCESS;
}
private void registerDeviceCalculatedPowerBlameOther() {
- // No op.
+ int tagId = StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullDeviceCalculatedPowerBlameOther(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullDeviceCalculatedPowerBlameOther() {
- // No op.
+ private int pullDeviceCalculatedPowerBlameOther(int atomTag, List<StatsEvent> pulledData) {
+ final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
+ if (sippers == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ for (BatterySipper bs : sippers) {
+ if (bs.drainType == bs.drainType.APP) {
+ continue; // This is a separate atom; see pullDeviceCalculatedPowerBlameUid().
+ }
+ if (bs.drainType == bs.drainType.USER) {
+ continue; // This is not supported. We purposefully calculate over USER_ALL.
+ }
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(bs.drainType.ordinal())
+ .writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah))
+ .build();
+ pulledData.add(e);
+ }
+ return StatsManager.PULL_SUCCESS;
}
private void registerDebugElapsedClock() {
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index f4fb93a..baef5d6 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -40,9 +40,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-import java.io.FileDescriptor;
import java.util.Objects;
/**
@@ -82,7 +80,7 @@
* @throws ExternalStorageServiceException if the session fails to start
* @throws IllegalStateException if a session has already been created for {@code vol}
*/
- public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol)
+ public void onVolumeMount(ParcelFileDescriptor deviceFd, VolumeInfo vol)
throws ExternalStorageServiceException {
if (!shouldHandle(vol)) {
return;
@@ -102,8 +100,8 @@
mConnections.put(userId, connection);
}
Slog.i(TAG, "Creating and starting session with id: " + sessionId);
- connection.startSession(sessionId, new ParcelFileDescriptor(deviceFd),
- vol.getPath().getPath(), vol.getInternalPath().getPath());
+ connection.startSession(sessionId, deviceFd, vol.getPath().getPath(),
+ vol.getInternalPath().getPath());
}
}
@@ -185,7 +183,7 @@
* This call removes all sessions for the user that is being stopped;
* this will make sure that we don't rebind to the service needlessly.
*/
- public void onUserStopping(int userId) throws ExternalStorageServiceException {
+ public void onUserStopping(int userId) {
if (!shouldHandle(null)) {
return;
}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index c02ded8..dd18f4e 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -60,7 +60,8 @@
*/
public final class StorageUserConnection {
private static final String TAG = "StorageUserConnection";
- private static final int REMOTE_TIMEOUT_SECONDS = 15;
+
+ public static final int REMOTE_TIMEOUT_SECONDS = 5;
private final Object mLock = new Object();
private final Context mContext;
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index e0a7b18..2cb7d5a 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -33,6 +33,27 @@
private final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
private final WindowManagerService mWmService;
+ /**
+ * The following constants represent priority of the window. SF uses this information when
+ * deciding which window has a priority when deciding about the refresh rate of the screen.
+ * Priority 0 is considered the highest priority. -1 means that the priority is unset.
+ */
+ static final int LAYER_PRIORITY_UNSET = -1;
+ /** Windows that are in focus and voted for the preferred mode ID have the highest priority. */
+ static final int LAYER_PRIORITY_FOCUSED_WITH_MODE = 0;
+ /**
+ * This is a default priority for all windows that are in focus, but have not requested a
+ * specific mode ID.
+ */
+ static final int LAYER_PRIORITY_FOCUSED_WITHOUT_MODE = 1;
+ /**
+ * Windows that are not in focus, but voted for a specific mode ID should be
+ * acknowledged by SF. For example, there are two applications in a split screen.
+ * One voted for a given mode ID, and the second one doesn't care. Even though the
+ * second one might be in focus, we can honor the mode ID of the first one.
+ */
+ static final int LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE = 2;
+
RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo,
HighRefreshRateBlacklist blacklist) {
mLowRefreshRateId = findLowRefreshRateModeId(displayInfo);
@@ -92,4 +113,28 @@
}
return 0;
}
+
+ /**
+ * Calculate the priority based on whether the window is in focus and whether the application
+ * voted for a specific refresh rate.
+ *
+ * TODO(b/144307188): This is a very basic algorithm version. Explore other signals that might
+ * be useful in edge cases when we are deciding which layer should get priority when deciding
+ * about the refresh rate.
+ */
+ int calculatePriority(WindowState w) {
+ boolean isFocused = w.isFocused();
+ int preferredModeId = getPreferredModeId(w);
+
+ if (!isFocused && preferredModeId > 0) {
+ return LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE;
+ }
+ if (isFocused && preferredModeId == 0) {
+ return LAYER_PRIORITY_FOCUSED_WITHOUT_MODE;
+ }
+ if (isFocused && preferredModeId > 0) {
+ return LAYER_PRIORITY_FOCUSED_WITH_MODE;
+ }
+ return LAYER_PRIORITY_UNSET;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c2eb0e4..36e9273 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -657,6 +657,13 @@
private KeyInterceptionInfo mKeyInterceptionInfo;
/**
+ * This information is passed to SurfaceFlinger to decide which window should have a priority
+ * when deciding about the refresh rate of the display. All windows have the lowest priority by
+ * default. The variable is cached, so we do not send too many updates to SF.
+ */
+ int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET;
+
+ /**
* @return The insets state as requested by the client, i.e. the dispatched insets state
* for which the visibilities are overridden with what the client requested.
*/
@@ -5165,6 +5172,24 @@
}
}
+
+ /**
+ * Notifies SF about the priority of the window, if it changed. SF then uses this information
+ * to decide which window's desired rendering rate should have a priority when deciding about
+ * the refresh rate of the screen. Priority
+ * {@link RefreshRatePolicy#LAYER_PRIORITY_FOCUSED_WITH_MODE} is considered the highest.
+ */
+ @VisibleForTesting
+ void updateFrameRateSelectionPriorityIfNeeded() {
+ final int priority = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy()
+ .calculatePriority(this);
+ if (mFrameRateSelectionPriority != priority) {
+ mFrameRateSelectionPriority = priority;
+ getPendingTransaction().setFrameRateSelectionPriority(mSurfaceControl,
+ mFrameRateSelectionPriority);
+ }
+ }
+
@Override
void prepareSurfaces() {
final Dimmer dimmer = getDimmer();
@@ -5173,6 +5198,8 @@
applyDims(dimmer);
}
updateSurfacePosition();
+ // Send information to SufaceFlinger about the priority of the current window.
+ updateFrameRateSelectionPriorityIfNeeded();
mWinAnimator.prepareSurfaceLocked(true);
super.prepareSurfaces();
diff --git a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
index 47c7e56..a1810b9 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/IntegrityFileManagerTest.java
@@ -16,6 +16,8 @@
package com.android.server.integrity;
+import static com.android.server.integrity.model.IndexingFileConstants.INDEXING_BLOCK_SIZE;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.integrity.AppInstallMetadata;
@@ -159,13 +161,14 @@
// Create a rule set with 2500 package name indexed, 2500 app certificate indexed and
// 500 unindexed rules.
List<Rule> rules = new ArrayList<>();
+ int unindexedRuleCount = 70;
for (int i = 0; i < 2500; i++) {
rules.add(getPackageNameIndexedRule(String.format("%s%04d", packageName, i)));
rules.add(getAppCertificateIndexedRule(String.format("%s%04d", appCertificate, i)));
}
- for (int i = 0; i < 70; i++) {
+ for (int i = 0; i < unindexedRuleCount; i++) {
rules.add(getInstallerCertificateRule(String.format("%s%04d", installerName, i)));
}
@@ -187,7 +190,8 @@
List<Rule> rulesFetched = mIntegrityFileManager.readRules(appInstallMetadata);
// Verify that we do not load all the rules and we have the necessary rules to evaluate.
- assertThat(rulesFetched.size()).isEqualTo(270);
+ assertThat(rulesFetched.size())
+ .isEqualTo(INDEXING_BLOCK_SIZE * 2 + unindexedRuleCount);
assertThat(rulesFetched)
.containsAllOf(
getPackageNameIndexedRule(installedPackageName),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 7ac45f0..6f16574 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -227,6 +227,7 @@
assertEquals(expected.getLightColor(), actual.getLightColor());
assertEquals(expected.getParentChannelId(), actual.getParentChannelId());
assertEquals(expected.getConversationId(), actual.getConversationId());
+ assertEquals(expected.isDemoted(), actual.isDemoted());
}
private void compareChannelsParentChild(NotificationChannel parent,
@@ -355,6 +356,7 @@
channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
channel2.setLightColor(Color.BLUE);
channel2.setConversationId("id1", "conversation");
+ channel2.setDemoted(true);
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
new file mode 100644
index 0000000..032edde
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This file tests WM setting the priority on windows that is used in SF to determine at what
+ * frame rate the Display should run. Any changes to the algorithm should be reflected in these
+ * tests.
+ *
+ * Build/Install/Run: atest FrameRateSelectionPriority
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class FrameRateSelectionPriorityTests extends WindowTestsBase {
+
+ @Test
+ public void basicTest() {
+ final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+ assertNotNull("Window state is created", appWindow);
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority doesn't change.
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ // Call the function a few times.
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+
+ // Since nothing changed in the priority state, the transaction should not be updating.
+ verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+ }
+
+ @Test
+ public void testApplicationInFocusWithoutModeId() {
+ final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+ assertEquals(appWindow.getDisplayContent().getDisplayPolicy().getRefreshRatePolicy()
+ .getPreferredModeId(appWindow), 0);
+
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority stays MAX_VALUE.
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+ verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ // Application is in focus.
+ appWindow.mToken.mDisplayContent.mCurrentFocus = appWindow;
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority changes to 1.
+ assertEquals(appWindow.mFrameRateSelectionPriority, 1);
+ verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), 1);
+ }
+
+ @Test
+ public void testApplicationInFocusWithModeId() {
+ final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ // Application is in focus.
+ appWindow.mToken.mDisplayContent.mCurrentFocus = appWindow;
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority changes.
+ assertEquals(appWindow.mFrameRateSelectionPriority, 1);
+ // Update the mode ID to a requested number.
+ appWindow.mAttrs.preferredDisplayModeId = 1;
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority changes.
+ assertEquals(appWindow.mFrameRateSelectionPriority, 0);
+
+ // Remove the mode ID request.
+ appWindow.mAttrs.preferredDisplayModeId = 0;
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority changes.
+ assertEquals(appWindow.mFrameRateSelectionPriority, 1);
+
+ // Verify we called actions on Transactions correctly.
+ verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+ verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), 0);
+ verify(appWindow.getPendingTransaction(), times(2)).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), 1);
+ }
+
+ @Test
+ public void testApplicationNotInFocusWithModeId() {
+ final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus");
+ appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow;
+
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // The window is not in focus.
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ // Update the mode ID to a requested number.
+ appWindow.mAttrs.preferredDisplayModeId = 1;
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority changes.
+ assertEquals(appWindow.mFrameRateSelectionPriority, 2);
+
+ verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+ verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), 2);
+ }
+
+ @Test
+ public void testApplicationNotInFocusWithoutModeId() {
+ final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus");
+ appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow;
+
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // The window is not in focus.
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ // Make sure that the mode ID is not set.
+ appWindow.mAttrs.preferredDisplayModeId = 0;
+ appWindow.updateFrameRateSelectionPriorityIfNeeded();
+ // Priority doesn't change.
+ assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+
+ verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
+ appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index f5d08dc..eda1fb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -250,4 +250,9 @@
return this;
}
+ @Override
+ public SurfaceControl.Transaction setFrameRateSelectionPriority(SurfaceControl sc,
+ int priority) {
+ return this;
+ }
}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java b/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java
new file mode 100644
index 0000000..a532548
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usage;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.pm.PackageStats;
+
+/**
+ * StorageStatsManager local system service interface.
+ *
+ * Only for use within the system server.
+ */
+public abstract class StorageStatsManagerInternal {
+ /**
+ * Class used to augment {@link PackageStats} with the data stored by the system on
+ * behalf of apps in system specific directories
+ * ({@link android.os.Environment#getDataSystemDirectory},
+ * {@link android.os.Environment#getDataSystemCeDirectory}, etc).
+ */
+ public interface StorageStatsAugmenter {
+ void augmentStatsForPackage(@NonNull PackageStats stats,
+ @NonNull String packageName, @UserIdInt int userId,
+ @NonNull String callingPackage);
+ void augmentStatsForUid(@NonNull PackageStats stats, int uid,
+ @NonNull String callingPackage);
+ void augmentStatsForUser(@NonNull PackageStats stats, @UserIdInt int userId,
+ @NonNull String callingPackage);
+ }
+
+ /**
+ * Register a {@link StorageStatsAugmenter}.
+ *
+ * @param augmenter the {@link StorageStatsAugmenter} object to be registered.
+ * @param tag the identifier to be used for debugging in logs/trace.
+ */
+ public abstract void registerStorageStatsAugmenter(@NonNull StorageStatsAugmenter augmenter,
+ @NonNull String tag);
+}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 531a931..18b640f 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.ArrayUtils.defeatNullable;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.usage.StorageStatsManagerInternal.StorageStatsAugmenter;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -46,6 +47,7 @@
import android.os.ParcelableException;
import android.os.StatFs;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.CrateInfo;
@@ -58,6 +60,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.DataUnit;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseLongArray;
@@ -77,6 +80,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
public class StorageStatsService extends IStorageStatsManager.Stub {
private static final String TAG = "StorageStatsService";
@@ -111,6 +116,9 @@
private final Installer mInstaller;
private final H mHandler;
+ private final CopyOnWriteArrayList<Pair<String, StorageStatsAugmenter>>
+ mStorageStatsAugmenters = new CopyOnWriteArrayList<>();
+
public StorageStatsService(Context context) {
mContext = Preconditions.checkNotNull(context);
mAppOps = Preconditions.checkNotNull(context.getSystemService(AppOpsManager.class));
@@ -139,6 +147,8 @@
}
}
});
+
+ LocalServices.addService(StorageStatsManagerInternal.class, new LocalService());
}
private void invalidateMounts() {
@@ -300,6 +310,12 @@
} catch (InstallerException e) {
throw new ParcelableException(new IOException(e.getMessage()));
}
+ if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+ forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
+ storageStatsAugmenter.augmentStatsForPackage(stats,
+ packageName, userId, callingPackage);
+ }, "queryStatsForPackage");
+ }
return translate(stats);
}
}
@@ -353,6 +369,12 @@
} catch (InstallerException e) {
throw new ParcelableException(new IOException(e.getMessage()));
}
+
+ if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+ forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
+ storageStatsAugmenter.augmentStatsForUid(stats, uid, callingPackage);
+ }, "queryStatsForUid");
+ }
return translate(stats);
}
@@ -379,6 +401,12 @@
} catch (InstallerException e) {
throw new ParcelableException(new IOException(e.getMessage()));
}
+
+ if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+ forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
+ storageStatsAugmenter.augmentStatsForUser(stats, userId, callingPackage);
+ }, "queryStatsForUser");
+ }
return translate(stats);
}
@@ -705,4 +733,29 @@
throw new ParcelableException(new IOException(e.getMessage()));
}
}
+
+ void forEachStorageStatsAugmenter(@NonNull Consumer<StorageStatsAugmenter> consumer,
+ @NonNull String queryTag) {
+ for (int i = 0, count = mStorageStatsAugmenters.size(); i < count; ++i) {
+ final Pair<String, StorageStatsAugmenter> pair = mStorageStatsAugmenters.get(i);
+ final String augmenterTag = pair.first;
+ final StorageStatsAugmenter storageStatsAugmenter = pair.second;
+
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, queryTag + ":" + augmenterTag);
+ try {
+ consumer.accept(storageStatsAugmenter);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+ }
+ }
+
+ private class LocalService extends StorageStatsManagerInternal {
+ @Override
+ public void registerStorageStatsAugmenter(
+ @NonNull StorageStatsAugmenter storageStatsAugmenter,
+ @NonNull String tag) {
+ mStorageStatsAugmenters.add(Pair.create(tag, storageStatsAugmenter));
+ }
+ }
}
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index f6ce0dc..b8b203d 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -592,7 +592,7 @@
private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) {
SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
Context.TELEPHONY_SUBSCRIPTION_SERVICE);
- int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
+ int[] activeSubIds = sm.getActiveAndHiddenSubscriptionIdList();
for (int activeSubId : activeSubIds) {
if (getCarrierPrivilegeStatus(context, activeSubId, uid)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
diff --git a/telephony/framework-telephony-jarjar-rules.txt b/telephony/framework-telephony-jarjar-rules.txt
new file mode 100644
index 0000000..7cab806
--- /dev/null
+++ b/telephony/framework-telephony-jarjar-rules.txt
@@ -0,0 +1,4 @@
+rule android.telephony.Annotation* android.telephony.framework.Annotation@1
+rule com.android.i18n.phonenumbers.** com.android.telephony.framework.phonenumbers.@1
+#TODO: add jarjar rules for statically linked util classes
+
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 8ed4ee5..fee6d3f 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -25,11 +25,12 @@
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.ActivityThread;
import android.app.PendingIntent;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.database.CursorWindow;
import android.net.Uri;
import android.os.Build;
@@ -423,7 +424,7 @@
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/, ActivityThread.currentPackageName());
+ true /* persistMessage*/, null);
}
/**
@@ -633,7 +634,7 @@
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- false /* persistMessage */, ActivityThread.currentPackageName());
+ false /* persistMessage */, null);
}
private void sendTextMessageInternal(
@@ -676,7 +677,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendTextForSubscriberWithOptions(subId,
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress,
text, sentIntent, deliveryIntent, persistMessage, finalPriority,
expectMore, finalValidity);
@@ -698,7 +699,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendTextForSubscriberWithOptions(getSubscriptionId(),
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress,
text, sentIntent, deliveryIntent, persistMessage, finalPriority,
expectMore, finalValidity);
@@ -920,7 +921,7 @@
String destinationAddress, String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName());
+ deliveryIntents, true /* persistMessage*/, null);
}
/**
@@ -937,8 +938,9 @@
* subscription.
* </p>
*
- * @param packageName serves as the default package name if
- * {@link ActivityThread#currentPackageName()} is null.
+ * @param packageName serves as the default package name if the package name that is
+ * associated with the user id is null.
+ *
* @hide
*/
@SystemApi
@@ -948,9 +950,7 @@
@NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents,
@Nullable List<PendingIntent> deliveryIntents, @NonNull String packageName) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/,
- ActivityThread.currentPackageName() == null
- ? packageName : ActivityThread.currentPackageName());
+ deliveryIntents, true /* persistMessage*/, packageName);
}
private void sendMultipartTextMessageInternal(
@@ -1051,7 +1051,7 @@
String destinationAddress, String scAddress, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName());
+ deliveryIntents, false /* persistMessage*/, null);
}
/**
@@ -1213,7 +1213,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendMultipartTextForSubscriberWithOptions(subId,
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress, parts, sentIntents, deliveryIntents,
persistMessage, finalPriority, expectMore, finalValidity);
}
@@ -1235,7 +1235,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress, parts, sentIntents, deliveryIntents,
persistMessage, finalPriority, expectMore, finalValidity);
}
@@ -1366,7 +1366,7 @@
public void onSuccess(int subId) {
try {
ISms iSms = getISmsServiceOrThrow();
- iSms.sendDataForSubscriber(subId, ActivityThread.currentPackageName(),
+ iSms.sendDataForSubscriber(subId, null,
destinationAddress, scAddress, destinationPort & 0xFFFF, data,
sentIntent, deliveryIntent);
} catch (RemoteException e) {
@@ -1492,7 +1492,6 @@
private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) {
int subId = getSubscriptionId();
boolean isSmsSimPickActivityNeeded = false;
- final Context context = ActivityThread.currentApplication().getApplicationContext();
try {
ISms iSms = getISmsService();
if (iSms != null) {
@@ -1514,14 +1513,14 @@
return;
}
// We need to ask the user pick an appropriate subid for the operation.
- Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for package "
- + context.getPackageName());
+ Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for calling"
+ + " package. ");
try {
// Create the SMS pick activity and call back once the activity is complete. Can't do
// it here because we do not have access to the activity context that is performing this
// operation.
// Requires that the calling process has the SEND_SMS permission.
- getITelephony().enqueueSmsPickResult(context.getOpPackageName(),
+ getITelephony().enqueueSmsPickResult(null,
new IIntegerConsumer.Stub() {
@Override
public void accept(int subId) {
@@ -1539,6 +1538,13 @@
}
}
+ /**
+ * To check the SDK version for SmsManager.sendResolverResult method.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
+ private static final long GET_TARGET_SDK_VERSION_CODE_CHANGE = 145147528L;
+
private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId,
boolean pickActivityShown) {
if (SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -1546,7 +1552,8 @@
return;
}
- if (getTargetSdkVersion() <= Build.VERSION_CODES.P && !pickActivityShown) {
+ if (!Compatibility.isChangeEnabled(GET_TARGET_SDK_VERSION_CODE_CHANGE)
+ && !pickActivityShown) {
// Do not fail, return a success with an INVALID subid for apps targeting P or below
// that tried to perform an operation and the SMS disambiguation dialog was never shown,
// as these applications may not have been written to handle the failure case properly.
@@ -1559,19 +1566,6 @@
}
}
- private static int getTargetSdkVersion() {
- final Context context = ActivityThread.currentApplication().getApplicationContext();
- int targetSdk;
- try {
- targetSdk = context.getPackageManager().getApplicationInfo(
- context.getOpPackageName(), 0).targetSdkVersion;
- } catch (PackageManager.NameNotFoundException e) {
- // Default to old behavior if we can not find this.
- targetSdk = -1;
- }
- return targetSdk;
- }
-
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
TelephonyFrameworkInitializer
@@ -1657,7 +1651,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
+ null,
status, pdu, smsc);
}
} catch (RemoteException ex) {
@@ -1698,7 +1692,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
+ null,
messageIndex, STATUS_ON_ICC_FREE, null /* pdu */);
}
} catch (RemoteException ex) {
@@ -1741,7 +1735,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
+ null,
messageIndex, newStatus, pdu);
}
} catch (RemoteException ex) {
@@ -1793,7 +1787,7 @@
if (iSms != null) {
records = iSms.getAllMessagesFromIccEfForSubscriber(
getSubscriptionId(),
- ActivityThread.currentPackageName());
+ null);
}
} catch (RemoteException ex) {
// ignore it
@@ -2617,7 +2611,7 @@
try {
ISms iccSms = getISmsServiceOrThrow();
return iccSms.createAppSpecificSmsToken(getSubscriptionId(),
- ActivityThread.currentPackageName(), intent);
+ null, intent);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
@@ -2737,7 +2731,7 @@
try {
ISms iccSms = getISmsServiceOrThrow();
return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
- ActivityThread.currentPackageName(), prefixes, intent);
+ null, prefixes, intent);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
@@ -2828,7 +2822,7 @@
ISms iccISms = getISmsServiceOrThrow();
if (iccISms != null) {
return iccISms.checkSmsShortCodeDestination(getSubscriptionId(),
- ActivityThread.currentPackageName(), null, destAddress, countryIso);
+ null, null, destAddress, countryIso);
}
} catch (RemoteException e) {
Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e);
@@ -2864,7 +2858,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
smsc = iSms.getSmscAddressFromIccEfForSubscriber(
- getSubscriptionId(), ActivityThread.currentPackageName());
+ getSubscriptionId(), null);
}
} catch (RemoteException ex) {
// ignore it
@@ -2898,7 +2892,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
return iSms.setSmscAddressOnIccEfForSubscriber(
- smsc, getSubscriptionId(), ActivityThread.currentPackageName());
+ smsc, getSubscriptionId(), null);
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 36f541f..b42ce35 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2232,6 +2232,7 @@
} else {
logd("putPhoneIdAndSubIdExtra: no valid subs");
intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
+ intent.putExtra(EXTRA_SLOT_INDEX, phoneId);
}
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 13aad7e..56ca8c7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -37,7 +37,6 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
-import android.app.ActivityThread;
import android.app.PendingIntent;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
@@ -380,8 +379,17 @@
// effort and get the context from the current activity thread.
if (mContext != null) {
return mContext.getOpPackageName();
+ } else {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return null;
+ try {
+ return telephony.getCurrentPackageName();
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ return null;
+ }
}
- return ActivityThread.currentOpPackageName();
}
private String getFeatureId() {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index cdb95a8..a8e76b9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2087,6 +2087,11 @@
int getRadioHalVersion();
/**
+ * Get the current calling package name.
+ */
+ String getCurrentPackageName();
+
+ /**
* Returns true if the specified type of application (e.g. {@link #APPTYPE_CSIM} is present
* on the UICC card.
* @hide
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 58e232c..cbce8a5 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -59,10 +59,22 @@
dst[i] = 0;
}
+static bool cmp_style_ids(ResourceId a, ResourceId b) {
+ // If one of a and b is from the framework package (package ID 0x01), and the
+ // other is a dynamic ID (package ID 0x00), then put the dynamic ID after the
+ // framework ID. This ensures that when AssetManager resolves the dynamic IDs,
+ // they will be in sorted order as expected by AssetManager.
+ if ((a.package_id() == kFrameworkPackageId && b.package_id() == 0x00) ||
+ (a.package_id() == 0x00 && b.package_id() == kFrameworkPackageId)) {
+ return b < a;
+ }
+ return a < b;
+}
+
static bool cmp_style_entries(const Style::Entry& a, const Style::Entry& b) {
if (a.key.id) {
if (b.key.id) {
- return a.key.id.value() < b.key.id.value();
+ return cmp_style_ids(a.key.id.value(), b.key.id.value());
}
return true;
} else if (!b.key.id) {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 8fbdd7f..af2293f 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -431,6 +431,47 @@
EXPECT_EQ("lib", iter->second);
}
+TEST_F(TableFlattenerTest, FlattenSharedLibraryWithStyle) {
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder().SetCompilationPackage("lib").SetPackageId(0x00).Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("lib", 0x00)
+ .AddValue("lib:style/Theme",
+ ResourceId(0x00030001),
+ test::StyleBuilder()
+ .AddItem("lib:attr/bar", ResourceId(0x00010002),
+ ResourceUtils::TryParseInt("2"))
+ .AddItem("lib:attr/foo", ResourceId(0x00010001),
+ ResourceUtils::TryParseInt("1"))
+ .AddItem("android:attr/bar", ResourceId(0x01010002),
+ ResourceUtils::TryParseInt("4"))
+ .AddItem("android:attr/foo", ResourceId(0x01010001),
+ ResourceUtils::TryParseInt("3"))
+ .Build())
+ .Build();
+ ResourceTable result;
+ ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result));
+
+ Maybe<ResourceTable::SearchResult> search_result =
+ result.FindResource(test::ParseNameOrDie("lib:style/Theme"));
+ ASSERT_TRUE(search_result);
+ EXPECT_EQ(0x00u, search_result.value().package->id.value());
+ EXPECT_EQ(0x03u, search_result.value().type->id.value());
+ EXPECT_EQ(0x01u, search_result.value().entry->id.value());
+ ASSERT_EQ(1u, search_result.value().entry->values.size());
+ Value* value = search_result.value().entry->values[0]->value.get();
+ Style* style = ValueCast<Style>(value);
+ ASSERT_TRUE(style);
+ ASSERT_EQ(4u, style->entries.size());
+ // Ensure the attributes from the shared library come after the items from
+ // android.
+ EXPECT_EQ(0x01010001, style->entries[0].key.id.value());
+ EXPECT_EQ(0x01010002, style->entries[1].key.id.value());
+ EXPECT_EQ(0x00010001, style->entries[2].key.id.value());
+ EXPECT_EQ(0x00010002, style->entries[3].key.id.value());
+}
+
TEST_F(TableFlattenerTest, FlattenTableReferencingSharedLibraries) {
std::unique_ptr<IAaptContext> context =
test::ContextBuilder().SetCompilationPackage("app").SetPackageId(0x7f).Build();
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 99a26dc..3c55237 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -53,36 +53,38 @@
val executor = newThreadPool()
- command.javaSourceArgs.map { path ->
- executor.submitCallable {
- val transformer = SourceTransformer(command.protoLogImplClassNameArg,
- command.protoLogCacheClassNameArg, processor)
- val file = File(path)
- val text = injector.readText(file)
- val outSrc = try {
- val code = tryParse(text, path)
- if (containsProtoLogText(text, command.protoLogClassNameArg)) {
- transformer.processClass(text, path, packagePath(file, code), code)
- } else {
+ try {
+ command.javaSourceArgs.map { path ->
+ executor.submitCallable {
+ val transformer = SourceTransformer(command.protoLogImplClassNameArg,
+ command.protoLogCacheClassNameArg, processor)
+ val file = File(path)
+ val text = injector.readText(file)
+ val outSrc = try {
+ val code = tryParse(text, path)
+ if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+ transformer.processClass(text, path, packagePath(file, code), code)
+ } else {
+ text
+ }
+ } catch (ex: ParsingException) {
+ // If we cannot parse this file, skip it (and log why). Compilation will
+ // fail in a subsequent build step.
+ injector.reportParseError(ex)
text
}
- } catch (ex: ParsingException) {
- // If we cannot parse this file, skip it (and log why). Compilation will fail
- // in a subsequent build step.
- injector.reportParseError(ex)
- text
+ path to outSrc
}
- path to outSrc
+ }.map { future ->
+ val (path, outSrc) = future.get()
+ outJar.putNextEntry(ZipEntry(path))
+ outJar.write(outSrc.toByteArray())
+ outJar.closeEntry()
}
- }.map { future ->
- val (path, outSrc) = future.get()
- outJar.putNextEntry(ZipEntry(path))
- outJar.write(outSrc.toByteArray())
- outJar.closeEntry()
+ } finally {
+ executor.shutdown()
}
- executor.shutdown()
-
val cacheSplit = command.protoLogCacheClassNameArg.split(".")
val cacheName = cacheSplit.last()
val cachePackage = cacheSplit.dropLast(1).joinToString(".")
@@ -153,30 +155,32 @@
val executor = newThreadPool()
- command.javaSourceArgs.map { path ->
- executor.submitCallable {
- val file = File(path)
- val text = injector.readText(file)
- if (containsProtoLogText(text, command.protoLogClassNameArg)) {
- try {
- val code = tryParse(text, path)
- builder.findLogCalls(code, path, packagePath(file, code))
- } catch (ex: ParsingException) {
- // If we cannot parse this file, skip it (and log why). Compilation will fail
- // in a subsequent build step.
- injector.reportParseError(ex)
+ try {
+ command.javaSourceArgs.map { path ->
+ executor.submitCallable {
+ val file = File(path)
+ val text = injector.readText(file)
+ if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+ try {
+ val code = tryParse(text, path)
+ builder.findLogCalls(code, path, packagePath(file, code))
+ } catch (ex: ParsingException) {
+ // If we cannot parse this file, skip it (and log why). Compilation will
+ // fail in a subsequent build step.
+ injector.reportParseError(ex)
+ null
+ }
+ } else {
null
}
- } else {
- null
}
+ }.forEach { future ->
+ builder.addLogCalls(future.get() ?: return@forEach)
}
- }.forEach { future ->
- builder.addLogCalls(future.get() ?: return@forEach)
+ } finally {
+ executor.shutdown()
}
- executor.shutdown()
-
val out = injector.fileOutputStream(command.viewerConfigJsonArg)
out.write(builder.build().toByteArray())
out.close()
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 70c9bef..4c9ee85 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -70,6 +70,7 @@
"framework-annotations-lib",
"unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
"unsupportedappusage-annotation", // for dalvik.annotation.compat.UnsupportedAppUsage
+ "framework-telephony-stubs",
],
srcs: [
":framework-wifi-updatable-sources",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index f490766..67f1663 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -92,6 +92,8 @@
void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
+ void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable);
+
boolean startScan(String packageName, String featureId);
List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a9621fc..b2fbb40 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -856,18 +856,6 @@
/**
* @hide
- * For debug: date at which the config was last updated
- */
- public String updateTime;
-
- /**
- * @hide
- * For debug: date at which the config was last updated
- */
- public String creationTime;
-
- /**
- * @hide
* The WiFi configuration is considered to have no internet access for purpose of autojoining
* if there has been a report of it having no internet access, and, it never have had
* internet access in the past.
@@ -1493,12 +1481,6 @@
private String mConnectChoice;
/**
- * The system timestamp when we records the connectChoice. This value is obtained from
- * System.currentTimeMillis
- */
- private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
-
- /**
* Used to cache the temporary candidate during the network selection procedure. It will be
* kept updating once a new scan result has a higher score than current one
*/
@@ -1601,25 +1583,6 @@
mConnectChoice = newConnectChoice;
}
- /**
- * get the timeStamp when user select a choice over this configuration
- * @return returns when current connectChoice is set (time from System.currentTimeMillis)
- * @hide
- */
- public long getConnectChoiceTimestamp() {
- return mConnectChoiceTimestamp;
- }
-
- /**
- * set the timeStamp when user select a choice over this configuration
- * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
- * be obtained from System.currentTimeMillis
- * @hide
- */
- public void setConnectChoiceTimestamp(long timeStamp) {
- mConnectChoiceTimestamp = timeStamp;
- }
-
/** Get the current Quality network selection status as a String (for debugging). */
@NonNull
public String getNetworkStatusString() {
@@ -1902,7 +1865,6 @@
setCandidate(source.getCandidate());
setCandidateScore(source.getCandidateScore());
setConnectChoice(source.getConnectChoice());
- setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
setHasEverConnected(source.getHasEverConnected());
}
@@ -1919,7 +1881,6 @@
if (getConnectChoice() != null) {
dest.writeInt(CONNECT_CHOICE_EXISTS);
dest.writeString(getConnectChoice());
- dest.writeLong(getConnectChoiceTimestamp());
} else {
dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
}
@@ -1938,10 +1899,8 @@
setNetworkSelectionBSSID(in.readString());
if (in.readInt() == CONNECT_CHOICE_EXISTS) {
setConnectChoice(in.readString());
- setConnectChoiceTimestamp(in.readLong());
} else {
setConnectChoice(null);
- setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
}
setHasEverConnected(in.readInt() != 0);
}
@@ -2165,9 +2124,6 @@
}
if (mNetworkSelectionStatus.getConnectChoice() != null) {
sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
- sbuf.append(" connect choice set time: ")
- .append(logTimeOfDay(
- mNetworkSelectionStatus.getConnectChoiceTimestamp()));
}
sbuf.append(" hasEverConnected: ")
.append(mNetworkSelectionStatus.getHasEverConnected()).append("\n");
@@ -2179,12 +2135,6 @@
sbuf.append(" numNoInternetAccessReports ");
sbuf.append(this.numNoInternetAccessReports).append("\n");
}
- if (this.updateTime != null) {
- sbuf.append(" update ").append(this.updateTime).append("\n");
- }
- if (this.creationTime != null) {
- sbuf.append(" creation ").append(this.creationTime).append("\n");
- }
if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
if (this.ephemeral) sbuf.append(" ephemeral");
if (this.osu) sbuf.append(" osu");
@@ -2731,8 +2681,6 @@
allowAutojoin = source.allowAutojoin;
numNoInternetAccessReports = source.numNoInternetAccessReports;
noInternetAccessExpected = source.noInternetAccessExpected;
- creationTime = source.creationTime;
- updateTime = source.updateTime;
shared = source.shared;
recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
mRandomizedMacAddress = source.mRandomizedMacAddress;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9540103..ec3de43 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4243,6 +4243,24 @@
}
/**
+ * Configure MAC randomization setting for a Passpoint profile.
+ * MAC randomization is enabled by default.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param enable true to enable MAC randomization, false to disable MAC randomization.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
+ try {
+ mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Disable an ephemeral network.
*
* @param ssid in the format of WifiConfiguration's SSID.
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index c0e0890..2fba5a3 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -122,6 +122,12 @@
* Whether the setCredentialSharedWithUser have been called.
*/
private boolean mIsSharedWithUserSet;
+
+ /**
+ * Whether this network is initialized with auto-join enabled (the default) or not.
+ */
+ private boolean mIsInitialAutoJoinEnabled;
+
/**
* Pre-shared key for use with WAPI-PSK networks.
*/
@@ -148,6 +154,7 @@
mIsMetered = false;
mIsSharedWithUser = true;
mIsSharedWithUserSet = false;
+ mIsInitialAutoJoinEnabled = true;
mPriority = UNASSIGNED_PRIORITY;
mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
mWapiPskPassphrase = null;
@@ -440,6 +447,27 @@
return this;
}
+ /**
+ * Specifies whether the suggestion is created with auto-join enabled or disabled. The
+ * user may modify the auto-join configuration of a suggestion directly once the device
+ * associates to the network.
+ * <p>
+ * If auto-join is initialized as disabled the user may still be able to manually connect
+ * to the network. Therefore, disabling auto-join only makes sense if
+ * {@link #setCredentialSharedWithUser(boolean)} is set to true (the default) which
+ * itself implies a secure (non-open) network.
+ * <p>
+ * If not set, defaults to true (i.e. auto-join is initialized as enabled).
+ *
+ * @param enabled true for initializing with auto-join enabled (the default), false to
+ * initializing with auto-join disabled.
+ * @return Instance of (@link {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setIsInitialAutoJoinEnabled(boolean enabled) {
+ mIsInitialAutoJoinEnabled = enabled;
+ return this;
+ }
+
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
@@ -587,7 +615,6 @@
+ "suggestion with Passpoint configuration");
}
wifiConfiguration = buildWifiConfigurationForPasspoint();
-
} else {
if (mSsid == null) {
throw new IllegalStateException("setSsid should be invoked for suggestion");
@@ -608,6 +635,12 @@
}
mIsSharedWithUser = false;
}
+
+ if (!mIsSharedWithUser && !mIsInitialAutoJoinEnabled) {
+ throw new IllegalStateException("Should have not a network with both "
+ + "setIsUserAllowedToManuallyConnect and "
+ + "setIsAutoJoinEnabled set to false");
+ }
}
return new WifiNetworkSuggestion(
@@ -615,7 +648,8 @@
mPasspointConfiguration,
mIsAppInteractionRequired,
mIsUserInteractionRequired,
- mIsSharedWithUser);
+ mIsSharedWithUser,
+ mIsInitialAutoJoinEnabled);
}
}
@@ -642,6 +676,7 @@
* @hide
*/
public final boolean isUserInteractionRequired;
+
/**
* Whether app share credential with the user, allow user use provided credential to
* connect network manually.
@@ -649,6 +684,12 @@
*/
public final boolean isUserAllowedToManuallyConnect;
+ /**
+ * Whether the suggestion will be initialized as auto-joined or not.
+ * @hide
+ */
+ public final boolean isInitialAutoJoinEnabled;
+
/** @hide */
public WifiNetworkSuggestion() {
this.wifiConfiguration = null;
@@ -656,6 +697,7 @@
this.isAppInteractionRequired = false;
this.isUserInteractionRequired = false;
this.isUserAllowedToManuallyConnect = true;
+ this.isInitialAutoJoinEnabled = true;
}
/** @hide */
@@ -663,7 +705,8 @@
@Nullable PasspointConfiguration passpointConfiguration,
boolean isAppInteractionRequired,
boolean isUserInteractionRequired,
- boolean isUserAllowedToManuallyConnect) {
+ boolean isUserAllowedToManuallyConnect,
+ boolean isInitialAutoJoinEnabled) {
checkNotNull(networkConfiguration);
this.wifiConfiguration = networkConfiguration;
this.passpointConfiguration = passpointConfiguration;
@@ -671,6 +714,7 @@
this.isAppInteractionRequired = isAppInteractionRequired;
this.isUserInteractionRequired = isUserInteractionRequired;
this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
+ this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
}
public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -682,7 +726,8 @@
in.readParcelable(null), // PasspointConfiguration
in.readBoolean(), // isAppInteractionRequired
in.readBoolean(), // isUserInteractionRequired
- in.readBoolean() // isSharedCredentialWithUser
+ in.readBoolean(), // isSharedCredentialWithUser
+ in.readBoolean() // isAutoJoinEnabled
);
}
@@ -704,6 +749,7 @@
dest.writeBoolean(isAppInteractionRequired);
dest.writeBoolean(isUserInteractionRequired);
dest.writeBoolean(isUserAllowedToManuallyConnect);
+ dest.writeBoolean(isInitialAutoJoinEnabled);
}
@Override
@@ -744,6 +790,7 @@
.append(", isAppInteractionRequired=").append(isAppInteractionRequired)
.append(", isUserInteractionRequired=").append(isUserInteractionRequired)
.append(", isUserAllowedToManuallyConnect=").append(isUserAllowedToManuallyConnect)
+ .append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
.append(" ]");
return sb.toString();
}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 1822e84..7c335fc 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -431,6 +431,13 @@
private boolean mIsAutoJoinEnabled = true;
/**
+ * The mac randomization setting specifies whether a randomized or device MAC address will
+ * be used to connect to the passpoint network. If true, a randomized MAC will be used.
+ * Otherwise, the device MAC address will be used.
+ */
+ private boolean mIsMacRandomizationEnabled = true;
+
+ /**
* Configures the auto-association status of this Passpoint configuration. A value of true
* indicates that the configuration will be considered for auto-connection, a value of false
* indicates that only manual connection will work - the framework will not auto-associate to
@@ -444,6 +451,18 @@
}
/**
+ * Configures the MAC randomization setting for this Passpoint configuration.
+ * If set to true, the framework will use a randomized MAC address to connect to this Passpoint
+ * network. Otherwise, the framework will use the device MAC address.
+ *
+ * @param enabled true to use randomized MAC address, false to use device MAC address.
+ * @hide
+ */
+ public void setMacRandomizationEnabled(boolean enabled) {
+ mIsMacRandomizationEnabled = enabled;
+ }
+
+ /**
* Indicates whether the Passpoint configuration may be auto-connected to by the framework. A
* value of true indicates that auto-connection can happen, a value of false indicates that it
* cannot. However, even when auto-connection is not possible manual connection by the user is
@@ -459,6 +478,19 @@
}
/**
+ * Indicates whether a randomized MAC address or device MAC address will be used for
+ * connections to this Passpoint network. If true, a randomized MAC address will be used.
+ * Otherwise, the device MAC address will be used.
+ *
+ * @return true for MAC randomization enabled. False for disabled.
+ * @hide
+ */
+ @SystemApi
+ public boolean isMacRandomizationEnabled() {
+ return mIsMacRandomizationEnabled;
+ }
+
+ /**
* Constructor for creating PasspointConfiguration with default values.
*/
public PasspointConfiguration() {}
@@ -501,6 +533,7 @@
mAaaServerTrustedNames = source.mAaaServerTrustedNames;
mCarrierId = source.mCarrierId;
mIsAutoJoinEnabled = source.mIsAutoJoinEnabled;
+ mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
}
@Override
@@ -531,6 +564,7 @@
dest.writeBundle(bundle);
dest.writeInt(mCarrierId);
dest.writeBoolean(mIsAutoJoinEnabled);
+ dest.writeBoolean(mIsMacRandomizationEnabled);
}
@Override
@@ -562,6 +596,7 @@
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
&& mCarrierId == that.mCarrierId
&& mIsAutoJoinEnabled == that.mIsAutoJoinEnabled
+ && mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
&& (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
: mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
}
@@ -572,7 +607,7 @@
mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
- mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled);
+ mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled, mIsMacRandomizationEnabled);
}
@Override
@@ -627,6 +662,7 @@
}
builder.append("CarrierId:" + mCarrierId);
builder.append("IsAutoJoinEnabled:" + mIsAutoJoinEnabled);
+ builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
return builder.toString();
}
@@ -733,6 +769,7 @@
config.setServiceFriendlyNames(friendlyNamesMap);
config.mCarrierId = in.readInt();
config.mIsAutoJoinEnabled = in.readBoolean();
+ config.mIsMacRandomizationEnabled = in.readBoolean();
return config;
}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 3c13562d..1cf3825 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -187,6 +187,11 @@
}
@Override
+ public void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean startScan(String packageName, String featureId) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 5bdc344..983ac82 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1706,6 +1706,17 @@
verify(mWifiService).allowAutojoinPasspoint(fqdn, true);
}
+ /**
+ * Test behavior of
+ * {@link WifiManager#setMacRandomizationSettingPasspointEnabled(String, boolean)}
+ */
+ @Test
+ public void testSetMacRandomizationSettingPasspointEnabled() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, true);
+ verify(mWifiService).setMacRandomizationSettingPasspointEnabled(fqdn, true);
+ }
+
/**
* Test behavior of {@link WifiManager#disconnect()}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index ac91544..cb1b774 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -32,8 +32,6 @@
*/
@SmallTest
public class WifiNetworkSuggestionTest {
- private static final int TEST_UID = 45677;
- private static final int TEST_UID_OTHER = 45673;
private static final String TEST_SSID = "\"Test123\"";
private static final String TEST_BSSID = "12:12:12:12:12:12";
private static final String TEST_SSID_1 = "\"Test1234\"";
@@ -61,7 +59,8 @@
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
- assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -90,7 +89,8 @@
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(0, suggestion.wifiConfiguration.priority);
- assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -105,6 +105,7 @@
.setSsid(TEST_SSID)
.setWpa2Passphrase(TEST_PRESHARED_KEY)
.setIsUserInteractionRequired(true)
+ .setIsInitialAutoJoinEnabled(false)
.setIsMetered(true)
.build();
@@ -119,6 +120,7 @@
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -140,6 +142,7 @@
assertNull(suggestion.wifiConfiguration.preSharedKey);
assertTrue(suggestion.wifiConfiguration.requirePMF);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -152,6 +155,7 @@
.setSsid(TEST_SSID)
.setWpa3Passphrase(TEST_PRESHARED_KEY)
.setCredentialSharedWithUser(true)
+ .setIsInitialAutoJoinEnabled(false)
.build();
assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -161,6 +165,7 @@
suggestion.wifiConfiguration.preSharedKey);
assertTrue(suggestion.wifiConfiguration.requirePMF);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isInitialAutoJoinEnabled);
}
@@ -191,6 +196,7 @@
// allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
// here.
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -526,7 +532,7 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
- configuration, null, false, true, true);
+ configuration, null, false, true, true, false);
Parcel parcelW = Parcel.obtain();
suggestion.writeToParcel(parcelW, 0);
@@ -548,6 +554,8 @@
parcelSuggestion.isAppInteractionRequired);
assertEquals(suggestion.isUserInteractionRequired,
parcelSuggestion.isUserInteractionRequired);
+ assertEquals(suggestion.isInitialAutoJoinEnabled,
+ parcelSuggestion.isInitialAutoJoinEnabled);
}
/**
@@ -580,6 +588,8 @@
parcelSuggestion.isAppInteractionRequired);
assertEquals(suggestion.isUserInteractionRequired,
parcelSuggestion.isUserInteractionRequired);
+ assertEquals(suggestion.isInitialAutoJoinEnabled,
+ parcelSuggestion.isInitialAutoJoinEnabled);
}
/**
@@ -593,14 +603,14 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, true, false, true);
+ new WifiNetworkSuggestion(configuration, null, true, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.BSSID = TEST_BSSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, true, true, false);
assertEquals(suggestion, suggestion1);
assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -616,13 +626,13 @@
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, false);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID_1;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, false);
assertNotEquals(suggestion, suggestion1);
}
@@ -638,13 +648,13 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
assertNotEquals(suggestion, suggestion1);
}
@@ -659,13 +669,13 @@
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
assertNotEquals(suggestion, suggestion1);
}
@@ -714,9 +724,38 @@
*/
@Test(expected = IllegalStateException.class)
public void testSetIsUserAllowedToManuallyConnectToWithOpenNetwork() {
- WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ new WifiNetworkSuggestion.Builder()
.setSsid(TEST_SSID)
.setCredentialSharedWithUser(true)
.build();
}
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when {@link WifiNetworkSuggestion.Builder#setIsInitialAutoJoinEnabled(boolean)} to
+ * false on a open network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsAutoJoinDisabledWithOpenNetwork() {
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsInitialAutoJoinEnabled(false)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when set both {@link WifiNetworkSuggestion.Builder#setIsInitialAutoJoinEnabled(boolean)}
+ * and {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} (boolean)}
+ * to false on a network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsAutoJoinDisabledWithSecureNetworkNotSharedWithUser() {
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setCredentialSharedWithUser(false)
+ .setIsInitialAutoJoinEnabled(false)
+ .build();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 94054fd..603e78b 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -172,6 +172,7 @@
assertFalse(config.validate());
assertFalse(config.validateForR2());
assertTrue(config.isAutoJoinEnabled());
+ assertTrue(config.isMacRandomizationEnabled());
}
/**