Merge "API review changes to CallDiagnosticService" into sc-dev
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 29bcfe0..1bd90a8 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_arm64/CtsShimPriv.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index be172e6..544bca02 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_arm64/CtsShim.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 13eca13..72386bb 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShimPriv.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index 2e863fe..893eac2 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
drops {
android_build_drop {
- build_id: "6508977"
+ build_id: "7197701"
target: "CtsShim"
source_file: "aosp_x86_64/CtsShim.apk"
}
@@ -8,5 +8,5 @@
version: ""
version_group: ""
git_project: "platform/frameworks/base"
- git_branch: "rvc-dev"
+ git_branch: "sc-dev"
}
diff --git a/Android.bp b/Android.bp
index 622b2c6..9690969 100644
--- a/Android.bp
+++ b/Android.bp
@@ -665,9 +665,8 @@
],
required: [
"framework-platform-compat-config",
- // TODO: remove gps_debug, cec_config.xml and protolog.conf.json when the build system propagates "required" properly.
+ // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
"gps_debug.conf",
- "cec_config.xml",
"icu4j-platform-compat-config",
"libcore-platform-compat-config",
"protolog.conf.json.gz",
diff --git a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
index 752c36e..6cdf585 100644
--- a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
+++ b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
@@ -65,7 +65,7 @@
* @return package names the system has white-listed to opt out of power save restrictions,
* except for device idle mode.
*
- * @hide Should be migrated to PowerWhitelistManager
+ * @hide Should be migrated to PowerExemptionManager
*/
@TestApi
public @NonNull String[] getSystemPowerWhitelistExceptIdle() {
@@ -80,7 +80,7 @@
* @return package names the system has white-listed to opt out of power save restrictions for
* all modes.
*
- * @hide Should be migrated to PowerWhitelistManager
+ * @hide Should be migrated to PowerExemptionManager
*/
@TestApi
public @NonNull String[] getSystemPowerWhitelist() {
diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
index 43d4873..9d18dfe 100644
--- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
+++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
@@ -42,7 +42,7 @@
boolean isPowerSaveWhitelistExceptIdleApp(String name);
boolean isPowerSaveWhitelistApp(String name);
@UnsupportedAppUsage(maxTargetSdk = 30,
- publicAlternatives = "Use SystemApi {@code PowerWhitelistManager#whitelistAppTemporarily(String, int, String)}.")
+ publicAlternatives = "Use SystemApi {@code PowerExemptionManager#addToTemporaryAllowList(String, int, int, String)}.")
void addPowerSaveTempWhitelistApp(String name, long duration, int userId, int reasonCode, String reason);
long addPowerSaveTempWhitelistAppForMms(String name, int userId, int reasonCode, String reason);
long addPowerSaveTempWhitelistAppForSms(String name, int userId, int reasonCode, String reason);
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index 8445335..d9a49aa 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -170,7 +170,7 @@
/** @hide */
public static final int REASON_EXEMPTED_PACKAGE = 64;
/** @hide */
- public static final int REASON_ALLOWLISTED_PACKAGE = 65;
+ public static final int REASON_ALLOWLISTED_PACKAGE = 65;
/** @hide */
public static final int REASON_APPOP = 66;
@@ -193,6 +193,10 @@
* Set temp-allow-list for activity recognition.
*/
public static final int REASON_ACTIVITY_RECOGNITION = 103;
+ /**
+ * Set temp-allow-list for transferring accounts between users.
+ */
+ public static final int REASON_ACCOUNT_TRANSFER = 104;
/* Reason code range 200-299 are reserved for broadcast actions */
/**
@@ -216,7 +220,7 @@
* Device idle system allow list, including EXCEPT-IDLE
* @hide
*/
- public static final int REASON_SYSTEM_ALLOW_LISTED = 300;
+ public static final int REASON_SYSTEM_ALLOW_LISTED = 300;
/** @hide */
public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301;
/**
@@ -329,6 +333,7 @@
REASON_PUSH_MESSAGING,
REASON_PUSH_MESSAGING_OVER_QUOTA,
REASON_ACTIVITY_RECOGNITION,
+ REASON_ACCOUNT_TRANSFER,
REASON_BOOT_COMPLETED,
REASON_PRE_BOOT_COMPLETED,
REASON_LOCKED_BOOT_COMPLETED,
@@ -579,6 +584,8 @@
return "PUSH_MESSAGING_OVER_QUOTA";
case REASON_ACTIVITY_RECOGNITION:
return "ACTIVITY_RECOGNITION";
+ case REASON_ACCOUNT_TRANSFER:
+ return "REASON_ACCOUNT_TRANSFER";
case REASON_BOOT_COMPLETED:
return "BOOT_COMPLETED";
case REASON_PRE_BOOT_COMPLETED:
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index b1b733a..eba39c7 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -16,13 +16,6 @@
package android.os;
-import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
-import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
-import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
-import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-import static android.app.ActivityManager.PROCESS_STATE_TOP;
-
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,7 +26,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
import java.util.List;
/**
@@ -43,9 +35,11 @@
* placed on the temporary whitelist are removed from that whitelist after a predetermined amount of
* time.
*
+ * @deprecated Use {@link PowerExemptionManager} instead
* @hide
*/
@SystemApi
+@Deprecated
@SystemService(Context.POWER_WHITELIST_MANAGER)
public class PowerWhitelistManager {
private final Context mContext;
@@ -53,21 +47,23 @@
// TODO: migrate to PowerWhitelistController
private final IDeviceIdleController mService;
+ private final PowerExemptionManager mPowerExemptionManager;
+
/**
* Indicates that an unforeseen event has occurred and the app should be whitelisted to handle
* it.
*/
- public static final int EVENT_UNSPECIFIED = 0;
+ public static final int EVENT_UNSPECIFIED = PowerExemptionManager.EVENT_UNSPECIFIED;
/**
* Indicates that an SMS event has occurred and the app should be whitelisted to handle it.
*/
- public static final int EVENT_SMS = 1;
+ public static final int EVENT_SMS = PowerExemptionManager.EVENT_SMS;
/**
* Indicates that an MMS event has occurred and the app should be whitelisted to handle it.
*/
- public static final int EVENT_MMS = 2;
+ public static final int EVENT_MMS = PowerExemptionManager.EVENT_MMS;
/**
* @hide
@@ -84,12 +80,14 @@
/**
* Allow the temp allowlist behavior, plus allow foreground service start from background.
*/
- public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0;
+ public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED =
+ PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
/**
* Only allow the temp allowlist behavior, not allow foreground service start from
* background.
*/
- public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1;
+ public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED =
+ PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
/**
* The list of temp allowlist types.
@@ -107,73 +105,83 @@
* BG-FGS-launch is denied.
* @hide
*/
- public static final int REASON_DENIED = -1;
+ public static final int REASON_DENIED = PowerExemptionManager.REASON_DENIED;
/* Reason code range 0-9 are reserved for default reasons */
/**
* The default reason code if reason is unknown.
*/
- public static final int REASON_UNKNOWN = 0;
+ public static final int REASON_UNKNOWN = PowerExemptionManager.REASON_UNKNOWN;
/**
* Use REASON_OTHER if there is no better choice.
*/
- public static final int REASON_OTHER = 1;
+ public static final int REASON_OTHER = PowerExemptionManager.REASON_OTHER;
/* Reason code range 10-49 are reserved for BG-FGS-launch allowed proc states */
/** @hide */
- public static final int REASON_PROC_STATE_PERSISTENT = 10;
+ public static final int REASON_PROC_STATE_PERSISTENT =
+ PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
/** @hide */
- public static final int REASON_PROC_STATE_PERSISTENT_UI = 11;
+ public static final int REASON_PROC_STATE_PERSISTENT_UI =
+ PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
/** @hide */
- public static final int REASON_PROC_STATE_TOP = 12;
+ public static final int REASON_PROC_STATE_TOP = PowerExemptionManager.REASON_PROC_STATE_TOP;
/** @hide */
- public static final int REASON_PROC_STATE_BTOP = 13;
+ public static final int REASON_PROC_STATE_BTOP = PowerExemptionManager.REASON_PROC_STATE_BTOP;
/** @hide */
- public static final int REASON_PROC_STATE_FGS = 14;
+ public static final int REASON_PROC_STATE_FGS = PowerExemptionManager.REASON_PROC_STATE_FGS;
/** @hide */
- public static final int REASON_PROC_STATE_BFGS = 15;
+ public static final int REASON_PROC_STATE_BFGS = PowerExemptionManager.REASON_PROC_STATE_BFGS;
/* Reason code range 50-99 are reserved for BG-FGS-launch allowed reasons */
/** @hide */
- public static final int REASON_UID_VISIBLE = 50;
+ public static final int REASON_UID_VISIBLE = PowerExemptionManager.REASON_UID_VISIBLE;
/** @hide */
- public static final int REASON_SYSTEM_UID = 51;
+ public static final int REASON_SYSTEM_UID = PowerExemptionManager.REASON_SYSTEM_UID;
/** @hide */
- public static final int REASON_ACTIVITY_STARTER = 52;
+ public static final int REASON_ACTIVITY_STARTER = PowerExemptionManager.REASON_ACTIVITY_STARTER;
/** @hide */
- public static final int REASON_START_ACTIVITY_FLAG = 53;
+ public static final int REASON_START_ACTIVITY_FLAG =
+ PowerExemptionManager.REASON_START_ACTIVITY_FLAG;
/** @hide */
- public static final int REASON_FGS_BINDING = 54;
+ public static final int REASON_FGS_BINDING = PowerExemptionManager.REASON_FGS_BINDING;
/** @hide */
- public static final int REASON_DEVICE_OWNER = 55;
+ public static final int REASON_DEVICE_OWNER = PowerExemptionManager.REASON_DEVICE_OWNER;
/** @hide */
- public static final int REASON_PROFILE_OWNER = 56;
+ public static final int REASON_PROFILE_OWNER = PowerExemptionManager.REASON_PROFILE_OWNER;
/** @hide */
- public static final int REASON_COMPANION_DEVICE_MANAGER = 57;
+ public static final int REASON_COMPANION_DEVICE_MANAGER =
+ PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
/**
* START_ACTIVITIES_FROM_BACKGROUND permission.
* @hide
*/
- public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION = 58;
+ public static final int REASON_BACKGROUND_ACTIVITY_PERMISSION =
+ PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
/**
* START_FOREGROUND_SERVICES_FROM_BACKGROUND permission.
* @hide
*/
- public static final int REASON_BACKGROUND_FGS_PERMISSION = 59;
+ public static final int REASON_BACKGROUND_FGS_PERMISSION =
+ PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION;
/** @hide */
- public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION = 60;
+ public static final int REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION =
+ PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
/** @hide */
- public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION = 61;
+ public static final int REASON_INSTR_BACKGROUND_FGS_PERMISSION =
+ PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
/** @hide */
- public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION = 62;
+ public static final int REASON_SYSTEM_ALERT_WINDOW_PERMISSION =
+ PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
/** @hide */
- public static final int REASON_DEVICE_DEMO_MODE = 63;
+ public static final int REASON_DEVICE_DEMO_MODE = PowerExemptionManager.REASON_DEVICE_DEMO_MODE;
/** @hide */
- public static final int REASON_EXEMPTED_PACKAGE = 64;
+ public static final int REASON_EXEMPTED_PACKAGE = PowerExemptionManager.REASON_EXEMPTED_PACKAGE;
/** @hide */
- public static final int REASON_ALLOWLISTED_PACKAGE = 65;
+ public static final int REASON_ALLOWLISTED_PACKAGE =
+ PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
/** @hide */
- public static final int REASON_APPOP = 66;
+ public static final int REASON_APPOP = PowerExemptionManager.REASON_APPOP;
/* BG-FGS-launch is allowed by temp-allowlist or system-allowlist.
Reason code for temp and system allowlist starts here.
@@ -181,117 +189,128 @@
/**
* Set temp-allowlist for location geofence purpose.
*/
- public static final int REASON_GEOFENCING = 100;
+ public static final int REASON_GEOFENCING = PowerExemptionManager.REASON_GEOFENCING;
/**
* Set temp-allowlist for server push messaging.
*/
- public static final int REASON_PUSH_MESSAGING = 101;
+ public static final int REASON_PUSH_MESSAGING = PowerExemptionManager.REASON_PUSH_MESSAGING;
/**
* Set temp-allowlist for server push messaging over the quota.
*/
- public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102;
+ public static final int REASON_PUSH_MESSAGING_OVER_QUOTA =
+ PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA;
/**
* Set temp-allowlist for activity recognition.
*/
- public static final int REASON_ACTIVITY_RECOGNITION = 103;
+ public static final int REASON_ACTIVITY_RECOGNITION =
+ PowerExemptionManager.REASON_ACTIVITY_RECOGNITION;
/* Reason code range 200-299 are reserved for broadcast actions */
/**
* Broadcast ACTION_BOOT_COMPLETED.
* @hide
*/
- public static final int REASON_BOOT_COMPLETED = 200;
+ public static final int REASON_BOOT_COMPLETED = PowerExemptionManager.REASON_BOOT_COMPLETED;
/**
* Broadcast ACTION_PRE_BOOT_COMPLETED.
* @hide
*/
- public static final int REASON_PRE_BOOT_COMPLETED = 201;
+ public static final int REASON_PRE_BOOT_COMPLETED =
+ PowerExemptionManager.REASON_PRE_BOOT_COMPLETED;
/**
* Broadcast ACTION_LOCKED_BOOT_COMPLETED.
* @hide
*/
- public static final int REASON_LOCKED_BOOT_COMPLETED = 202;
+ public static final int REASON_LOCKED_BOOT_COMPLETED =
+ PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED;
/* Reason code range 300-399 are reserved for other internal reasons */
/**
* Device idle system allowlist, including EXCEPT-IDLE
* @hide
*/
- public static final int REASON_SYSTEM_ALLOW_LISTED = 300;
+ public static final int REASON_SYSTEM_ALLOW_LISTED =
+ PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
/** @hide */
- public static final int REASON_ALARM_MANAGER_ALARM_CLOCK = 301;
+ public static final int REASON_ALARM_MANAGER_ALARM_CLOCK =
+ PowerExemptionManager.REASON_ALARM_MANAGER_ALARM_CLOCK;
/**
* AlarmManagerService.
* @hide
*/
- public static final int REASON_ALARM_MANAGER_WHILE_IDLE = 302;
+ public static final int REASON_ALARM_MANAGER_WHILE_IDLE =
+ PowerExemptionManager.REASON_ALARM_MANAGER_WHILE_IDLE;
/**
* ActiveServices.
* @hide
*/
- public static final int REASON_SERVICE_LAUNCH = 303;
+ public static final int REASON_SERVICE_LAUNCH = PowerExemptionManager.REASON_SERVICE_LAUNCH;
/**
* KeyChainSystemService.
* @hide
*/
- public static final int REASON_KEY_CHAIN = 304;
+ public static final int REASON_KEY_CHAIN = PowerExemptionManager.REASON_KEY_CHAIN;
/**
* PackageManagerService.
* @hide
*/
- public static final int REASON_PACKAGE_VERIFIER = 305;
+ public static final int REASON_PACKAGE_VERIFIER = PowerExemptionManager.REASON_PACKAGE_VERIFIER;
/**
* SyncManager.
* @hide
*/
- public static final int REASON_SYNC_MANAGER = 306;
+ public static final int REASON_SYNC_MANAGER = PowerExemptionManager.REASON_SYNC_MANAGER;
/**
* DomainVerificationProxyV1.
* @hide
*/
- public static final int REASON_DOMAIN_VERIFICATION_V1 = 307;
+ public static final int REASON_DOMAIN_VERIFICATION_V1 =
+ PowerExemptionManager.REASON_DOMAIN_VERIFICATION_V1;
/**
* DomainVerificationProxyV2.
* @hide
*/
- public static final int REASON_DOMAIN_VERIFICATION_V2 = 308;
+ public static final int REASON_DOMAIN_VERIFICATION_V2 =
+ PowerExemptionManager.REASON_DOMAIN_VERIFICATION_V2;
/** @hide */
public static final int REASON_VPN = 309;
/**
* NotificationManagerService.
* @hide
*/
- public static final int REASON_NOTIFICATION_SERVICE = 310;
+ public static final int REASON_NOTIFICATION_SERVICE =
+ PowerExemptionManager.REASON_NOTIFICATION_SERVICE;
/**
* Broadcast ACTION_MY_PACKAGE_REPLACED.
* @hide
*/
- public static final int REASON_PACKAGE_REPLACED = 311;
+ public static final int REASON_PACKAGE_REPLACED = PowerExemptionManager.REASON_PACKAGE_REPLACED;
/**
* LocationProviderManager.
* @hide
*/
- public static final int REASON_LOCATION_PROVIDER = 312;
+ public static final int REASON_LOCATION_PROVIDER =
+ PowerExemptionManager.REASON_LOCATION_PROVIDER;
/**
* MediaButtonReceiver.
* @hide
*/
- public static final int REASON_MEDIA_BUTTON = 313;
+ public static final int REASON_MEDIA_BUTTON = PowerExemptionManager.REASON_MEDIA_BUTTON;
/**
* InboundSmsHandler.
* @hide
*/
- public static final int REASON_EVENT_SMS = 314;
+ public static final int REASON_EVENT_SMS = PowerExemptionManager.REASON_EVENT_SMS;
/**
* InboundSmsHandler.
* @hide
*/
- public static final int REASON_EVENT_MMS = 315;
+ public static final int REASON_EVENT_MMS = PowerExemptionManager.REASON_EVENT_MMS;
/**
* Shell app.
* @hide
*/
- public static final int REASON_SHELL = 316;
+ public static final int REASON_SHELL = PowerExemptionManager.REASON_SHELL;
/**
* The list of BG-FGS-Launch and temp-allowlist reason code.
@@ -360,26 +379,29 @@
public PowerWhitelistManager(@NonNull Context context) {
mContext = context;
mService = context.getSystemService(DeviceIdleManager.class).getService();
+ mPowerExemptionManager = context.getSystemService(PowerExemptionManager.class);
}
/**
* Add the specified package to the permanent power save whitelist.
+ *
+ * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(String)} instead
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.DEVICE_POWER)
public void addToWhitelist(@NonNull String packageName) {
- addToWhitelist(Collections.singletonList(packageName));
+ mPowerExemptionManager.addToPermanentAllowList(packageName);
}
/**
* Add the specified packages to the permanent power save whitelist.
+ *
+ * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(List)} instead
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.DEVICE_POWER)
public void addToWhitelist(@NonNull List<String> packageNames) {
- try {
- mService.addPowerSaveWhitelistApps(packageNames);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPowerExemptionManager.addToPermanentAllowList(packageNames);
}
/**
@@ -388,19 +410,13 @@
*
* @param includingIdle Set to true if the app should be whitelisted from device idle as well
* as other power save restrictions
+ * @deprecated Use {@link PowerExemptionManager#getAllowListedAppIds(boolean)} instead
* @hide
*/
+ @Deprecated
@NonNull
public int[] getWhitelistedAppIds(boolean includingIdle) {
- try {
- if (includingIdle) {
- return mService.getAppIdWhitelist();
- } else {
- return mService.getAppIdWhitelistExceptIdle();
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mPowerExemptionManager.getAllowListedAppIds(includingIdle);
}
/**
@@ -409,18 +425,12 @@
*
* @param includingIdle Set to true if the app should be whitelisted from device
* idle as well as other power save restrictions
+ * @deprecated Use {@link PowerExemptionManager#isAllowListed(String, boolean)} instead
* @hide
*/
+ @Deprecated
public boolean isWhitelisted(@NonNull String packageName, boolean includingIdle) {
- try {
- if (includingIdle) {
- return mService.isPowerSaveWhitelistApp(packageName);
- } else {
- return mService.isPowerSaveWhitelistExceptIdleApp(packageName);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mPowerExemptionManager.isAllowListed(packageName, includingIdle);
}
/**
@@ -429,14 +439,12 @@
* whitelisted by default by the system cannot be removed.
*
* @param packageName The app to remove from the whitelist
+ * @deprecated Use {@link PowerExemptionManager#removeFromAllowList(String)} instead
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.DEVICE_POWER)
public void removeFromWhitelist(@NonNull String packageName) {
- try {
- mService.removePowerSaveWhitelistApp(packageName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPowerExemptionManager.removeFromAllowList(packageName);
}
/**
@@ -446,16 +454,14 @@
* @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
* @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
* @param reason a optional human readable reason string, could be null or empty string.
+ * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
+ * String, long, int, String)} instead
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
public void whitelistAppTemporarily(@NonNull String packageName, long durationMs,
@ReasonCode int reasonCode, @Nullable String reason) {
- try {
- mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(),
- reasonCode, reason);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mPowerExemptionManager.addToTemporaryAllowList(packageName, durationMs, reasonCode, reason);
}
/**
@@ -463,12 +469,14 @@
*
* @param packageName The package to add to the temp whitelist
* @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
- * @deprecated Use {@link #whitelistAppTemporarily(String, long, int, String)} instead
+ * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
+ * String, long, int, String)} instead
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
- whitelistAppTemporarily(packageName, durationMs, REASON_UNKNOWN, packageName);
+ mPowerExemptionManager.addToTemporaryAllowList(
+ packageName, durationMs, REASON_UNKNOWN, packageName);
}
/**
@@ -481,13 +489,15 @@
* @param reason A human-readable reason explaining why the app is temp whitelisted. Only
* used for logging purposes. Could be null or empty string.
* @return The duration (in milliseconds) that the app is whitelisted for
- * @deprecated Use {@link #whitelistAppTemporarilyForEvent(String, int, int, String)} instead
+ * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
+ * String, int, int, String)} instead
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
@WhitelistEvent int event, @Nullable String reason) {
- return whitelistAppTemporarilyForEvent(packageName, event, REASON_UNKNOWN, reason);
+ return mPowerExemptionManager.addToTemporaryAllowListForEvent(
+ packageName, event, REASON_UNKNOWN, reason);
}
/**
@@ -501,47 +511,25 @@
* @param reason A human-readable reason explaining why the app is temp whitelisted. Only
* used for logging purposes. Could be null or empty string.
* @return The duration (in milliseconds) that the app is whitelisted for
+ * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
+ * String, int, int, String)} instead
*/
+ @Deprecated
@RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
@WhitelistEvent int event, @ReasonCode int reasonCode, @Nullable String reason) {
- try {
- switch (event) {
- case EVENT_MMS:
- return mService.addPowerSaveTempWhitelistAppForMms(
- packageName, mContext.getUserId(), reasonCode, reason);
- case EVENT_SMS:
- return mService.addPowerSaveTempWhitelistAppForSms(
- packageName, mContext.getUserId(), reasonCode, reason);
- case EVENT_UNSPECIFIED:
- default:
- return mService.whitelistAppTemporarily(
- packageName, mContext.getUserId(), reasonCode, reason);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mPowerExemptionManager.addToTemporaryAllowListForEvent(
+ packageName, event, reasonCode, reason);
}
/**
* @hide
+ *
+ * @deprecated Use {@link PowerExemptionManager#getReasonCodeFromProcState(int)} instead
*/
+ @Deprecated
public static @ReasonCode int getReasonCodeFromProcState(int procState) {
- if (procState <= PROCESS_STATE_PERSISTENT) {
- return REASON_PROC_STATE_PERSISTENT;
- } else if (procState <= PROCESS_STATE_PERSISTENT_UI) {
- return REASON_PROC_STATE_PERSISTENT_UI;
- } else if (procState <= PROCESS_STATE_TOP) {
- return REASON_PROC_STATE_TOP;
- } else if (procState <= PROCESS_STATE_BOUND_TOP) {
- return REASON_PROC_STATE_BTOP;
- } else if (procState <= PROCESS_STATE_FOREGROUND_SERVICE) {
- return REASON_PROC_STATE_FGS;
- } else if (procState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- return REASON_PROC_STATE_BFGS;
- } else {
- return REASON_DENIED;
- }
+ return PowerExemptionManager.getReasonCodeFromProcState(procState);
}
/**
@@ -549,111 +537,10 @@
* @hide
* @param reasonCode
* @return string name of the reason code.
+ * @deprecated Use {@link PowerExemptionManager#reasonCodeToString(int)} instead
*/
+ @Deprecated
public static String reasonCodeToString(@ReasonCode int reasonCode) {
- switch (reasonCode) {
- case REASON_DENIED:
- return "DENIED";
- case REASON_UNKNOWN:
- return "UNKNOWN";
- case REASON_OTHER:
- return "OTHER";
- case REASON_PROC_STATE_PERSISTENT:
- return "PROC_STATE_PERSISTENT";
- case REASON_PROC_STATE_PERSISTENT_UI:
- return "PROC_STATE_PERSISTENT_UI";
- case REASON_PROC_STATE_TOP:
- return "PROC_STATE_TOP";
- case REASON_PROC_STATE_BTOP:
- return "PROC_STATE_BTOP";
- case REASON_PROC_STATE_FGS:
- return "PROC_STATE_FGS";
- case REASON_PROC_STATE_BFGS:
- return "PROC_STATE_BFGS";
- case REASON_UID_VISIBLE:
- return "UID_VISIBLE";
- case REASON_SYSTEM_UID:
- return "SYSTEM_UID";
- case REASON_ACTIVITY_STARTER:
- return "ACTIVITY_STARTER";
- case REASON_START_ACTIVITY_FLAG:
- return "START_ACTIVITY_FLAG";
- case REASON_FGS_BINDING:
- return "FGS_BINDING";
- case REASON_DEVICE_OWNER:
- return "DEVICE_OWNER";
- case REASON_PROFILE_OWNER:
- return "PROFILE_OWNER";
- case REASON_COMPANION_DEVICE_MANAGER:
- return "COMPANION_DEVICE_MANAGER";
- case REASON_BACKGROUND_ACTIVITY_PERMISSION:
- return "BACKGROUND_ACTIVITY_PERMISSION";
- case REASON_BACKGROUND_FGS_PERMISSION:
- return "BACKGROUND_FGS_PERMISSION";
- case REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION:
- return "INSTR_BACKGROUND_ACTIVITY_PERMISSION";
- case REASON_INSTR_BACKGROUND_FGS_PERMISSION:
- return "INSTR_BACKGROUND_FGS_PERMISSION";
- case REASON_SYSTEM_ALERT_WINDOW_PERMISSION:
- return "SYSTEM_ALERT_WINDOW_PERMISSION";
- case REASON_DEVICE_DEMO_MODE:
- return "DEVICE_DEMO_MODE";
- case REASON_EXEMPTED_PACKAGE:
- return "EXEMPTED_PACKAGE";
- case REASON_ALLOWLISTED_PACKAGE:
- return "ALLOWLISTED_PACKAGE";
- case REASON_APPOP:
- return "APPOP";
- case REASON_GEOFENCING:
- return "GEOFENCING";
- case REASON_PUSH_MESSAGING:
- return "PUSH_MESSAGING";
- case REASON_PUSH_MESSAGING_OVER_QUOTA:
- return "PUSH_MESSAGING_OVER_QUOTA";
- case REASON_ACTIVITY_RECOGNITION:
- return "ACTIVITY_RECOGNITION";
- case REASON_BOOT_COMPLETED:
- return "BOOT_COMPLETED";
- case REASON_PRE_BOOT_COMPLETED:
- return "PRE_BOOT_COMPLETED";
- case REASON_LOCKED_BOOT_COMPLETED:
- return "LOCKED_BOOT_COMPLETED";
- case REASON_SYSTEM_ALLOW_LISTED:
- return "SYSTEM_ALLOW_LISTED";
- case REASON_ALARM_MANAGER_ALARM_CLOCK:
- return "ALARM_MANAGER_ALARM_CLOCK";
- case REASON_ALARM_MANAGER_WHILE_IDLE:
- return "ALARM_MANAGER_WHILE_IDLE";
- case REASON_SERVICE_LAUNCH:
- return "SERVICE_LAUNCH";
- case REASON_KEY_CHAIN:
- return "KEY_CHAIN";
- case REASON_PACKAGE_VERIFIER:
- return "PACKAGE_VERIFIER";
- case REASON_SYNC_MANAGER:
- return "SYNC_MANAGER";
- case REASON_DOMAIN_VERIFICATION_V1:
- return "DOMAIN_VERIFICATION_V1";
- case REASON_DOMAIN_VERIFICATION_V2:
- return "DOMAIN_VERIFICATION_V2";
- case REASON_VPN:
- return "VPN";
- case REASON_NOTIFICATION_SERVICE:
- return "NOTIFICATION_SERVICE";
- case REASON_PACKAGE_REPLACED:
- return "PACKAGE_REPLACED";
- case REASON_LOCATION_PROVIDER:
- return "LOCATION_PROVIDER";
- case REASON_MEDIA_BUTTON:
- return "MEDIA_BUTTON";
- case REASON_EVENT_SMS:
- return "EVENT_SMS";
- case REASON_EVENT_MMS:
- return "EVENT_MMS";
- case REASON_SHELL:
- return "SHELL";
- default:
- return "(unknown:" + reasonCode + ")";
- }
+ return PowerExemptionManager.reasonCodeToString(reasonCode);
}
}
diff --git a/config/preloaded-classes b/config/preloaded-classes
index c6ec376..7c3fd8c 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1844,11 +1844,9 @@
android.ddm.DdmHandleAppName$Names
android.ddm.DdmHandleAppName
android.ddm.DdmHandleExit
-android.ddm.DdmHandleHeap
android.ddm.DdmHandleHello
android.ddm.DdmHandleNativeHeap
android.ddm.DdmHandleProfiling
-android.ddm.DdmHandleThread
android.ddm.DdmHandleViewDebug
android.ddm.DdmRegister
android.debug.AdbManager
diff --git a/core/api/current.txt b/core/api/current.txt
index 54aa356..4a1c325 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -329,6 +329,7 @@
field public static final int apiKey = 16843281; // 0x1010211
field public static final int appCategory = 16844101; // 0x1010545
field public static final int appComponentFactory = 16844154; // 0x101057a
+ field public static final int attributionTags = 16844353; // 0x1010641
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -8490,7 +8491,7 @@
field public static final int WIDGET_CATEGORY_HOME_SCREEN = 1; // 0x1
field public static final int WIDGET_CATEGORY_KEYGUARD = 2; // 0x2
field public static final int WIDGET_CATEGORY_SEARCHBOX = 4; // 0x4
- field public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 3; // 0x3
+ field public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 4; // 0x4
field public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2; // 0x2
field public static final int WIDGET_FEATURE_RECONFIGURABLE = 1; // 0x1
field public int autoAdvanceViewId;
@@ -10500,6 +10501,7 @@
field public static final String DEVICE_POLICY_SERVICE = "device_policy";
field public static final String DISPLAY_HASH_SERVICE = "display_hash";
field public static final String DISPLAY_SERVICE = "display";
+ field public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
field public static final String DOWNLOAD_SERVICE = "download";
field public static final String DROPBOX_SERVICE = "dropbox";
field public static final String EUICC_SERVICE = "euicc";
@@ -26137,10 +26139,6 @@
ctor public NetworkSpecifier();
}
- public class ParseException extends java.lang.RuntimeException {
- field public String response;
- }
-
public abstract class PlatformVpnProfile {
method public final int getType();
method @NonNull public final String getTypeString();
@@ -30427,6 +30425,7 @@
field public static final String BASE_OS;
field public static final String CODENAME;
field public static final String INCREMENTAL;
+ field public static final int MEDIA_PERFORMANCE_CLASS;
field public static final int PREVIEW_SDK_INT;
field public static final String RELEASE;
field @NonNull public static final String RELEASE_OR_CODENAME;
@@ -39601,22 +39600,22 @@
method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
method public final void connectionServiceFocusReleased();
method @Nullable public final android.telecom.RemoteConference createRemoteIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public final android.telecom.RemoteConnection createRemoteIncomingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method @Nullable public final android.telecom.RemoteConference createRemoteOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public final android.telecom.RemoteConnection createRemoteOutgoingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method public final java.util.Collection<android.telecom.Conference> getAllConferences();
method public final java.util.Collection<android.telecom.Connection> getAllConnections();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
- method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
- method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
- method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateOutgoingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConferenceFailed(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -40614,14 +40613,6 @@
public static final class CarrierConfigManager.Iwlan {
field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1
field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0
- field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2
- field public static final int DH_GROUP_1536_BIT_MODP = 5; // 0x5
- field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe
- field public static final int DH_GROUP_3072_BIT_MODP = 15; // 0xf
- field public static final int DH_GROUP_4096_BIT_MODP = 16; // 0x10
- field public static final int DH_GROUP_NONE = 0; // 0x0
- field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc
- field public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13; // 0xd
field public static final int EPDG_ADDRESS_CELLULAR_LOC = 3; // 0x3
field public static final int EPDG_ADDRESS_PCO = 2; // 0x2
field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1
@@ -40629,12 +40620,6 @@
field public static final int ID_TYPE_FQDN = 2; // 0x2
field public static final int ID_TYPE_KEY_ID = 11; // 0xb
field public static final int ID_TYPE_RFC822_ADDR = 3; // 0x3
- field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd
- field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe
- field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0
field public static final String KEY_ADD_KE_TO_CHILD_SESSION_REKEY_BOOL = "iwlan.add_ke_to_child_session_rekey_bool";
field public static final String KEY_CHILD_SA_REKEY_HARD_TIMER_SEC_INT = "iwlan.child_sa_rekey_hard_timer_sec_int";
field public static final String KEY_CHILD_SA_REKEY_SOFT_TIMER_SEC_INT = "iwlan.child_sa_rekey_soft_timer_sec_int";
@@ -40654,10 +40639,6 @@
field public static final String KEY_IKE_REMOTE_ID_TYPE_INT = "iwlan.ike_remote_id_type_int";
field public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_cbc_key_size_int_array";
field public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.ike_session_encryption_aes_ctr_key_size_int_array";
- field public static final int KEY_LEN_AES_128 = 128; // 0x80
- field public static final int KEY_LEN_AES_192 = 192; // 0xc0
- field public static final int KEY_LEN_AES_256 = 256; // 0x100
- field public static final int KEY_LEN_UNUSED = 0; // 0x0
field public static final String KEY_MAX_RETRIES_INT = "iwlan.max_retries_int";
field public static final String KEY_MCC_MNCS_STRING_ARRAY = "iwlan.mcc_mncs_string_array";
field public static final String KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT = "iwlan.natt_keep_alive_timer_sec_int";
@@ -40667,11 +40648,6 @@
field public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY = "iwlan.supported_ike_session_encryption_algorithms_int_array";
field public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY = "iwlan.supported_integrity_algorithms_int_array";
field public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY = "iwlan.supported_prf_algorithms_int_array";
- field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4
- field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
- field public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5; // 0x5
- field public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6; // 0x6
- field public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7; // 0x7
}
public abstract class CellIdentity implements android.os.Parcelable {
@@ -42040,6 +42016,7 @@
method public static int getDefaultSmsSubscriptionId();
method public static int getDefaultSubscriptionId();
method public static int getDefaultVoiceSubscriptionId();
+ method public int getDeviceToDeviceStatusSharing(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions();
method public static int getSlotIndex(int);
method @Nullable public int[] getSubscriptionIds(int);
@@ -42052,6 +42029,7 @@
method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharing(int, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
method public void setSubscriptionOverrideCongested(int, boolean, long);
method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long);
@@ -42063,6 +42041,11 @@
field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
field public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
field public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+ field public static final int D2D_SHARING_ALL = 3; // 0x3
+ field public static final int D2D_SHARING_ALL_CONTACTS = 1; // 0x1
+ field public static final int D2D_SHARING_DISABLED = 0; // 0x0
+ field public static final int D2D_SHARING_STARRED_CONTACTS = 2; // 0x2
+ field public static final String D2D_STATUS_SHARING = "d2d_sharing_status";
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
@@ -54983,6 +54966,7 @@
ctor public RemoteViews(@NonNull java.util.Map<android.util.SizeF,android.widget.RemoteViews>);
ctor public RemoteViews(android.widget.RemoteViews);
ctor public RemoteViews(android.os.Parcel);
+ method public void addStableView(@IdRes int, @NonNull android.widget.RemoteViews, int);
method public void addView(@IdRes int, android.widget.RemoteViews);
method public android.view.View apply(android.content.Context, android.view.ViewGroup);
method @Deprecated public android.widget.RemoteViews clone();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 057e16c..18b0a43 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -59,6 +59,10 @@
method @NonNull public android.os.UserHandle getUser();
}
+ public class Intent implements java.lang.Cloneable android.os.Parcelable {
+ field public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
+ }
+
}
package android.content.pm {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cd69021..afa9a7e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2162,7 +2162,6 @@
field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
- field public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
field public static final String ETHERNET_SERVICE = "ethernet";
field public static final String EUICC_CARD_SERVICE = "euicc_card";
field public static final String FONT_SERVICE = "font";
@@ -2174,7 +2173,6 @@
field public static final String OEM_LOCK_SERVICE = "oem_lock";
field public static final String PERMISSION_SERVICE = "permission";
field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
- field public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
field public static final String REBOOT_READINESS_SERVICE = "reboot_readiness";
field public static final String ROLLBACK_SERVICE = "rollback";
field public static final String SEARCH_UI_SERVICE = "search_ui";
@@ -2901,7 +2899,7 @@
}
public class FontManager {
- method @NonNull public android.text.FontConfig getFontConfig();
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig();
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb
field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff
@@ -7521,12 +7519,12 @@
package android.net.vcn {
public class VcnManager {
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void addVcnNetworkPolicyChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.vcn.VcnNetworkPolicyResult applyVcnNetworkPolicy(@NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties);
- method public void removeVcnNetworkPolicyListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyListener);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void removeVcnNetworkPolicyChangeListener(@NonNull android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener);
}
- public static interface VcnManager.VcnNetworkPolicyListener {
+ public static interface VcnManager.VcnNetworkPolicyChangeListener {
method public void onPolicyChanged();
}
@@ -8184,6 +8182,7 @@
field public static final int EVENT_MMS = 2; // 0x2
field public static final int EVENT_SMS = 1; // 0x1
field public static final int EVENT_UNSPECIFIED = 0; // 0x0
+ field public static final int REASON_ACCOUNT_TRANSFER = 104; // 0x68
field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
field public static final int REASON_GEOFENCING = 100; // 0x64
field public static final int REASON_OTHER = 1; // 0x1
@@ -8224,25 +8223,25 @@
field public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1; // 0x1
}
- public class PowerWhitelistManager {
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String);
+ @Deprecated public class PowerWhitelistManager {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long, int, @Nullable String);
method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @Nullable String);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String);
- field public static final int EVENT_MMS = 2; // 0x2
- field public static final int EVENT_SMS = 1; // 0x1
- field public static final int EVENT_UNSPECIFIED = 0; // 0x0
- field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
- field public static final int REASON_GEOFENCING = 100; // 0x64
- field public static final int REASON_OTHER = 1; // 0x1
- field public static final int REASON_PUSH_MESSAGING = 101; // 0x65
- field public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66
- field public static final int REASON_UNKNOWN = 0; // 0x0
- field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
- field public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, int, @Nullable String);
+ field @Deprecated public static final int EVENT_MMS = 2; // 0x2
+ field @Deprecated public static final int EVENT_SMS = 1; // 0x1
+ field @Deprecated public static final int EVENT_UNSPECIFIED = 0; // 0x0
+ field @Deprecated public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
+ field @Deprecated public static final int REASON_GEOFENCING = 100; // 0x64
+ field @Deprecated public static final int REASON_OTHER = 1; // 0x1
+ field @Deprecated public static final int REASON_PUSH_MESSAGING = 101; // 0x65
+ field @Deprecated public static final int REASON_PUSH_MESSAGING_OVER_QUOTA = 102; // 0x66
+ field @Deprecated public static final int REASON_UNKNOWN = 0; // 0x0
+ field @Deprecated public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
+ field @Deprecated public static final int TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
}
public class RecoverySystem {
@@ -10251,6 +10250,7 @@
ctor public HotwordDetectionService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public void onDetectFromDspSource(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
+ method public void onUpdateState(@Nullable android.os.Bundle, @Nullable android.os.SharedMemory);
field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";
}
@@ -10261,10 +10261,8 @@
public class VoiceInteractionService extends android.app.Service {
method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+ method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.Bundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
- method public final int setHotwordDetectionConfig(@Nullable android.os.Bundle);
- field public static final int HOTWORD_CONFIG_FAILURE = 1; // 0x1
- field public static final int HOTWORD_CONFIG_SUCCESS = 0; // 0x0
}
}
@@ -11473,7 +11471,7 @@
}
public static interface TelephonyCallback.AllowedNetworkTypesListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(int, long);
}
public static interface TelephonyCallback.CallAttributesListener {
@@ -11957,7 +11955,7 @@
method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV4(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(@IntRange(from=android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET, to=15) int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
@@ -12052,7 +12050,6 @@
}
public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
- method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel);
method public int describeContents();
method public long getGuaranteedDownlinkBitRate();
method public long getGuaranteedUplinkBitRate();
@@ -13035,6 +13032,7 @@
method public void onAutoConfigurationErrorReceived(int, @NonNull String);
method public void onConfigurationChanged(@NonNull byte[]);
method public void onConfigurationReset();
+ method public void onPreProvisioningReceived(@NonNull byte[]);
method public void onRemoved();
}
@@ -13504,6 +13502,7 @@
method public int getConfigInt(int);
method public String getConfigString(int);
method public final void notifyAutoConfigurationErrorReceived(int, @NonNull String);
+ method public final void notifyPreProvisioningReceived(@NonNull byte[]);
method public final void notifyProvisionedValueChanged(int, int);
method public final void notifyProvisionedValueChanged(int, String);
method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
@@ -13835,6 +13834,7 @@
package android.uwb {
public final class AngleMeasurement implements android.os.Parcelable {
+ ctor public AngleMeasurement(double, double, double);
method public int describeContents();
method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
@@ -13843,14 +13843,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR;
}
- public static final class AngleMeasurement.Builder {
- ctor public AngleMeasurement.Builder();
- method @NonNull public android.uwb.AngleMeasurement build();
- method @NonNull public android.uwb.AngleMeasurement.Builder setConfidenceLevel(double);
- method @NonNull public android.uwb.AngleMeasurement.Builder setErrorRadians(double);
- method @NonNull public android.uwb.AngleMeasurement.Builder setRadians(double);
- }
-
public final class AngleOfArrivalMeasurement implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.uwb.AngleMeasurement getAltitude();
@@ -13860,10 +13852,9 @@
}
public static final class AngleOfArrivalMeasurement.Builder {
- ctor public AngleOfArrivalMeasurement.Builder();
+ ctor public AngleOfArrivalMeasurement.Builder(@NonNull android.uwb.AngleMeasurement);
method @NonNull public android.uwb.AngleOfArrivalMeasurement build();
method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement);
- method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAzimuth(@NonNull android.uwb.AngleMeasurement);
}
public final class DistanceMeasurement implements android.os.Parcelable {
@@ -13963,7 +13954,7 @@
public final class UwbManager {
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos();
method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo();
- method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
+ method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.CancellationSignal openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 72d3976..d951405 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -414,6 +414,7 @@
method public long getLastNetworkLogRetrievalTime();
method public long getLastSecurityLogRetrievalTime();
method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
+ method @NonNull @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public java.util.Set<java.lang.String> getPolicyExemptApps();
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
method @RequiresPermission(anyOf={"android.permission.MARK_DEVICE_ORGANIZATION_OWNED", "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
@@ -698,7 +699,8 @@
field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle";
field public static final String DREAM_SERVICE = "dream";
field public static final String FONT_SERVICE = "font";
- field public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
+ field public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
+ field @Deprecated public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
@@ -706,6 +708,10 @@
method public int getDisplayId();
}
+ public class SyncAdapterType implements android.os.Parcelable {
+ method @Nullable public String getPackageName();
+ }
+
}
package android.content.integrity {
@@ -940,6 +946,12 @@
method public void splitVertically(@NonNull android.graphics.Rect...);
}
+ public class Typeface {
+ method @NonNull public static java.util.Map<java.lang.String,android.graphics.Typeface> deserializeFontMap(@NonNull java.nio.ByteBuffer) throws java.io.IOException;
+ method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory();
+ method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException;
+ }
+
}
package android.graphics.drawable {
@@ -962,7 +974,7 @@
package android.graphics.fonts {
public class FontManager {
- method @NonNull public android.text.FontConfig getFontConfig();
+ method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public android.text.FontConfig getFontConfig();
method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int);
field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb
field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff
@@ -1485,6 +1497,14 @@
package android.os {
+ public final class BatteryStatsManager {
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void resetBattery(boolean);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryLevel(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setChargerAcOnline(boolean, boolean);
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void suspendBatteryInput();
+ method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void unplugBattery(boolean);
+ }
+
public class Build {
method public static boolean is64BitAbi(String);
field public static final boolean IS_EMULATOR;
@@ -2538,6 +2558,7 @@
method public default int getDisplayImePolicy(int);
method public default void holdLock(android.os.IBinder, int);
method public default void setDisplayImePolicy(int, int);
+ method public default void setForceCrossWindowBlurDisabled(boolean);
method public default void setShouldShowSystemDecors(int, boolean);
method public default void setShouldShowWithInsecureKeyguard(int, boolean);
method public default boolean shouldShowSystemDecors(int);
@@ -2915,7 +2936,7 @@
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
- method @BinderThread public void removeStartingWindow(int);
+ method @BinderThread public void removeStartingWindow(int, @Nullable android.view.SurfaceControl, @Nullable android.graphics.Rect, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8e53b5b..7dbbc54 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -57,6 +57,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.DeadSystemException;
+import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -120,6 +121,8 @@
/** {@hide} */
private static final String VALUE_CMF_COLOR =
android.os.SystemProperties.get("ro.boot.hardware.color");
+ /** {@hide} */
+ private static final String WALLPAPER_CMF_PATH = "/wallpaper/image/";
/**
* Activity Action: Show settings for choosing wallpaper. Do not use directly to construct
@@ -2066,22 +2069,17 @@
return null;
} else {
whichProp = PROP_WALLPAPER;
- final int defaultColorResId = context.getResources().getIdentifier(
- "default_wallpaper_" + VALUE_CMF_COLOR, "drawable", "android");
- defaultResId =
- defaultColorResId == 0 ? com.android.internal.R.drawable.default_wallpaper
- : defaultColorResId;
+ defaultResId = com.android.internal.R.drawable.default_wallpaper;
}
final String path = SystemProperties.get(whichProp);
- if (!TextUtils.isEmpty(path)) {
- final File file = new File(path);
- if (file.exists()) {
- try {
- return new FileInputStream(file);
- } catch (IOException e) {
- // Ignored, fall back to platform default below
- }
- }
+ final InputStream wallpaperInputStream = getWallpaperInputStream(path);
+ if (wallpaperInputStream != null) {
+ return wallpaperInputStream;
+ }
+ final String cmfPath = getCmfWallpaperPath();
+ final InputStream cmfWallpaperInputStream = getWallpaperInputStream(cmfPath);
+ if (cmfWallpaperInputStream != null) {
+ return cmfWallpaperInputStream;
}
try {
return context.getResources().openRawResource(defaultResId);
@@ -2091,6 +2089,25 @@
return null;
}
+ private static InputStream getWallpaperInputStream(String path) {
+ if (!TextUtils.isEmpty(path)) {
+ final File file = new File(path);
+ if (file.exists()) {
+ try {
+ return new FileInputStream(file);
+ } catch (IOException e) {
+ // Ignored, fall back to platform default
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String getCmfWallpaperPath() {
+ return Environment.getProductDirectory() + WALLPAPER_CMF_PATH + "default_wallpaper_"
+ + VALUE_CMF_COLOR;
+ }
+
/**
* Return {@link ComponentName} of the default live wallpaper, or
* {@code null} if none is defined.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 30fb858..930717b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -13726,4 +13726,22 @@
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Lists apps that are exempt from policies (such as
+ * {@link #setPackagesSuspended(ComponentName, String[], boolean)}).
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(value = android.Manifest.permission.MANAGE_DEVICE_ADMINS)
+ public @NonNull Set<String> getPolicyExemptApps() {
+ if (mService == null) return Collections.emptySet();
+
+ try {
+ return new HashSet<>(mService.listPolicyExemptApps());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 25ca599..e98720c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -177,6 +177,7 @@
String[] setPackagesSuspended(in ComponentName admin, in String callerPackage, in String[] packageNames, boolean suspended);
boolean isPackageSuspended(in ComponentName admin, in String callerPackage, String packageName);
+ List<String> listPolicyExemptApps();
boolean installCaCert(in ComponentName admin, String callerPackage, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, String callerPackage, in String[] aliases);
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 6ac1c1a..1cbb2fb 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -121,7 +121,7 @@
*
* @see #widgetFeatures
*/
- public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 3;
+ public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 4;
/** @hide */
@IntDef(flag = true, prefix = { "FLAG_" }, value = {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0509e3f..2523459 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3713,6 +3713,9 @@
* usage statistics.
* <dt> {@link #HARDWARE_PROPERTIES_SERVICE} ("hardware_properties")
* <dd> A {@link android.os.HardwarePropertiesManager} for accessing hardware properties.
+ * <dt> {@link #DOMAIN_VERIFICATION_SERVICE} ("domain_verification")
+ * <dd> A {@link android.content.pm.verify.domain.DomainVerificationManager} for accessing
+ * web domain approval state.
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -3794,6 +3797,8 @@
* @see android.app.usage.NetworkStatsManager
* @see android.os.HardwarePropertiesManager
* @see #HARDWARE_PROPERTIES_SERVICE
+ * @see #DOMAIN_VERIFICATION_SERVICE
+ * @see android.content.pm.verify.domain.DomainVerificationManager
*/
public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
@@ -3813,7 +3818,8 @@
* {@link android.view.inputmethod.InputMethodManager},
* {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
* {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
- * {@link android.app.usage.NetworkStatsManager}.
+ * {@link android.app.usage.NetworkStatsManager},
+ * {@link android.content.pm.verify.domain.DomainVerificationManager}.
* </p>
*
* <p>
@@ -4833,7 +4839,8 @@
* @hide
*/
@TestApi
- @SuppressLint("ServiceName") // TODO: This should be renamed to POWER_WHITELIST_SERVICE
+ @Deprecated
+ @SuppressLint("ServiceName")
public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
/**
@@ -4842,7 +4849,7 @@
* @see #getSystemService(String)
* @hide
*/
- @SystemApi
+ @TestApi
public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
/**
@@ -5544,12 +5551,13 @@
public static final String GAME_SERVICE = "game";
/**
- * Use with {@link #getSystemService(String)} to access domain verification service.
+ * Use with {@link #getSystemService(String)} to access
+ * {@link android.content.pm.verify.domain.DomainVerificationManager} to retrieve approval and
+ * user state for declared web domains.
*
* @see #getSystemService(String)
- * @hide
+ * @see android.content.pm.verify.domain.DomainVerificationManager
*/
- @SystemApi
public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index de17fda..04f93ca 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2331,6 +2331,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
/**
* Alarm Changed Action: This is broadcast when the AlarmClock
diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 1c21b2a..47c333c 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -17,6 +17,7 @@
package android.content;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -168,6 +169,7 @@
*
* @hide
*/
+ @TestApi
public @Nullable String getPackageName() {
return packageName;
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5a17753..58f83a7 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1086,6 +1086,13 @@
*/
public WindowLayout windowLayout;
+ /**
+ * Attribution tags for finer grained calls if a {@android.content.Context#sendBroadcast(Intent,
+ * String)} is used with a permission.
+ * @hide
+ */
+ public String[] attributionTags;
+
public ActivityInfo() {
}
@@ -1114,6 +1121,7 @@
maxAspectRatio = orig.maxAspectRatio;
minAspectRatio = orig.minAspectRatio;
supportsSizeChanges = orig.supportsSizeChanges;
+ attributionTags = orig.attributionTags;
}
/**
@@ -1361,6 +1369,15 @@
if (supportsSizeChanges) {
pw.println(prefix + "supportsSizeChanges=true");
}
+ if (attributionTags != null && attributionTags.length > 0) {
+ StringBuilder tags = new StringBuilder();
+ tags.append(attributionTags[0]);
+ for (int i = 1; i < attributionTags.length; i++) {
+ tags.append(", ");
+ tags.append(attributionTags[i]);
+ }
+ pw.println(prefix + "attributionTags=[" + tags + "]");
+ }
super.dumpBack(pw, prefix, dumpFlags);
}
@@ -1406,6 +1423,7 @@
dest.writeFloat(maxAspectRatio);
dest.writeFloat(minAspectRatio);
dest.writeBoolean(supportsSizeChanges);
+ dest.writeString8Array(attributionTags);
}
/**
@@ -1525,6 +1543,7 @@
maxAspectRatio = source.readFloat();
minAspectRatio = source.readFloat();
supportsSizeChanges = source.readBoolean();
+ attributionTags = source.createString8Array();
}
/**
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index 745c39b..79b70f2 100644
--- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -23,32 +23,34 @@
oneway interface IDataLoaderStatusListener {
/** The DataLoader process died, binder disconnected or class destroyed. */
const int DATA_LOADER_DESTROYED = 0;
+ /** The system is in process of binding to the DataLoader. */
+ const int DATA_LOADER_BINDING = 1;
/** DataLoader process is running and bound to. */
- const int DATA_LOADER_BOUND = 1;
+ const int DATA_LOADER_BOUND = 2;
/** DataLoader has handled onCreate(). */
- const int DATA_LOADER_CREATED = 2;
+ const int DATA_LOADER_CREATED = 3;
/** DataLoader can receive missing pages and read pages notifications,
* and ready to provide data. */
- const int DATA_LOADER_STARTED = 3;
+ const int DATA_LOADER_STARTED = 4;
/** DataLoader no longer ready to provide data and is not receiving
* any notifications from IncFS. */
- const int DATA_LOADER_STOPPED = 4;
+ const int DATA_LOADER_STOPPED = 5;
/** DataLoader streamed everything necessary to continue installation. */
- const int DATA_LOADER_IMAGE_READY = 5;
+ const int DATA_LOADER_IMAGE_READY = 6;
/** Installation can't continue as DataLoader failed to stream necessary data. */
- const int DATA_LOADER_IMAGE_NOT_READY = 6;
+ const int DATA_LOADER_IMAGE_NOT_READY = 7;
/** DataLoader instance can't run at the moment, but might recover later.
* It's up to system to decide if the app is still usable. */
- const int DATA_LOADER_UNAVAILABLE = 7;
+ const int DATA_LOADER_UNAVAILABLE = 8;
/** DataLoader reports that this instance is invalid and can never be restored.
* Warning: this is a terminal status that data loader should use carefully and
* the system should almost never use - e.g. only if all recovery attempts
* fail and all retry limits are exceeded. */
- const int DATA_LOADER_UNRECOVERABLE = 8;
+ const int DATA_LOADER_UNRECOVERABLE = 9;
/** There are no known issues with the data stream. */
const int STREAM_HEALTHY = 0;
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index 0d5b33c..8f9a0d7 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -29,6 +29,7 @@
import android.util.jar.StrictJarFile;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.security.VerityUtils;
import java.io.File;
import java.io.IOException;
@@ -76,7 +77,8 @@
* Returns whether fs-verity is required to install a dex metadata
*/
public static boolean isFsVerityRequired() {
- return SystemProperties.getBoolean(PROPERTY_DM_FSVERITY_REQUIRED, false);
+ return VerityUtils.isFsVeritySupported()
+ && SystemProperties.getBoolean(PROPERTY_DM_FSVERITY_REQUIRED, false);
}
/**
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 9a84ded..b660a00 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -482,6 +482,7 @@
ai.rotationAnimation = a.getRotationAnimation();
ai.colorMode = a.getColorMode();
ai.windowLayout = a.getWindowLayout();
+ ai.attributionTags = a.getAttributionTags();
if ((flags & PackageManager.GET_META_DATA) != 0) {
ai.metaData = a.getMetaData();
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 6f478ac..9285ccb 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -82,6 +82,9 @@
@Nullable
ActivityInfo.WindowLayout windowLayout;
+ @Nullable
+ String[] attributionTags;
+
public ParsedActivity(ParsedActivity other) {
super(other);
this.theme = other.theme;
@@ -107,6 +110,7 @@
this.rotationAnimation = other.rotationAnimation;
this.colorMode = other.colorMode;
this.windowLayout = other.windowLayout;
+ this.attributionTags = other.attributionTags;
}
/**
@@ -172,6 +176,7 @@
alias.requestedVrComponent = target.requestedVrComponent;
alias.directBootAware = target.directBootAware;
alias.setProcessName(target.getProcessName());
+ alias.attributionTags = target.attributionTags;
return alias;
// Not all attributes from the target ParsedActivity are copied to the alias.
@@ -299,6 +304,7 @@
} else {
dest.writeBoolean(false);
}
+ dest.writeString8Array(this.attributionTags);
}
public ParsedActivity() {
@@ -332,6 +338,7 @@
if (in.readBoolean()) {
windowLayout = new ActivityInfo.WindowLayout(in);
}
+ this.attributionTags = in.createString8Array();
}
public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
@@ -445,4 +452,9 @@
public ActivityInfo.WindowLayout getWindowLayout() {
return windowLayout;
}
+
+ @Nullable
+ public String[] getAttributionTags() {
+ return attributionTags;
+ }
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 0f4aa06..d99c410 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -210,6 +210,11 @@
pkg.setVisibleToInstantApps(true);
}
+ String attributionTags = sa.getString(R.styleable.AndroidManifestActivity_attributionTags);
+ if (attributionTags != null) {
+ activity.attributionTags = attributionTags.split("\\|");
+ }
+
return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver,
false /*isAlias*/, visibleToEphemeral, input,
R.styleable.AndroidManifestActivity_parentActivityName,
diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java
index e24aeb2..8fa2352 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -30,15 +30,7 @@
*/
public class DdmHandleHeap extends ChunkHandler {
- public static final int CHUNK_HPIF = type("HPIF");
- public static final int CHUNK_HPSG = type("HPSG");
- public static final int CHUNK_HPDU = type("HPDU");
- public static final int CHUNK_HPDS = type("HPDS");
- public static final int CHUNK_NHSG = type("NHSG");
public static final int CHUNK_HPGC = type("HPGC");
- public static final int CHUNK_REAE = type("REAE");
- public static final int CHUNK_REAQ = type("REAQ");
- public static final int CHUNK_REAL = type("REAL");
private static DdmHandleHeap mInstance = new DdmHandleHeap();
@@ -50,15 +42,7 @@
* Register for the messages we're interested in.
*/
public static void register() {
- DdmServer.registerHandler(CHUNK_HPIF, mInstance);
- DdmServer.registerHandler(CHUNK_HPSG, mInstance);
- DdmServer.registerHandler(CHUNK_HPDU, mInstance);
- DdmServer.registerHandler(CHUNK_HPDS, mInstance);
- DdmServer.registerHandler(CHUNK_NHSG, mInstance);
DdmServer.registerHandler(CHUNK_HPGC, mInstance);
- DdmServer.registerHandler(CHUNK_REAE, mInstance);
- DdmServer.registerHandler(CHUNK_REAQ, mInstance);
- DdmServer.registerHandler(CHUNK_REAL, mInstance);
}
/**
@@ -81,24 +65,8 @@
Log.v("ddm-heap", "Handling " + name(request.type) + " chunk");
int type = request.type;
- if (type == CHUNK_HPIF) {
- return handleHPIF(request);
- } else if (type == CHUNK_HPSG) {
- return handleHPSGNHSG(request, false);
- } else if (type == CHUNK_HPDU) {
- return handleHPDU(request);
- } else if (type == CHUNK_HPDS) {
- return handleHPDS(request);
- } else if (type == CHUNK_NHSG) {
- return handleHPSGNHSG(request, true);
- } else if (type == CHUNK_HPGC) {
+ if (type == CHUNK_HPGC) {
return handleHPGC(request);
- } else if (type == CHUNK_REAE) {
- return handleREAE(request);
- } else if (type == CHUNK_REAQ) {
- return handleREAQ(request);
- } else if (type == CHUNK_REAL) {
- return handleREAL(request);
} else {
throw new RuntimeException("Unknown packet "
+ ChunkHandler.name(type));
@@ -106,112 +74,6 @@
}
/*
- * Handle a "HeaP InFo" request.
- */
- private Chunk handleHPIF(Chunk request) {
- ByteBuffer in = wrapChunk(request);
-
- int when = in.get();
- if (false)
- Log.v("ddm-heap", "Heap segment enable: when=" + when);
-
- boolean ok = DdmVmInternal.heapInfoNotify(when);
- if (!ok) {
- return createFailChunk(1, "Unsupported HPIF what");
- } else {
- return null; // empty response
- }
- }
-
- /*
- * Handle a "HeaP SeGment" or "Native Heap SeGment" request.
- */
- private Chunk handleHPSGNHSG(Chunk request, boolean isNative) {
- ByteBuffer in = wrapChunk(request);
-
- int when = in.get();
- int what = in.get();
- if (false)
- Log.v("ddm-heap", "Heap segment enable: when=" + when
- + ", what=" + what + ", isNative=" + isNative);
-
- boolean ok = DdmVmInternal.heapSegmentNotify(when, what, isNative);
- if (!ok) {
- return createFailChunk(1, "Unsupported HPSG what/when");
- } else {
- // TODO: if "when" is non-zero and we want to see a dump
- // right away, initiate a GC.
- return null; // empty response
- }
- }
-
- /*
- * Handle a "HeaP DUmp" request.
- *
- * This currently just returns a result code. We could pull up
- * the entire contents of the file and return them, but hprof dump
- * files can be a few megabytes.
- */
- private Chunk handleHPDU(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- byte result;
-
- /* get the filename for the output file */
- int len = in.getInt();
- String fileName = getString(in, len);
- if (false)
- Log.d("ddm-heap", "Heap dump: file='" + fileName + "'");
-
- try {
- Debug.dumpHprofData(fileName);
- result = 0;
- } catch (UnsupportedOperationException uoe) {
- Log.w("ddm-heap", "hprof dumps not supported in this VM");
- result = -1;
- } catch (IOException ioe) {
- result = -1;
- } catch (RuntimeException re) {
- result = -1;
- }
-
- /* create a non-empty reply so the handler fires on completion */
- byte[] reply = { result };
- return new Chunk(CHUNK_HPDU, reply, 0, reply.length);
- }
-
- /*
- * Handle a "HeaP Dump Streaming" request.
- *
- * This tells the VM to create a heap dump and send it directly to
- * DDMS. The dumps are large enough that we don't want to copy the
- * data into a byte[] and send it from here.
- */
- private Chunk handleHPDS(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- byte result;
-
- /* get the filename for the output file */
- if (false)
- Log.d("ddm-heap", "Heap dump: [DDMS]");
-
- String failMsg = null;
- try {
- Debug.dumpHprofDataDdms();
- } catch (UnsupportedOperationException uoe) {
- failMsg = "hprof dumps not supported in this VM";
- } catch (RuntimeException re) {
- failMsg = "Exception: " + re.getMessage();
- }
-
- if (failMsg != null) {
- Log.w("ddm-heap", failMsg);
- return createFailChunk(1, failMsg);
- } else {
- return null;
- }
- }
-
- /*
* Handle a "HeaP Garbage Collection" request.
*/
private Chunk handleHPGC(Chunk request) {
@@ -223,47 +85,4 @@
return null; // empty response
}
-
- /*
- * Handle a "REcent Allocation Enable" request.
- */
- private Chunk handleREAE(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- boolean enable;
-
- enable = (in.get() != 0);
-
- if (false)
- Log.d("ddm-heap", "Recent allocation enable request: " + enable);
-
- DdmVmInternal.enableRecentAllocations(enable);
-
- return null; // empty response
- }
-
- /*
- * Handle a "REcent Allocation Query" request.
- */
- private Chunk handleREAQ(Chunk request) {
- //ByteBuffer in = wrapChunk(request);
-
- byte[] reply = new byte[1];
- reply[0] = DdmVmInternal.getRecentAllocationStatus() ? (byte)1 :(byte)0;
- return new Chunk(CHUNK_REAQ, reply, 0, reply.length);
- }
-
- /*
- * Handle a "REcent ALlocations" request.
- */
- private Chunk handleREAL(Chunk request) {
- //ByteBuffer in = wrapChunk(request);
-
- if (false)
- Log.d("ddm-heap", "Recent allocations request");
-
- /* generate the reply in a ready-to-go format */
- byte[] reply = DdmVmInternal.getRecentAllocations();
- return new Chunk(CHUNK_REAL, reply, 0, reply.length);
- }
}
-
diff --git a/core/java/android/ddm/DdmHandleThread.java b/core/java/android/ddm/DdmHandleThread.java
deleted file mode 100644
index 613ab75..0000000
--- a/core/java/android/ddm/DdmHandleThread.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.ddm;
-
-import org.apache.harmony.dalvik.ddmc.Chunk;
-import org.apache.harmony.dalvik.ddmc.ChunkHandler;
-import org.apache.harmony.dalvik.ddmc.DdmServer;
-import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
-import android.util.Log;
-import java.nio.ByteBuffer;
-
-/**
- * Handle thread-related traffic.
- */
-public class DdmHandleThread extends ChunkHandler {
-
- public static final int CHUNK_THEN = type("THEN");
- public static final int CHUNK_THCR = type("THCR");
- public static final int CHUNK_THDE = type("THDE");
- public static final int CHUNK_THST = type("THST");
- public static final int CHUNK_STKL = type("STKL");
-
- private static DdmHandleThread mInstance = new DdmHandleThread();
-
-
- /* singleton, do not instantiate */
- private DdmHandleThread() {}
-
- /**
- * Register for the messages we're interested in.
- */
- public static void register() {
- DdmServer.registerHandler(CHUNK_THEN, mInstance);
- DdmServer.registerHandler(CHUNK_THST, mInstance);
- DdmServer.registerHandler(CHUNK_STKL, mInstance);
- }
-
- /**
- * Called when the DDM server connects. The handler is allowed to
- * send messages to the server.
- */
- public void connected() {}
-
- /**
- * Called when the DDM server disconnects. Can be used to disable
- * periodic transmissions or clean up saved state.
- */
- public void disconnected() {}
-
- /**
- * Handle a chunk of data.
- */
- public Chunk handleChunk(Chunk request) {
- if (false)
- Log.v("ddm-thread", "Handling " + name(request.type) + " chunk");
- int type = request.type;
-
- if (type == CHUNK_THEN) {
- return handleTHEN(request);
- } else if (type == CHUNK_THST) {
- return handleTHST(request);
- } else if (type == CHUNK_STKL) {
- return handleSTKL(request);
- } else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
- }
- }
-
- /*
- * Handle a "THread notification ENable" request.
- */
- private Chunk handleTHEN(Chunk request) {
- ByteBuffer in = wrapChunk(request);
-
- boolean enable = (in.get() != 0);
- //Log.i("ddm-thread", "Thread notify enable: " + enable);
-
- DdmVmInternal.threadNotify(enable);
- return null; // empty response
- }
-
- /*
- * Handle a "THread STatus" request. This is constructed by the VM.
- */
- private Chunk handleTHST(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- // currently nothing to read from "in"
-
- //Log.d("ddm-thread", "Thread status request");
-
- byte[] status = DdmVmInternal.getThreadStats();
- if (status != null)
- return new Chunk(CHUNK_THST, status, 0, status.length);
- else
- return createFailChunk(1, "Can't build THST chunk");
- }
-
- /*
- * Handle a STacK List request.
- *
- * This is done by threadId, which isn't great since those are
- * recycled. We need a thread serial ID. The Linux tid is an okay
- * answer as it's unlikely to recycle at the exact wrong moment.
- * However, we're using the short threadId in THST messages, so we
- * use them here for consistency. (One thought is to keep the current
- * thread ID in the low 16 bits and somehow serialize the top 16 bits.)
- */
- private Chunk handleSTKL(Chunk request) {
- ByteBuffer in = wrapChunk(request);
- int threadId;
-
- threadId = in.getInt();
-
- //Log.d("ddm-thread", "Stack list request " + threadId);
-
- StackTraceElement[] trace = DdmVmInternal.getStackTraceById(threadId);
- if (trace == null) {
- return createFailChunk(1, "Stack trace unavailable");
- } else {
- return createStackChunk(trace, threadId);
- }
- }
-
- /*
- * Serialize a StackTraceElement[] into an STKL chunk.
- *
- * We include the threadId in the response so the other side doesn't have
- * to match up requests and responses as carefully.
- */
- private Chunk createStackChunk(StackTraceElement[] trace, int threadId) {
- int bufferSize = 0;
-
- bufferSize += 4; // version, flags, whatever
- bufferSize += 4; // thread ID
- bufferSize += 4; // frame count
- for (StackTraceElement elem : trace) {
- bufferSize += 4 + elem.getClassName().length() * 2;
- bufferSize += 4 + elem.getMethodName().length() * 2;
- bufferSize += 4;
- if (elem.getFileName() != null)
- bufferSize += elem.getFileName().length() * 2;
- bufferSize += 4; // line number
- }
-
- ByteBuffer out = ByteBuffer.allocate(bufferSize);
- out.putInt(0);
- out.putInt(threadId);
- out.putInt(trace.length);
- for (StackTraceElement elem : trace) {
- out.putInt(elem.getClassName().length());
- putString(out, elem.getClassName());
- out.putInt(elem.getMethodName().length());
- putString(out, elem.getMethodName());
- if (elem.getFileName() != null) {
- out.putInt(elem.getFileName().length());
- putString(out, elem.getFileName());
- } else {
- out.putInt(0);
- }
- out.putInt(elem.getLineNumber());
- }
-
- return new Chunk(CHUNK_STKL, out);
- }
-}
-
diff --git a/core/java/android/ddm/DdmRegister.java b/core/java/android/ddm/DdmRegister.java
index e0faa51..ca10312 100644
--- a/core/java/android/ddm/DdmRegister.java
+++ b/core/java/android/ddm/DdmRegister.java
@@ -16,9 +16,10 @@
package android.ddm;
-import org.apache.harmony.dalvik.ddmc.DdmServer;
import android.util.Log;
+import org.apache.harmony.dalvik.ddmc.DdmServer;
+
/**
* Just a place to stick handler registrations, instead of scattering
* them around.
@@ -46,7 +47,6 @@
if (false)
Log.v("ddm", "Registering DDM message handlers");
DdmHandleHello.register();
- DdmHandleThread.register();
DdmHandleHeap.register();
DdmHandleNativeHeap.register();
DdmHandleProfiling.register();
diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java
index 7bf692f..fa2ccbc 100644
--- a/core/java/android/graphics/fonts/FontManager.java
+++ b/core/java/android/graphics/fonts/FontManager.java
@@ -195,6 +195,7 @@
* @return The current font configuration. null if failed to fetch information from the system
* service.
*/
+ @RequiresPermission(Manifest.permission.UPDATE_FONTS)
public @NonNull FontConfig getFontConfig() {
try {
return mIFontManager.getFontConfig();
diff --git a/core/java/android/hardware/SensorPrivacyManagerInternal.java b/core/java/android/hardware/SensorPrivacyManagerInternal.java
new file mode 100644
index 0000000..d12e9f8
--- /dev/null
+++ b/core/java/android/hardware/SensorPrivacyManagerInternal.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * SensorPrivacyManager calls for within the system server
+ * @hide
+ */
+public abstract class SensorPrivacyManagerInternal {
+
+ /**
+ * A class implementing this interface can register to receive a callback when state changes.
+ */
+ public interface OnSensorPrivacyChangedListener {
+ /**
+ * The callback invoked when the state changes.
+ */
+ void onSensorPrivacyChanged(boolean enabled);
+ }
+
+ /**
+ * A class implementing this interface can register to receive a callback when state changes for
+ * any user.
+ */
+ public interface OnUserSensorPrivacyChangedListener {
+ /**
+ * The callback invoked when the state changes.
+ */
+ void onSensorPrivacyChanged(int userId, boolean enabled);
+ }
+
+ /**
+ * Get the individual sensor privacy state for a given user.
+ */
+ public abstract boolean isSensorPrivacyEnabled(int userId, int sensor);
+
+ /**
+ * Registers a new listener to receive notification when the state of sensor privacy
+ * changes.
+ */
+ public abstract void addSensorPrivacyListener(int userId, int sensor,
+ OnSensorPrivacyChangedListener listener);
+
+ /**
+ * Registers a new listener to receive notification when the state of sensor privacy
+ * changes for any user.
+ */
+ public abstract void addSensorPrivacyListenerForAllUsers(int sensor,
+ OnUserSensorPrivacyChangedListener listener);
+}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 788afe3..365dea6 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -65,7 +65,7 @@
private static final int CAPPED_SAMPLING_RATE_LEVEL = SensorDirectChannel.RATE_NORMAL;
private static final String HIGH_SAMPLING_RATE_SENSORS_PERMISSION =
- "android.permisison.HIGH_SAMPLING_RATE_SENSORS";
+ "android.permission.HIGH_SAMPLING_RATE_SENSORS";
/**
* For apps targeting S and above, a SecurityException is thrown when they do not have
* HIGH_SAMPLING_RATE_SENSORS permission, run in debug mode, and request sampling rates that
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 8ebf757..062438c 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -73,7 +73,8 @@
public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
- private static final Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ private static final Map<
+ VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
@NonNull private final Context mContext;
@@ -93,13 +94,13 @@
}
/**
- * Get all currently registered VcnNetworkPolicyListeners for testing purposes.
+ * Get all currently registered VcnNetworkPolicyChangeListeners for testing purposes.
*
* @hide
*/
@VisibleForTesting(visibility = Visibility.PRIVATE)
@NonNull
- public static Map<VcnNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ public static Map<VcnNetworkPolicyChangeListener, VcnUnderlyingNetworkPolicyListenerBinder>
getAllPolicyListeners() {
return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS);
}
@@ -162,14 +163,14 @@
}
// TODO(b/180537630): remove all VcnUnderlyingNetworkPolicyListener refs once Telephony is using
- // the new VcnNetworkPolicyListener API
+ // the new VcnNetworkPolicyChangeListener API
/**
* VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
* can register to receive updates for VCN-underlying Network policies from the System Server.
*
* @hide
*/
- public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyListener {}
+ public interface VcnUnderlyingNetworkPolicyListener extends VcnNetworkPolicyChangeListener {}
/**
* Add a listener for VCN-underlying network policy updates.
@@ -185,7 +186,7 @@
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public void addVcnUnderlyingNetworkPolicyListener(
@NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
- addVcnNetworkPolicyListener(executor, listener);
+ addVcnNetworkPolicyChangeListener(executor, listener);
}
/**
@@ -198,7 +199,7 @@
*/
public void removeVcnUnderlyingNetworkPolicyListener(
@NonNull VcnUnderlyingNetworkPolicyListener listener) {
- removeVcnNetworkPolicyListener(listener);
+ removeVcnNetworkPolicyChangeListener(listener);
}
/**
@@ -233,20 +234,20 @@
}
/**
- * VcnNetworkPolicyListener is the interface through which internal system components (e.g.
- * Network Factories) can register to receive updates for VCN-underlying Network policies from
- * the System Server.
+ * VcnNetworkPolicyChangeListener is the interface through which internal system components
+ * (e.g. Network Factories) can register to receive updates for VCN-underlying Network policies
+ * from the System Server.
*
* <p>Any Network Factory that brings up Networks capable of being VCN-underlying Networks
- * should register a VcnNetworkPolicyListener. VcnManager will then use this listener to notify
- * the registrant when VCN Network policies change. Upon receiving this signal, the listener
- * must check {@link VcnManager} for the current Network policy result for each of its Networks
- * via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
+ * should register a VcnNetworkPolicyChangeListener. VcnManager will then use this listener to
+ * notify the registrant when VCN Network policies change. Upon receiving this signal, the
+ * listener must check {@link VcnManager} for the current Network policy result for each of its
+ * Networks via {@link #applyVcnNetworkPolicy(NetworkCapabilities, LinkProperties)}.
*
* @hide
*/
@SystemApi
- public interface VcnNetworkPolicyListener {
+ public interface VcnNetworkPolicyChangeListener {
/**
* Notifies the implementation that the VCN's underlying Network policy has changed.
*
@@ -260,20 +261,21 @@
/**
* Add a listener for VCN-underlying Network policy updates.
*
- * <p>A {@link VcnNetworkPolicyListener} is eligible to begin receiving callbacks once it is
- * registered. No callbacks are guaranteed upon registration.
+ * <p>A {@link VcnNetworkPolicyChangeListener} is eligible to begin receiving callbacks once it
+ * is registered. No callbacks are guaranteed upon registration.
*
* @param executor the Executor that will be used for invoking all calls to the specified
* Listener
- * @param listener the VcnNetworkPolicyListener to be added
+ * @param listener the VcnNetworkPolicyChangeListener to be added
* @throws SecurityException if the caller does not have permission NETWORK_FACTORY
- * @throws IllegalStateException if the specified VcnNetworkPolicyListener is already registered
+ * @throws IllegalStateException if the specified VcnNetworkPolicyChangeListener is already
+ * registered
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public void addVcnNetworkPolicyListener(
- @NonNull Executor executor, @NonNull VcnNetworkPolicyListener listener) {
+ public void addVcnNetworkPolicyChangeListener(
+ @NonNull Executor executor, @NonNull VcnNetworkPolicyChangeListener listener) {
requireNonNull(executor, "executor must not be null");
requireNonNull(listener, "listener must not be null");
@@ -292,15 +294,18 @@
}
/**
- * Remove the specified VcnNetworkPolicyListener from VcnManager.
+ * Remove the specified VcnNetworkPolicyChangeListener from VcnManager.
*
* <p>If the specified listener is not currently registered, this is a no-op.
*
- * @param listener the VcnNetworkPolicyListener that will be removed
+ * @param listener the VcnNetworkPolicyChangeListener that will be removed
+ * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
* @hide
*/
@SystemApi
- public void removeVcnNetworkPolicyListener(@NonNull VcnNetworkPolicyListener listener) {
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public void removeVcnNetworkPolicyChangeListener(
+ @NonNull VcnNetworkPolicyChangeListener listener) {
requireNonNull(listener, "listener must not be null");
VcnUnderlyingNetworkPolicyListenerBinder binder =
@@ -320,8 +325,9 @@
* Applies the network policy for a {@link android.net.Network} with the given parameters.
*
* <p>Prior to a new NetworkAgent being registered, or upon notification that Carrier VCN policy
- * may have changed via {@link VcnNetworkPolicyListener#onPolicyChanged()}, a Network Provider
- * MUST poll for the updated Network policy based on that Network's capabilities and properties.
+ * may have changed via {@link VcnNetworkPolicyChangeListener#onPolicyChanged()}, a Network
+ * Provider MUST poll for the updated Network policy based on that Network's capabilities and
+ * properties.
*
* @param networkCapabilities the NetworkCapabilities to be used in determining the Network
* policy result for this Network.
@@ -532,17 +538,18 @@
}
/**
- * Binder wrapper for added VcnNetworkPolicyListeners to receive signals from System Server.
+ * Binder wrapper for added VcnNetworkPolicyChangeListeners to receive signals from System
+ * Server.
*
* @hide
*/
private static class VcnUnderlyingNetworkPolicyListenerBinder
extends IVcnUnderlyingNetworkPolicyListener.Stub {
@NonNull private final Executor mExecutor;
- @NonNull private final VcnNetworkPolicyListener mListener;
+ @NonNull private final VcnNetworkPolicyChangeListener mListener;
private VcnUnderlyingNetworkPolicyListenerBinder(
- Executor executor, VcnNetworkPolicyListener listener) {
+ Executor executor, VcnNetworkPolicyChangeListener listener) {
mExecutor = executor;
mListener = listener;
}
diff --git a/core/java/android/os/BatteryManagerInternal.java b/core/java/android/os/BatteryManagerInternal.java
index a86237d..97ec594 100644
--- a/core/java/android/os/BatteryManagerInternal.java
+++ b/core/java/android/os/BatteryManagerInternal.java
@@ -83,4 +83,29 @@
* wait on the battery service lock.
*/
public abstract int getInvalidCharger();
+
+ /**
+ * Sets battery AC charger to enabled/disabled, and freezes the battery state.
+ */
+ public abstract void setChargerAcOnline(boolean online, boolean forceUpdate);
+
+ /**
+ * Sets battery level, and freezes the battery state.
+ */
+ public abstract void setBatteryLevel(int level, boolean forceUpdate);
+
+ /**
+ * Unplugs battery, and freezes the battery state.
+ */
+ public abstract void unplugBattery(boolean forceUpdate);
+
+ /**
+ * Unfreezes battery state, returning to current hardware values.
+ */
+ public abstract void resetBattery(boolean forceUpdate);
+
+ /**
+ * Suspend charging even if plugged in.
+ */
+ public abstract void suspendBatteryInput();
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 66f7bd9..4c26e2f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -995,6 +995,15 @@
public abstract long getScreenOnMeasuredBatteryConsumptionUC();
/**
+ * Returns the battery consumption (in microcoulombs) of the uid's cpu usage, derived from
+ * on device power measurement data.
+ * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+ *
+ * {@hide}
+ */
+ public abstract long getCpuMeasuredBatteryConsumptionUC();
+
+ /**
* Returns the battery consumption (in microcoulombs) used by this uid for each
* {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
* type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
@@ -2521,6 +2530,15 @@
public abstract long getScreenDozeMeasuredBatteryConsumptionUC();
/**
+ * Returns the battery consumption (in microcoulombs) of the cpu, derived from on device power
+ * measurement data.
+ * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+ *
+ * {@hide}
+ */
+ public abstract long getCpuMeasuredBatteryConsumptionUC();
+
+ /**
* Returns the battery consumption (in microcoulombs) that each
* {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
* type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}) consumed.
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 1905d70..e47478a 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -23,6 +23,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.net.NetworkStack;
import android.os.connectivity.CellularBatteryStats;
@@ -487,4 +488,74 @@
return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
: DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
}
-}
+
+ /**
+ * Sets battery AC charger to enabled/disabled, and freezes the battery state.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void setChargerAcOnline(boolean online, boolean forceUpdate) {
+ try {
+ mBatteryStats.setChargerAcOnline(online, forceUpdate);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets battery level, and freezes the battery state.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void setBatteryLevel(int level, boolean forceUpdate) {
+ try {
+ mBatteryStats.setBatteryLevel(level, forceUpdate);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unplugs battery, and freezes the battery state.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void unplugBattery(boolean forceUpdate) {
+ try {
+ mBatteryStats.unplugBattery(forceUpdate);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unfreezes battery state, returning to current hardware values.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void resetBattery(boolean forceUpdate) {
+ try {
+ mBatteryStats.resetBattery(forceUpdate);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Suspend charging even if plugged in.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+ public void suspendBatteryInput() {
+ try {
+ mBatteryStats.suspendBatteryInput();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 83f78a5..0d9f715 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -27,6 +27,7 @@
import android.app.Application;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.sysprop.DeviceProperties;
import android.sysprop.SocProperties;
import android.sysprop.TelephonyProperties;
import android.text.TextUtils;
@@ -298,6 +299,19 @@
"ro.build.version.security_patch", "");
/**
+ * The media performance class of the device or 0 if none.
+ * <p>
+ * If this value is not <code>0</code>, the device conforms to the media performance class
+ * definition of the SDK version of this value. This value never changes while a device is
+ * booted, but it may increase when the hardware manufacturer provides an OTA update.
+ * <p>
+ * Possible non-zero values are defined in {@link Build.VERSION_CODES} starting with
+ * {@link Build.VERSION_CODES#S}.
+ */
+ public static final int MEDIA_PERFORMANCE_CLASS =
+ DeviceProperties.media_performance_class().orElse(0);
+
+ /**
* The user-visible SDK version of the framework in its raw String
* representation; use {@link #SDK_INT} instead.
*
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 124c0b0..21bf8b8 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -728,11 +728,11 @@
/**
* Standard directory in which to place any audio files that should be
* in the regular list of music for the user.
- * This may be combined with
+ * This may be combined with {@link #DIRECTORY_AUDIOBOOKS},
* {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
- * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+ * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+ * categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_MUSIC = "Music";
@@ -741,10 +741,10 @@
* in the list of podcasts that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_NOTIFICATIONS},
- * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_NOTIFICATIONS},
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+ * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+ * categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_PODCASTS = "Podcasts";
@@ -753,10 +753,10 @@
* in the list of ringtones that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
- * {@link #DIRECTORY_ALARMS} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
+ * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_RINGTONES = "Ringtones";
@@ -765,10 +765,10 @@
* in the list of alarms that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
- * and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_RINGTONES},
+ * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_ALARMS = "Alarms";
@@ -777,10 +777,10 @@
* in the list of notifications that the user can select (not as regular
* music).
* This may be combined with {@link #DIRECTORY_MUSIC},
- * {@link #DIRECTORY_PODCASTS},
- * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
- * of directories to categories a particular audio file as more than one
- * type.
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES}, and
+ * {@link #DIRECTORY_RECORDINGS} as a series of directories to
+ * categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
@@ -831,14 +831,26 @@
public static String DIRECTORY_SCREENSHOTS = "Screenshots";
/**
- * Standard directory in which to place any audio files which are
- * audiobooks.
+ * Standard directory in which to place any audio files that should be
+ * in the list of audiobooks that the user can select (not as regular
+ * music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
+ * {@link #DIRECTORY_ALARMS}, {@link #DIRECTORY_RINGTONES},
+ * and {@link #DIRECTORY_RECORDINGS} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
public static String DIRECTORY_AUDIOBOOKS = "Audiobooks";
/**
- * Standard directory in which to place any audio files which are
- * recordings.
+ * Standard directory in which to place any audio files that should be
+ * in the list of voice recordings recorded by voice recorder apps that
+ * the user can select (not as regular music).
+ * This may be combined with {@link #DIRECTORY_MUSIC},
+ * {@link #DIRECTORY_AUDIOBOOKS}, {@link #DIRECTORY_PODCASTS},
+ * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_ALARMS},
+ * and {@link #DIRECTORY_RINGTONES} as a series of directories
+ * to categorize a particular audio file as more than one type.
*/
@NonNull
// The better way is that expose a static method getRecordingDirectories.
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index dc6f63a..047c05a 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -30,6 +30,7 @@
import com.android.internal.annotations.GuardedBy;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -265,6 +266,13 @@
}
/**
+ * Checks if an fd corresponds to a file on a mounted Incremental File System.
+ */
+ public static boolean isIncrementalFileFd(@NonNull FileDescriptor fd) {
+ return nativeIsIncrementalFd(fd.getInt$());
+ }
+
+ /**
* Returns raw signature for file if it's on Incremental File System.
* Unsafe, use only if you are sure what you are doing.
*/
@@ -421,9 +429,22 @@
storage.unregisterStorageHealthListener();
}
+ /**
+ * Returns the metrics of an Incremental Storage.
+ */
+ public IncrementalMetrics getMetrics(@NonNull String codePath) {
+ final IncrementalStorage storage = openStorage(codePath);
+ if (storage == null) {
+ // storage does not exist, package not installed
+ return null;
+ }
+ return new IncrementalMetrics(storage.getMetrics());
+ }
+
/* Native methods */
private static native boolean nativeIsEnabled();
private static native boolean nativeIsV2Available();
private static native boolean nativeIsIncrementalPath(@NonNull String path);
+ private static native boolean nativeIsIncrementalFd(@NonNull int fd);
private static native byte[] nativeUnsafeGetFileSignature(@NonNull String path);
}
diff --git a/core/java/android/os/incremental/IncrementalMetrics.java b/core/java/android/os/incremental/IncrementalMetrics.java
new file mode 100644
index 0000000..44dea1b
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalMetrics.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.annotation.NonNull;
+import android.os.PersistableBundle;
+
+/**
+ * Provides methods to access metrics about an app installed via Incremental
+ * @hide
+ */
+public class IncrementalMetrics {
+ @NonNull private final PersistableBundle mData;
+
+ public IncrementalMetrics(@NonNull PersistableBundle data) {
+ mData = data;
+ }
+
+ /**
+ * @return Milliseconds between now and when the oldest pending read happened
+ */
+ public long getMillisSinceOldestPendingRead() {
+ return mData.getLong(IIncrementalService.METRICS_MILLIS_SINCE_OLDEST_PENDING_READ, -1);
+ }
+}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index e6ce8cd..7cf0144 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.pm.DataLoaderParams;
import android.content.pm.IDataLoaderStatusListener;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import java.io.File;
@@ -601,4 +602,17 @@
return;
}
}
+
+ /**
+ * Returns the metrics of the current storage.
+ * {@see IIncrementalService} for metrics keys.
+ */
+ public PersistableBundle getMetrics() {
+ try {
+ return mService.getMetrics(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 8a4812a..374de9c 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5310,5 +5310,12 @@
* @hide
*/
public static final String COLUMN_VOIMS_OPT_IN_STATUS = "voims_opt_in_status";
+
+ /**
+ * TelephonyProvider column name for device to device sharing status.
+ *
+ * @hide
+ */
+ public static final String COLUMN_D2D_STATUS_SHARING = "d2d_sharing_status";
}
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index c1d9d58..def13db 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -41,10 +41,12 @@
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SharedMemory;
import android.util.Slog;
import com.android.internal.app.IHotwordRecognitionStatusCallback;
@@ -287,6 +289,7 @@
private final Handler mHandler;
private final IBinder mBinder = new Binder();
private final int mTargetSdkVersion;
+ private final boolean mSupportHotwordDetectionService;
private int mAvailability = STATE_NOT_READY;
@@ -488,11 +491,22 @@
* @param callback A non-null Callback for receiving the recognition events.
* @param modelManagementService A service that allows management of sound models.
* @param targetSdkVersion The target SDK version.
+ * @param supportHotwordDetectionService {@code true} if hotword detection service should be
+ * triggered, otherwise {@code false}.
+ * @param options Application configuration data provided by the
+ * {@link VoiceInteractionService}. The system strips out any remotable objects or other
+ * contents that can be used to communicate with other processes.
+ * @param sharedMemory The unrestricted data blob provided by the
+ * {@link VoiceInteractionService}. Use this to provide the hotword models data or other
+ * such data to the trusted process.
+ *
* @hide
*/
public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
- IVoiceInteractionManagerService modelManagementService, int targetSdkVersion) {
+ IVoiceInteractionManagerService modelManagementService, int targetSdkVersion,
+ boolean supportHotwordDetectionService, @Nullable Bundle options,
+ @Nullable SharedMemory sharedMemory) {
mText = text;
mLocale = locale;
mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
@@ -501,6 +515,10 @@
mInternalCallback = new SoundTriggerListener(mHandler);
mModelManagementService = modelManagementService;
mTargetSdkVersion = targetSdkVersion;
+ mSupportHotwordDetectionService = supportHotwordDetectionService;
+ if (mSupportHotwordDetectionService) {
+ setHotwordDetectionServiceConfig(options, sharedMemory);
+ }
try {
Identity identity = new Identity();
identity.packageName = ActivityThread.currentOpPackageName();
@@ -513,6 +531,38 @@
}
/**
+ * Set configuration and pass read-only data to hotword detection service.
+ *
+ * @param options Application configuration data provided by the
+ * {@link VoiceInteractionService}. The system strips out any remotable objects or other
+ * contents that can be used to communicate with other processes.
+ * @param sharedMemory The unrestricted data blob provided by the
+ * {@link VoiceInteractionService}. Use this to provide the hotword models data or other
+ * such data to the trusted process.
+ *
+ * @throws IllegalStateException if it doesn't support hotword detection service.
+ *
+ * @hide
+ */
+ public final void setHotwordDetectionServiceConfig(@Nullable Bundle options,
+ @Nullable SharedMemory sharedMemory) {
+ if (DBG) {
+ Slog.d(TAG, "setHotwordDetectionServiceConfig()");
+ }
+ if (!mSupportHotwordDetectionService) {
+ throw new IllegalStateException(
+ "setHotwordDetectionServiceConfig called, but it doesn't support hotword"
+ + " detection service");
+ }
+
+ try {
+ mModelManagementService.setHotwordDetectionServiceConfig(options, sharedMemory);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Gets the recognition modes supported by the associated keyphrase.
*
* @see #RECOGNITION_MODE_USER_IDENTIFICATION
@@ -839,6 +889,14 @@
synchronized (mLock) {
mAvailability = STATE_INVALID;
notifyStateChangedLocked();
+
+ if (mSupportHotwordDetectionService) {
+ try {
+ mModelManagementService.shutdownHotwordDetectionService();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
}
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 7f1c5ff96..fcef26f 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -27,13 +27,17 @@
import android.app.Service;
import android.content.Intent;
import android.media.AudioFormat;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.os.SharedMemory;
import android.util.Log;
+import java.util.Locale;
+
/**
* Implemented by an application that wants to offer detection for hotword. The system will
* start the service after calling {@link VoiceInteractionService#setHotwordDetectionConfig}.
@@ -76,6 +80,17 @@
timeoutMillis,
new DspHotwordDetectionCallback(callback)));
}
+
+ @Override
+ public void setConfig(Bundle options, SharedMemory sharedMemory) throws RemoteException {
+ if (DBG) {
+ Log.d(TAG, "#setConfig");
+ }
+ mHandler.sendMessage(obtainMessage(HotwordDetectionService::onUpdateState,
+ HotwordDetectionService.this,
+ options,
+ sharedMemory));
+ }
};
@CallSuper
@@ -121,6 +136,25 @@
}
/**
+ * Called when the {@link VoiceInteractionService#createAlwaysOnHotwordDetector(String, Locale,
+ * Bundle, SharedMemory, AlwaysOnHotwordDetector.Callback)} or {@link AlwaysOnHotwordDetector#
+ * setHotwordDetectionServiceConfig(Bundle, SharedMemory)} requests an update of the hotword
+ * detection parameters.
+ *
+ * @param options Application configuration data provided by the
+ * {@link VoiceInteractionService}. The system strips out any remotable objects or other
+ * contents that can be used to communicate with other processes.
+ * @param sharedMemory The unrestricted data blob provided by the
+ * {@link VoiceInteractionService}. Use this to provide the hotword models data or other
+ * such data to the trusted process.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void onUpdateState(@Nullable Bundle options, @Nullable SharedMemory sharedMemory) {
+ }
+
+ /**
* Callback for returning the detected result.
*
* @hide
diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl
index cbe76e4..8f0874a 100644
--- a/core/java/android/service/voice/IHotwordDetectionService.aidl
+++ b/core/java/android/service/voice/IHotwordDetectionService.aidl
@@ -17,7 +17,9 @@
package android.service.voice;
import android.media.AudioFormat;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
+import android.os.SharedMemory;
import android.service.voice.IDspHotwordDetectionCallback;
/**
@@ -31,4 +33,6 @@
in AudioFormat audioFormat,
long timeoutMillis,
in IDspHotwordDetectionCallback callback);
+
+ void setConfig(in Bundle options, in SharedMemory sharedMemory);
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 25f8090..048d9f5 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -17,7 +17,6 @@
package android.service.voice;
import android.Manifest;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -36,6 +35,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SharedMemory;
import android.provider.Settings;
import android.util.ArraySet;
import android.util.Log;
@@ -47,8 +47,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -73,32 +71,6 @@
static final String TAG = VoiceInteractionService.class.getSimpleName();
/**
- * Indicates that the given configs have been set successfully after calling
- * {@link VoiceInteractionService#setHotwordDetectionConfig}.
- *
- * @hide
- */
- @SystemApi
- public static final int HOTWORD_CONFIG_SUCCESS = 0;
-
- /**
- * Indicates that the given configs have been set unsuccessfully after calling
- * {@link VoiceInteractionService#setHotwordDetectionConfig}.
- *
- * @hide
- */
- @SystemApi
- public static final int HOTWORD_CONFIG_FAILURE = 1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "HOTWORD_CONFIG_" }, value = {
- HOTWORD_CONFIG_SUCCESS,
- HOTWORD_CONFIG_FAILURE,
- })
- public @interface HotwordConfigResult {}
-
- /**
* The {@link Intent} that must be declared as handled by the service.
* To be supported, the service must also require the
* {@link android.Manifest.permission#BIND_VOICE_INTERACTION} permission so
@@ -330,35 +302,6 @@
}
/**
- * Set hotword detection configuration.
- *
- * Note: Currently it will trigger hotword detection service after calling this function when
- * all conditions meet the requirements.
- *
- * @param options Config data.
- * @return {@link VoiceInteractionService#HOTWORD_CONFIG_SUCCESS} in case of success,
- * {@link VoiceInteractionService#HOTWORD_CONFIG_FAILURE} in case of failure.
- *
- * @throws IllegalStateException if the function is called before onReady() is called.
- *
- * @hide
- */
- @SystemApi
- @HotwordConfigResult
- public final int setHotwordDetectionConfig(
- @SuppressLint("NullableCollection") @Nullable Bundle options) {
- if (mSystemService == null) {
- throw new IllegalStateException("Not available until onReady() is called");
- }
-
- try {
- return mSystemService.setHotwordDetectionConfig(options);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale.
* This instance must be retained and used by the client.
* Calling this a second time invalidates the previously created hotword detector
@@ -374,9 +317,61 @@
@SystemApi
@NonNull
public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
- @SuppressLint("MissingNullability") String keyphrase, // TODO: annotate nullability properly
+ @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly
@SuppressLint({"MissingNullability", "UseIcu"}) Locale locale,
@SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) {
+ return createAlwaysOnHotwordDetectorInternal(keyphrase, locale,
+ /* supportHotwordDetectionService= */ false, /* options= */ null,
+ /* sharedMemory= */ null, callback);
+ }
+
+ /**
+ * Create an {@link AlwaysOnHotwordDetector} and trigger a {@link HotwordDetectionService}
+ * service, then it will also pass the read-only data to hotword detection service.
+ *
+ * Like {@see #createAlwaysOnHotwordDetector(String, Locale, AlwaysOnHotwordDetector.Callback)
+ * }. Before calling this function, you should set a valid hotword detection service with
+ * android:hotwordDetectionService in an android.voice_interaction metadata file and set
+ * android:isolatedProcess="true" in the AndroidManifest.xml of hotword detection service.
+ * Otherwise it will throw IllegalStateException. After calling this function, the system will
+ * also trigger a hotword detection service and pass the read-only data back to it.
+ *
+ * <p>Note: The system will trigger hotword detection service after calling this function when
+ * all conditions meet the requirements.
+ *
+ * @param keyphrase The keyphrase that's being used, for example "Hello Android".
+ * @param locale The locale for which the enrollment needs to be performed.
+ * @param options Application configuration data provided by the
+ * {@link VoiceInteractionService}. The system strips out any remotable objects or other
+ * contents that can be used to communicate with other processes.
+ * @param sharedMemory The unrestricted data blob provided by the
+ * {@link VoiceInteractionService}. Use this to provide the hotword models data or other
+ * such data to the trusted process.
+ * @param callback The callback to notify of detection events.
+ * @return An always-on hotword detector for the given keyphrase and locale.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
+ @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly
+ @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale,
+ @Nullable Bundle options,
+ @Nullable SharedMemory sharedMemory,
+ @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) {
+ return createAlwaysOnHotwordDetectorInternal(keyphrase, locale,
+ /* supportHotwordDetectionService= */ true, options,
+ sharedMemory, callback);
+ }
+
+ private AlwaysOnHotwordDetector createAlwaysOnHotwordDetectorInternal(
+ @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly
+ @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale,
+ boolean supportHotwordDetectionService,
+ @Nullable Bundle options,
+ @Nullable SharedMemory sharedMemory,
+ @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) {
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}
@@ -385,7 +380,8 @@
safelyShutdownHotwordDetector();
mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
mKeyphraseEnrollmentInfo, mSystemService,
- getApplicationContext().getApplicationInfo().targetSdkVersion);
+ getApplicationContext().getApplicationInfo().targetSdkVersion,
+ supportHotwordDetectionService, options, sharedMemory);
}
return mHotwordDetector;
}
@@ -432,7 +428,6 @@
}
private void safelyShutdownHotwordDetector() {
- // TODO (b/178171906): Need to check if the HotwordDetectionService should be unbound.
synchronized (mLock) {
if (mHotwordDetector == null) {
return;
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index bbe887f..e9a79e7 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -20,7 +20,6 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.compat.annotation.ChangeId;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Binder;
import android.os.Build;
@@ -1577,7 +1576,7 @@
// default implementation empty
}
- public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
+ public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) {
// default implementation empty
}
}
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 2cadda2..e3d3dec 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -546,9 +546,6 @@
/**
* Event for changes to allowed network list based on all active subscriptions.
*
- * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
- * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
* @hide
* @see AllowedNetworkTypesListener#onAllowedNetworkTypesChanged
*/
@@ -1265,30 +1262,34 @@
public interface AllowedNetworkTypesListener {
/**
* Callback invoked when the current allowed network type list has changed on the
- * registered subscription.
+ * registered subscription for a specified reason.
* Note, the registered subscription is associated with {@link TelephonyManager} object
- * on which
- * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
+ * on which {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
* was called.
* If this TelephonyManager object was created with
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* given subscription ID. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
- * @param allowedNetworkTypesList Map associating all allowed network type reasons
- * ({@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER},
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER},
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, and
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}) with reason's allowed
- * network type values.
+ * @param reason an allowed network type reasons.
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER
+ * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G
+ *
+ * @param allowedNetworkType an allowed network type bitmask value. (for example,
+ * the long bitmask value is {{@link TelephonyManager#NETWORK_TYPE_BITMASK_NR}|
+ * {@link TelephonyManager#NETWORK_TYPE_BITMASK_LTE}})
+ *
* For example:
- * map{{TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, long type value}}
+ * If the latest allowed network type is changed by user, then the system
+ * notifies the {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER} and
+ * long type value}.
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- void onAllowedNetworkTypesChanged(@NonNull Map<Integer, Long> allowedNetworkTypesList);
+ void onAllowedNetworkTypesChanged(
+ @TelephonyManager.AllowedNetworkTypesReason int reason,
+ @TelephonyManager.NetworkTypeBitMask long allowedNetworkType);
}
/**
@@ -1707,14 +1708,15 @@
enabled, reason)));
}
- public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
+ public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) {
AllowedNetworkTypesListener listener =
(AllowedNetworkTypesListener) mTelephonyCallbackWeakRef.get();
if (listener == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(
- () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList)));
+ () -> listener.onAllowedNetworkTypesChanged(reason,
+ allowedNetworkType)));
}
}
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 9cda4ae..3fa63d8 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -825,16 +825,18 @@
}
/**
- * Notify emergency number list changed on certain subscription.
- *
- * @param slotIndex for which emergency number list changed. Can be derived from subId except
- * when subId is invalid.
- * @param subId for which emergency number list changed.
+ * Notify the allowed network types has changed for a specific subscription and the specific
+ * reason.
+ * @param slotIndex for which allowed network types changed.
+ * @param subId for which allowed network types changed.
+ * @param reason an allowed network type reasons.
+ * @param allowedNetworkType an allowed network type bitmask value.
*/
public void notifyAllowedNetworkTypesChanged(int slotIndex, int subId,
- Map<Integer, Long> allowedNetworkTypeList) {
+ int reason, long allowedNetworkType) {
try {
- sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, allowedNetworkTypeList);
+ sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, reason,
+ allowedNetworkType);
} catch (RemoteException ex) {
// system process is dead
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index c97c995..7e6175c 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -200,10 +200,9 @@
// physical memory.
DataSource beforeApkSigningBlock =
- new MemoryMappedFileDataSource(apkFileDescriptor, 0,
- signatureInfo.apkSigningBlockOffset);
+ DataSource.create(apkFileDescriptor, 0, signatureInfo.apkSigningBlockOffset);
DataSource centralDir =
- new MemoryMappedFileDataSource(
+ DataSource.create(
apkFileDescriptor, signatureInfo.centralDirOffset,
signatureInfo.eocdOffset - signatureInfo.centralDirOffset);
diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java
index 82f3800..dd6389d 100644
--- a/core/java/android/util/apk/DataSource.java
+++ b/core/java/android/util/apk/DataSource.java
@@ -16,6 +16,10 @@
package android.util.apk;
+import android.annotation.NonNull;
+import android.os.incremental.IncrementalManager;
+
+import java.io.FileDescriptor;
import java.io.IOException;
import java.security.DigestException;
@@ -35,4 +39,22 @@
*/
void feedIntoDataDigester(DataDigester md, long offset, int size)
throws IOException, DigestException;
+
+ /**
+ * Creates a DataSource that can handle the passed fd in the most efficient and safe manner.
+ * @param fd file descriptor to read from
+ * @param pos starting offset
+ * @param size size of the region
+ * @return created DataSource object
+ */
+ static @NonNull DataSource create(@NonNull FileDescriptor fd, long pos, long size) {
+ if (IncrementalManager.isIncrementalFileFd(fd)) {
+ // IncFS-based files may have missing pages, and reading those via mmap() results
+ // in a SIGBUS signal. Java doesn't have a good way of catching it, ending up killing
+ // the process by default. Going back to read() is the safest option for these files.
+ return new ReadFileDataSource(fd, pos, size);
+ } else {
+ return new MemoryMappedFileDataSource(fd, pos, size);
+ }
+ }
}
diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java
index 8d2b1e32..69a526d 100644
--- a/core/java/android/util/apk/MemoryMappedFileDataSource.java
+++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java
@@ -40,6 +40,7 @@
/**
* Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
*
+ * @param fd file descriptor to read from.
* @param position start position of the region in the file.
* @param size size (in bytes) of the region.
*/
diff --git a/core/java/android/util/apk/ReadFileDataSource.java b/core/java/android/util/apk/ReadFileDataSource.java
new file mode 100644
index 0000000..d0e1140
--- /dev/null
+++ b/core/java/android/util/apk/ReadFileDataSource.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.apk;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+
+/**
+ * {@link DataSource} which provides data from a file descriptor by reading the sections
+ * of the file via raw read() syscall. This is slower than memory-mapping but safer.
+ */
+class ReadFileDataSource implements DataSource {
+ private final FileDescriptor mFd;
+ private final long mFilePosition;
+ private final long mSize;
+
+ private static final int CHUNK_SIZE = 1024 * 1024;
+
+ /**
+ * Constructs a new {@code ReadFileDataSource} for the specified region of the file.
+ *
+ * @param fd file descriptor to read from.
+ * @param position start position of the region in the file.
+ * @param size size (in bytes) of the region.
+ */
+ ReadFileDataSource(FileDescriptor fd, long position, long size) {
+ mFd = fd;
+ mFilePosition = position;
+ mSize = size;
+ }
+
+ @Override
+ public long size() {
+ return mSize;
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException {
+ try {
+ final byte[] buffer = new byte[Math.min(size, CHUNK_SIZE)];
+ final long start = mFilePosition + offset;
+ final long end = start + size;
+ for (long pos = start, curSize = Math.min(size, CHUNK_SIZE);
+ pos < end; curSize = Math.min(end - pos, CHUNK_SIZE)) {
+ final int readSize = Os.pread(mFd, buffer, 0, (int) curSize, pos);
+ md.consume(ByteBuffer.wrap(buffer, 0, readSize));
+ pos += readSize;
+ }
+ } catch (ErrnoException e) {
+ throw new IOException(e);
+ }
+ }
+}
diff --git a/core/java/android/util/apk/TEST_MAPPING b/core/java/android/util/apk/TEST_MAPPING
index 8544e82..4598b4f 100644
--- a/core/java/android/util/apk/TEST_MAPPING
+++ b/core/java/android/util/apk/TEST_MAPPING
@@ -1,6 +1,17 @@
{
"presubmit": [
{
+ "name": "CtsContentTestCases",
+ "options": [
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerShellCommandIncrementalTest"
+ },
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerShellCommandTest"
+ }
+ ]
+ },
+ {
"name": "FrameworksCoreTests",
"options": [
{
diff --git a/core/java/android/util/apk/VerityBuilder.java b/core/java/android/util/apk/VerityBuilder.java
index 4596c6e..b0a5992 100644
--- a/core/java/android/util/apk/VerityBuilder.java
+++ b/core/java/android/util/apk/VerityBuilder.java
@@ -294,7 +294,7 @@
// 1. Digest the whole file by chunks.
consumeByChunk(digester,
- new MemoryMappedFileDataSource(file.getFD(), 0, file.length()),
+ DataSource.create(file.getFD(), 0, file.length()),
MMAP_REGION_SIZE_BYTES);
// 2. Pad 0s up to the nearest 4096-byte block before hashing.
@@ -315,7 +315,7 @@
// 1. Digest from the beginning of the file, until APK Signing Block is reached.
consumeByChunk(digester,
- new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
+ DataSource.create(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
MMAP_REGION_SIZE_BYTES);
// 2. Skip APK Signing Block and continue digesting, until the Central Directory offset
@@ -323,7 +323,7 @@
long eocdCdOffsetFieldPosition =
signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET;
consumeByChunk(digester,
- new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset,
+ DataSource.create(apk.getFD(), signatureInfo.centralDirOffset,
eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset),
MMAP_REGION_SIZE_BYTES);
@@ -338,7 +338,7 @@
long offsetAfterEocdCdOffsetField =
eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
consumeByChunk(digester,
- new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
+ DataSource.create(apk.getFD(), offsetAfterEocdCdOffsetField,
apk.length() - offsetAfterEocdCdOffsetField),
MMAP_REGION_SIZE_BYTES);
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java
index 49ff237..b28cfb8 100644
--- a/core/java/android/util/imetracing/ImeTracing.java
+++ b/core/java/android/util/imetracing/ImeTracing.java
@@ -23,7 +23,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodManager;
@@ -104,12 +103,6 @@
public abstract void addToBuffer(ProtoOutputStream proto, int source);
/**
- * @param shell The shell command to process
- * @return {@code 0} if the command was successfully processed, {@code -1} otherwise
- */
- public abstract int onShellCommand(ShellCommand shell);
-
- /**
* Starts a proto dump of the client side information.
*
* @param where Place where the trace was triggered.
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java
index 2c27639..35a81b7 100644
--- a/core/java/android/util/imetracing/ImeTracingClientImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java
@@ -20,7 +20,6 @@
import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodManager;
@@ -45,11 +44,6 @@
}
@Override
- public int onShellCommand(ShellCommand shell) {
- return -1;
- }
-
- @Override
public void triggerClientDump(String where, @NonNull InputMethodManager immInstance,
ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
index e793c28..77f017a 100644
--- a/core/java/android/util/imetracing/ImeTracingServerImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -22,7 +22,6 @@
import android.inputmethodservice.AbstractInputMethodService;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.ShellCommand;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceFileProto;
@@ -106,32 +105,6 @@
}
}
- /**
- * Responds to a shell command of the format "adb shell cmd input_method ime tracing <command>"
- *
- * @param shell The shell command to process
- * @return {@code 0} if the command was valid and successfully processed, {@code -1} otherwise
- */
- @Override
- public int onShellCommand(ShellCommand shell) {
- PrintWriter pw = shell.getOutPrintWriter();
- String cmd = shell.getNextArgRequired();
- switch (cmd) {
- case "start":
- startTrace(pw);
- return 0;
- case "stop":
- stopTrace(pw);
- return 0;
- default:
- pw.println("Unknown command: " + cmd);
- pw.println("Input method trace options:");
- pw.println(" start: Start tracing");
- pw.println(" stop: Stop tracing");
- return -1;
- }
- }
-
@Override
public void triggerClientDump(String where, InputMethodManager immInstance,
ProtoOutputStream icProto) {
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index 9df213b..8c771ba 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -38,9 +38,30 @@
private final double mErrorRadians;
private final double mConfidenceLevel;
- private AngleMeasurement(double radians, double errorRadians, double confidenceLevel) {
+ /**
+ * Constructs a new {@link AngleMeasurement} object
+ *
+ * @param radians the angle in radians
+ * @param errorRadians the error of the angle measurement in radians
+ * @param confidenceLevel confidence level of the angle measurement
+ *
+ * @throws IllegalArgumentException if the radians, errorRadians, or confidenceLevel is out of
+ * allowed range
+ */
+ public AngleMeasurement(double radians, double errorRadians, double confidenceLevel) {
+ if (radians < -Math.PI || radians > Math.PI) {
+ throw new IllegalArgumentException("Invalid radians: " + radians);
+ }
mRadians = radians;
+
+ if (errorRadians < 0.0 || errorRadians > Math.PI) {
+ throw new IllegalArgumentException("Invalid error radians: " + errorRadians);
+ }
mErrorRadians = errorRadians;
+
+ if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
+ throw new IllegalArgumentException("Invalid confidence level: " + confidenceLevel);
+ }
mConfidenceLevel = confidenceLevel;
}
@@ -122,11 +143,7 @@
new Creator<AngleMeasurement>() {
@Override
public AngleMeasurement createFromParcel(Parcel in) {
- Builder builder = new Builder();
- builder.setRadians(in.readDouble());
- builder.setErrorRadians(in.readDouble());
- builder.setConfidenceLevel(in.readDouble());
- return builder.build();
+ return new AngleMeasurement(in.readDouble(), in.readDouble(), in.readDouble());
}
@Override
@@ -134,82 +151,4 @@
return new AngleMeasurement[size];
}
};
-
- /**
- * Builder class for {@link AngleMeasurement}.
- */
- public static final class Builder {
- private double mRadians = Double.NaN;
- private double mErrorRadians = Double.NaN;
- private double mConfidenceLevel = Double.NaN;
-
- /**
- * Set the angle in radians
- *
- * @param radians angle in radians
- * @throws IllegalArgumentException if angle exceeds allowed limits of [-Math.PI, +Math.PI]
- */
- @NonNull
- public Builder setRadians(double radians) {
- if (radians < -Math.PI || radians > Math.PI) {
- throw new IllegalArgumentException("Invalid radians: " + radians);
- }
- mRadians = radians;
- return this;
- }
-
- /**
- * Set the angle error in radians
- *
- * @param errorRadians error of the angle in radians
- * @throws IllegalArgumentException if the error exceeds the allowed limits of [0, +Math.PI]
- */
- @NonNull
- public Builder setErrorRadians(double errorRadians) {
- if (errorRadians < 0.0 || errorRadians > Math.PI) {
- throw new IllegalArgumentException(
- "Invalid error radians: " + errorRadians);
- }
- mErrorRadians = errorRadians;
- return this;
- }
-
- /**
- * Set the angle confidence level
- *
- * @param confidenceLevel level of confidence of the angle measurement
- * @throws IllegalArgumentException if the error exceeds the allowed limits of [0.0, 1.0]
- */
- @NonNull
- public Builder setConfidenceLevel(double confidenceLevel) {
- if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
- throw new IllegalArgumentException(
- "Invalid confidence level: " + confidenceLevel);
- }
- mConfidenceLevel = confidenceLevel;
- return this;
- }
-
- /**
- * Build the {@link AngleMeasurement} object
- *
- * @throws IllegalStateException if angle, error, or confidence values are missing
- */
- @NonNull
- public AngleMeasurement build() {
- if (Double.isNaN(mRadians)) {
- throw new IllegalStateException("Angle is not set");
- }
-
- if (Double.isNaN(mErrorRadians)) {
- throw new IllegalStateException("Angle error is not set");
- }
-
- if (Double.isNaN(mConfidenceLevel)) {
- throw new IllegalStateException("Angle confidence level is not set");
- }
-
- return new AngleMeasurement(mRadians, mErrorRadians, mConfidenceLevel);
- }
- }
}
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index 3d8626b..db04ad1 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -116,9 +116,8 @@
new Creator<AngleOfArrivalMeasurement>() {
@Override
public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
- Builder builder = new Builder();
-
- builder.setAzimuth(in.readParcelable(AngleMeasurement.class.getClassLoader()));
+ Builder builder =
+ new Builder(in.readParcelable(AngleMeasurement.class.getClassLoader()));
builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader()));
@@ -135,18 +134,16 @@
* Builder class for {@link AngleOfArrivalMeasurement}.
*/
public static final class Builder {
- private AngleMeasurement mAzimuthAngleMeasurement = null;
+ private final AngleMeasurement mAzimuthAngleMeasurement;
private AngleMeasurement mAltitudeAngleMeasurement = null;
/**
- * Set the azimuth angle
+ * Constructs an {@link AngleOfArrivalMeasurement} object
*
- * @param azimuthAngle azimuth angle
+ * @param azimuthAngle the azimuth angle of the measurement
*/
- @NonNull
- public Builder setAzimuth(@NonNull AngleMeasurement azimuthAngle) {
+ public Builder(@NonNull AngleMeasurement azimuthAngle) {
mAzimuthAngleMeasurement = azimuthAngle;
- return this;
}
/**
@@ -162,15 +159,9 @@
/**
* Build the {@link AngleOfArrivalMeasurement} object
- *
- * @throws IllegalStateException if the required azimuth angle is not provided
*/
@NonNull
public AngleOfArrivalMeasurement build() {
- if (mAzimuthAngleMeasurement == null) {
- throw new IllegalStateException("Azimuth angle measurement is not set");
- }
-
return new AngleOfArrivalMeasurement(mAzimuthAngleMeasurement,
mAltitudeAngleMeasurement);
}
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index 468a69c..4036892 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -62,9 +62,6 @@
/**
* Request to open a new ranging session
*
- * This function must return before calling any functions in
- * IUwbAdapterCallbacks.
- *
* This function does not start the ranging session, but all necessary
* components must be initialized and ready to start a new ranging
* session prior to calling IUwbAdapterCallback#onRangingOpened.
@@ -77,12 +74,16 @@
* RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being called
* if the ranging session fails to be opened.
*
+ * If the provided sessionHandle is already open for the calling client, then
+ * #onRangingOpenFailed must be called and the new session must not be opened.
+ *
+ * @param sessionHandle the session handle to open ranging for
* @param rangingCallbacks the callbacks used to deliver ranging information
* @param parameters the configuration to use for ranging
- * @return a SessionHandle used to identify this ranging request
*/
- SessionHandle openRanging(in IUwbRangingCallbacks rangingCallbacks,
- in PersistableBundle parameters);
+ void openRanging(in SessionHandle sessionHandle,
+ in IUwbRangingCallbacks rangingCallbacks,
+ in PersistableBundle parameters);
/**
* Request to start ranging
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
index c0d8187..85f2c1c 100644
--- a/core/java/android/uwb/RangingManager.java
+++ b/core/java/android/uwb/RangingManager.java
@@ -17,6 +17,7 @@
package android.uwb;
import android.annotation.NonNull;
+import android.os.CancellationSignal;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.util.Log;
@@ -32,6 +33,7 @@
private final IUwbAdapter mAdapter;
private final Hashtable<SessionHandle, RangingSession> mRangingSessionTable = new Hashtable<>();
+ private int mNextSessionId = 1;
public RangingManager(IUwbAdapter adapter) {
mAdapter = adapter;
@@ -44,29 +46,26 @@
* @param executor {@link Executor} to run callbacks
* @param callbacks {@link RangingSession.Callback} to associate with the {@link RangingSession}
* that is being opened.
- * @return a new {@link RangingSession}
+ * @return a {@link CancellationSignal} that may be used to cancel the opening of the
+ * {@link RangingSession}.
*/
- public RangingSession openSession(@NonNull PersistableBundle params, @NonNull Executor executor,
+ public CancellationSignal openSession(@NonNull PersistableBundle params,
+ @NonNull Executor executor,
@NonNull RangingSession.Callback callbacks) {
- SessionHandle sessionHandle;
- try {
- sessionHandle = mAdapter.openRanging(this, params);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
synchronized (this) {
- if (hasSession(sessionHandle)) {
- Log.w(TAG, "Newly created session unexpectedly reuses an active SessionHandle");
- executor.execute(() -> callbacks.onClosed(
- RangingSession.Callback.REASON_GENERIC_ERROR,
- new PersistableBundle()));
- }
-
+ SessionHandle sessionHandle = new SessionHandle(mNextSessionId++);
RangingSession session =
new RangingSession(executor, callbacks, mAdapter, sessionHandle);
mRangingSessionTable.put(sessionHandle, session);
- return session;
+ try {
+ mAdapter.openRanging(sessionHandle, this, params);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ CancellationSignal cancellationSignal = new CancellationSignal();
+ cancellationSignal.setOnCancelListener(() -> session.close());
+ return cancellationSignal;
}
}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 63a6d05..844bbbe 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -228,14 +229,14 @@
* @param callbacks {@link RangingSession.Callback} to associate with the
* {@link RangingSession} that is being opened.
*
- * @return an {@link AutoCloseable} that is able to be used to close or cancel the opening of a
+ * @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
* {@link RangingSession} that has been requested through {@link #openRangingSession}
* but has not yet been made available by
* {@link RangingSession.Callback#onOpened(RangingSession)}.
*/
@NonNull
@RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
- public AutoCloseable openRangingSession(@NonNull PersistableBundle parameters,
+ public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
@NonNull @CallbackExecutor Executor executor,
@NonNull RangingSession.Callback callbacks) {
return mRangingManager.openSession(parameters, executor, callbacks);
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index a8aaeb7..9aaf5c0 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -636,7 +636,9 @@
public void getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
Configuration configuration) {
Rect bounds = configuration.windowConfiguration.getMaxBounds();
- getMetricsWithSize(outMetrics, compatInfo, configuration, bounds.width(), bounds.height());
+ // Pass in null configuration to ensure width and height are not overridden to app bounds.
+ getMetricsWithSize(outMetrics, compatInfo, /* configuration= */ null,
+ bounds.width(), bounds.height());
}
public int getNaturalWidth() {
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index afbd249..ddb49786 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -142,7 +142,13 @@
*
* The system reparents the leash of navigation bar to the app when the recents animation starts
* and Launcher should call this method to let system restore the navigation bar to its
- * original position when the quick switch gesture is finished.
+ * original position when the quick switch gesture is finished and will run the fade-in
+ * animation If {@param moveHomeToTop} is {@code true}. Otherwise, restore the navigtation bar
+ * without animation.
+ *
+ * @param moveHomeToTop if {@code true}, the home activity should be moved to the top.
+ * Otherwise, the home activity is hidden and the user is returned to the
+ * app.
*/
- void detachNavigationBarFromApp();
+ void detachNavigationBarFromApp(boolean moveHomeToTop);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5477800..b345b2e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -816,4 +816,6 @@
* @param listener the listener to be unregistered
*/
void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener);
+
+ void setForceCrossWindowBlurDisabled(boolean disable);
}
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 02a9788..aa1acc1 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.input.InputManager;
import android.os.Build;
@@ -25,6 +26,8 @@
import android.util.AndroidRuntimeException;
import android.util.SparseIntArray;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.text.Normalizer;
/**
@@ -297,6 +300,8 @@
private static native char nativeGetDisplayLabel(long ptr, int keyCode);
private static native int nativeGetKeyboardType(long ptr);
private static native KeyEvent[] nativeGetEvents(long ptr, char[] chars);
+ private static native KeyCharacterMap nativeObtainEmptyKeyCharacterMap(int deviceId);
+ private static native boolean nativeEquals(long ptr1, long ptr2);
private KeyCharacterMap(Parcel in) {
if (in == null) {
@@ -323,6 +328,18 @@
}
/**
+ * Obtain empty key character map
+ * @param deviceId The input device ID
+ * @return The KeyCharacterMap object
+ * @hide
+ */
+ @VisibleForTesting
+ @Nullable
+ public static KeyCharacterMap obtainEmptyMap(int deviceId) {
+ return nativeObtainEmptyKeyCharacterMap(deviceId);
+ }
+
+ /**
* Loads the key character maps for the keyboard with the specified device id.
*
* @param deviceId The device id of the keyboard.
@@ -729,6 +746,18 @@
return 0;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof KeyCharacterMap)) {
+ return false;
+ }
+ KeyCharacterMap peer = (KeyCharacterMap) obj;
+ if (mPtr == 0 || peer.mPtr == 0) {
+ return mPtr == peer.mPtr;
+ }
+ return nativeEquals(mPtr, peer.mPtr);
+ }
+
/**
* Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded.
*/
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index a86984f..31f6f6a 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -80,5 +80,6 @@
per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
# Scroll Capture
+per-file *ScrollCapture*.aidl = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9fc415d..35726c0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8572,6 +8572,17 @@
}
@Override
+ public void onDragEvent(boolean isExiting, float x, float y) {
+ // force DRAG_EXITED_EVENT if appropriate
+ DragEvent event = DragEvent.obtain(
+ isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
+ x, y, 0 /* offsetX */, 0 /* offsetY */, null/* localState */,
+ null/* description */, null /* data */, null /* dragSurface */,
+ null /* dragAndDropPermissions */, false /* result */);
+ dispatchDragEvent(event);
+ }
+
+ @Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 7338c7d..818a2b0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -873,6 +873,20 @@
default void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
}
+ /**
+ * Disables cross-window blurs device-wide. This includes window blur behind
+ * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur
+ * (see {@link Window#setBackgroundBlurRadius}).
+ *
+ * @param disable specifies whether to disable the blur. Note that calling this
+ * with 'disable=false' will not enable blurs if there is something
+ * else disabling blurs.
+ * @hide
+ */
+ @TestApi
+ default void setForceCrossWindowBlurDisabled(boolean disable) {
+ }
+
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index b398707..e37522b 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -317,4 +317,13 @@
public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) {
CrossWindowBlurListeners.getInstance().removeListener(listener);
}
+
+ @Override
+ public void setForceCrossWindowBlurDisabled(boolean disable) {
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .setForceCrossWindowBlurDisabled(disable);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a8fff8b..53bbc0a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -106,7 +106,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
@@ -413,7 +412,7 @@
* The InputConnection that was last retrieved from the served view.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- ControlledInputConnectionWrapper mServedInputConnectionWrapper;
+ IInputConnectionWrapper mServedInputConnectionWrapper;
/**
* The completions that were last provided by the served view.
*/
@@ -740,8 +739,7 @@
/**
* Checks whether the active input connection (if any) is for the given view.
*
- * TODO(b/160968797): Remove this method and move mServedInputConnectionWrapper to
- * ImeFocusController.
+ * TODO(b/182259171): Clean-up hasActiveConnection to simplify the logic.
*
* Note that this method is only intended for restarting input after focus gain
* (e.g. b/160391516), DO NOT leverage this method to do another check.
@@ -755,7 +753,7 @@
return mServedInputConnectionWrapper != null
&& mServedInputConnectionWrapper.isActive()
- && mServedInputConnectionWrapper.mServedView.get() == view;
+ && mServedInputConnectionWrapper.getServedView() == view;
}
}
}
@@ -1022,77 +1020,6 @@
}
}
- private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
- private final InputMethodManager mParentInputMethodManager;
- private final WeakReference<View> mServedView;
-
- ControlledInputConnectionWrapper(Looper icLooper, InputConnection conn,
- InputMethodManager inputMethodManager, View servedView) {
- super(icLooper, conn);
- mParentInputMethodManager = inputMethodManager;
- mServedView = new WeakReference<>(servedView);
- }
-
- @Override
- public boolean isActive() {
- return mParentInputMethodManager.mActive && !isFinished();
- }
-
- @Override
- public InputMethodManager getIMM() {
- return mParentInputMethodManager;
- }
-
- void deactivate() {
- if (isFinished()) {
- // This is a small performance optimization. Still only the 1st call of
- // reportFinish() will take effect.
- return;
- }
- closeConnection();
-
- // Notify the app that the InputConnection was closed.
- final View servedView = mServedView.get();
- if (servedView != null) {
- final Handler handler = servedView.getHandler();
- // The handler is null if the view is already detached. When that's the case, for
- // now, we simply don't dispatch this callback.
- if (handler != null) {
- if (DEBUG) {
- Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
- }
- if (handler.getLooper().isCurrentThread()) {
- servedView.onInputConnectionClosedInternal();
- } else {
- handler.post(servedView::onInputConnectionClosedInternal);
- }
- }
- }
- }
-
- @Override
- public String toString() {
- return "ControlledInputConnectionWrapper{"
- + "connection=" + getInputConnection()
- + " finished=" + isFinished()
- + " mParentInputMethodManager.mActive=" + mParentInputMethodManager.mActive
- + " mServedView=" + mServedView.get()
- + "}";
- }
-
- void dumpDebug(ProtoOutputStream proto, long fieldId) {
- // Check that the call is initiated in the main thread of the current InputConnection
- // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
- // executed on this thread. Otherwise the messages are dispatched to the correct thread
- // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
- // reasons.
- if (getInputConnection() instanceof DumpableInputConnection && Looper.myLooper()
- == getLooper()) {
- ((DumpableInputConnection) getInputConnection()).dumpDebug(proto, fieldId);
- }
- }
- }
-
final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
@Override
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
@@ -1256,8 +1183,7 @@
mMainLooper = looper;
mH = new H(looper);
mDisplayId = displayId;
- mIInputContext = new ControlledInputConnectionWrapper(looper, mDummyInputConnection, this,
- null);
+ mIInputContext = new IInputConnectionWrapper(looper, mDummyInputConnection, this, null);
}
/**
@@ -2063,7 +1989,7 @@
mServedInputConnectionWrapper.deactivate();
mServedInputConnectionWrapper = null;
}
- ControlledInputConnectionWrapper servedContext;
+ IInputConnectionWrapper servedContext;
final int missingMethodFlags;
if (ic != null) {
mCursorSelStart = tba.initialSelStart;
@@ -2080,7 +2006,7 @@
} else {
icHandler = ic.getHandler();
}
- servedContext = new ControlledInputConnectionWrapper(
+ servedContext = new IInputConnectionWrapper(
icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this, view);
} else {
servedContext = null;
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 34fe51e..42d7535 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -200,6 +200,8 @@
mTimeZone = toZoneId(a.getString(com.android.internal.R.styleable.AnalogClock_timeZone));
createClock();
+ a.recycle();
+
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 012352d..7517b80 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3790,7 +3790,7 @@
}
public SuggestionsPopupWindow() {
- mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+ mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr();
}
@Override
@@ -3957,7 +3957,7 @@
}
if (updateSuggestions()) {
- mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+ mCursorWasVisibleBeforeSuggestions = mTextView.isCursorVisibleFromAttr();
mTextView.setCursorVisible(false);
mIsShowingUp = true;
super.show();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2328e58..d2f4cea 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -120,6 +120,7 @@
import java.util.Stack;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* A class that describes a view hierarchy that can be displayed in
@@ -1993,22 +1994,79 @@
mIsRoot = false;
}
+ private static boolean hasStableId(View view) {
+ Object tag = view.getTag(com.android.internal.R.id.remote_views_stable_id);
+ return tag != null;
+ }
+
+ private static int getStableId(View view) {
+ Integer id = (Integer) view.getTag(com.android.internal.R.id.remote_views_stable_id);
+ return id == null ? ViewGroupActionAdd.NO_ID : id;
+ }
+
+ private static void setStableId(View view, int stableId) {
+ view.setTagInternal(com.android.internal.R.id.remote_views_stable_id, stableId);
+ }
+
+ // Returns the next recyclable child of the view group, or -1 if there are none.
+ private static int getNextRecyclableChild(ViewGroup vg) {
+ Integer tag = (Integer) vg.getTag(com.android.internal.R.id.remote_views_next_child);
+ return tag == null ? -1 : tag;
+ }
+
+ private static int getViewLayoutId(View v) {
+ return (Integer) v.getTag(R.id.widget_frame);
+ }
+
+ private static void setNextRecyclableChild(ViewGroup vg, int nextChild, int numChildren) {
+ if (nextChild < 0 || nextChild >= numChildren) {
+ vg.setTagInternal(com.android.internal.R.id.remote_views_next_child, -1);
+ } else {
+ vg.setTagInternal(com.android.internal.R.id.remote_views_next_child, nextChild);
+ }
+ }
+
+ private void finalizeViewRecycling(ViewGroup root) {
+ // Remove any recyclable children that were not used. nextChild should either be -1 or point
+ // to the next recyclable child that hasn't been recycled.
+ int nextChild = getNextRecyclableChild(root);
+ if (nextChild >= 0 && nextChild < root.getChildCount()) {
+ root.removeViews(nextChild, root.getChildCount() - nextChild);
+ }
+ // Make sure on the next round, we don't try to recycle if removeAllViews is not called.
+ setNextRecyclableChild(root, -1, 0);
+ // Traverse the view tree.
+ for (int i = 0; i < root.getChildCount(); i++) {
+ View child = root.getChildAt(i);
+ if (child instanceof ViewGroup && !child.isRootNamespace()) {
+ finalizeViewRecycling((ViewGroup) child);
+ }
+ }
+ }
+
/**
* ViewGroup methods that are related to adding Views.
*/
private class ViewGroupActionAdd extends Action {
+ static final int NO_ID = -1;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private RemoteViews mNestedViews;
private int mIndex;
+ private int mStableId;
ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews) {
- this(viewId, nestedViews, -1 /* index */);
+ this(viewId, nestedViews, -1 /* index */, NO_ID /* nestedViewId */);
}
ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews, int index) {
+ this(viewId, nestedViews, index, NO_ID /* nestedViewId */);
+ }
+
+ ViewGroupActionAdd(@IdRes int viewId, RemoteViews nestedViews, int index, int stableId) {
this.viewId = viewId;
mNestedViews = nestedViews;
mIndex = index;
+ mStableId = stableId;
if (nestedViews != null) {
configureRemoteViewsAsChild(nestedViews);
}
@@ -2018,6 +2076,7 @@
int depth, Map<Class, Object> classCookies) {
viewId = parcel.readInt();
mIndex = parcel.readInt();
+ mStableId = parcel.readInt();
mNestedViews = new RemoteViews(parcel, bitmapCache, info, depth, classCookies);
mNestedViews.addFlags(mApplyFlags);
}
@@ -2025,6 +2084,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(viewId);
dest.writeInt(mIndex);
+ dest.writeInt(mStableId);
mNestedViews.writeToParcel(dest, flags);
}
@@ -2033,6 +2093,17 @@
return mNestedViews.hasSameAppInfo(parentInfo);
}
+ private int findViewIndexToRecycle(ViewGroup target, RemoteViews newContent) {
+ for (int nextChild = getNextRecyclableChild(target); nextChild < target.getChildCount();
+ nextChild++) {
+ View child = target.getChildAt(nextChild);
+ if (getStableId(child) == mStableId) {
+ return nextChild;
+ }
+ }
+ return -1;
+ }
+
@Override
public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
ColorResources colorResources) {
@@ -2043,10 +2114,45 @@
return;
}
+ // If removeAllViews was called, this returns the next potential recycled view.
+ // If there are no more views to recycle (or removeAllViews was not called), this
+ // will return -1.
+ final int nextChild = getNextRecyclableChild(target);
+ RemoteViews rvToApply = mNestedViews.getRemoteViewsToApply(context);
+ if (nextChild >= 0 && mStableId != NO_ID) {
+ // At that point, the views starting at index nextChild are the ones recyclable but
+ // not yet recycled. All views added on that round of application are placed before.
+ // Find the next view with the same stable id, or -1.
+ int recycledViewIndex = findViewIndexToRecycle(target, rvToApply);
+ if (recycledViewIndex >= 0) {
+ View child = target.getChildAt(recycledViewIndex);
+ if (getViewLayoutId(child) == rvToApply.getLayoutId()) {
+ if (nextChild < recycledViewIndex) {
+ target.removeViews(nextChild, recycledViewIndex - nextChild);
+ }
+ setNextRecyclableChild(target, nextChild + 1, target.getChildCount());
+ rvToApply.reapply(context, child, handler, null /* size */, colorResources,
+ false /* topLevel */);
+ return;
+ }
+ // If we cannot recycle the views, we still remove all views in between to
+ // avoid weird behaviors and insert the new view in place of the old one.
+ target.removeViews(nextChild, recycledViewIndex - nextChild + 1);
+ }
+ }
+ // If we cannot recycle, insert the new view before the next recyclable child.
+
// Inflate nested views and add as children
- target.addView(
- mNestedViews.apply(context, target, handler, null /* size */, colorResources),
- mIndex);
+ View nestedView = rvToApply.apply(context, target, handler, null /* size */,
+ colorResources);
+ if (mStableId != NO_ID) {
+ setStableId(nestedView, mStableId);
+ }
+ target.addView(nestedView, mIndex >= 0 ? mIndex : nextChild);
+ if (nextChild >= 0) {
+ // If we are at the end, there is no reason to try to recycle anymore
+ setNextRecyclableChild(target, nextChild + 1, target.getChildCount());
+ }
}
@Override
@@ -2063,24 +2169,91 @@
// Inflate nested views and perform all the async tasks for the child remoteView.
final Context context = root.mRoot.getContext();
- final AsyncApplyTask task = mNestedViews.getAsyncApplyTask(context, targetVg,
- null /* listener */, handler, null /* size */, colorResources);
+
+ // If removeAllViews was called, this returns the next potential recycled view.
+ // If there are no more views to recycle (or removeAllViews was not called), this
+ // will return -1.
+ final int nextChild = getNextRecyclableChild(targetVg);
+ if (nextChild >= 0 && mStableId != NO_ID) {
+ RemoteViews rvToApply = mNestedViews.getRemoteViewsToApply(context);
+ final int recycledViewIndex = target.findChildIndex(nextChild,
+ view -> getStableId(view) == mStableId);
+ if (recycledViewIndex >= 0) {
+ // At that point, the views starting at index nextChild are the ones
+ // recyclable but not yet recycled. All views added on that round of
+ // application are placed before.
+ ViewTree recycled = target.mChildren.get(recycledViewIndex);
+ // We can only recycle the view if the layout id is the same.
+ if (getViewLayoutId(recycled.mRoot) == rvToApply.getLayoutId()) {
+ if (recycledViewIndex > nextChild) {
+ target.removeChildren(nextChild, recycledViewIndex - nextChild);
+ }
+ setNextRecyclableChild(targetVg, nextChild + 1, target.mChildren.size());
+ final AsyncApplyTask reapplyTask = rvToApply.getInternalAsyncApplyTask(
+ context,
+ targetVg, null /* listener */, handler, null /* size */,
+ colorResources,
+ recycled.mRoot);
+ final ViewTree tree = reapplyTask.doInBackground();
+ if (tree == null) {
+ throw new ActionException(reapplyTask.mError);
+ }
+ return new RuntimeAction() {
+ @Override
+ public void apply(View root, ViewGroup rootParent,
+ InteractionHandler handler, ColorResources colorResources)
+ throws ActionException {
+ reapplyTask.onPostExecute(tree);
+ if (recycledViewIndex > nextChild) {
+ targetVg.removeViews(nextChild, recycledViewIndex - nextChild);
+ }
+ }
+ };
+ }
+ // If the layout id is different, still remove the children as if we recycled
+ // the view, to insert at the same place.
+ target.removeChildren(nextChild, recycledViewIndex - nextChild + 1);
+ return insertNewView(context, target, handler, colorResources,
+ () -> targetVg.removeViews(nextChild,
+ recycledViewIndex - nextChild + 1));
+
+ }
+ }
+ // If we cannot recycle, simply add the view at the same available slot.
+ return insertNewView(context, target, handler, colorResources, () -> {});
+ }
+
+ private Action insertNewView(Context context, ViewTree target, InteractionHandler handler,
+ ColorResources colorResources, Runnable finalizeAction) {
+ ViewGroup targetVg = (ViewGroup) target.mRoot;
+ int nextChild = getNextRecyclableChild(targetVg);
+ final AsyncApplyTask task = mNestedViews.getInternalAsyncApplyTask(context, targetVg,
+ null /* listener */, handler, null /* size */, colorResources,
+ null /* result */);
final ViewTree tree = task.doInBackground();
if (tree == null) {
throw new ActionException(task.mError);
}
+ if (mStableId != NO_ID) {
+ setStableId(task.mResult, mStableId);
+ }
// Update the global view tree, so that next call to findViewTreeById
// goes through the subtree as well.
- target.addChild(tree, mIndex);
+ final int insertIndex = mIndex >= 0 ? mIndex : nextChild;
+ target.addChild(tree, insertIndex);
+ if (nextChild >= 0) {
+ setNextRecyclableChild(targetVg, nextChild + 1, target.mChildren.size());
+ }
return new RuntimeAction() {
@Override
public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
ColorResources colorResources) throws ActionException {
task.onPostExecute(tree);
- targetVg.addView(task.mResult, mIndex);
+ finalizeAction.run();
+ targetVg.addView(task.mResult, insertIndex);
}
};
}
@@ -2148,7 +2321,14 @@
}
if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
- target.removeAllViews();
+ // Remote any view without a stable id
+ for (int i = target.getChildCount() - 1; i >= 0; i--) {
+ if (!hasStableId(target.getChildAt(i))) {
+ target.removeViewAt(i);
+ }
+ }
+ // In the end, only children with a stable id (i.e. recyclable) are left.
+ setNextRecyclableChild(target, 0, target.getChildCount());
return;
}
@@ -2170,8 +2350,8 @@
final ViewGroup targetVg = (ViewGroup) target.mRoot;
if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
- // Clear all children when there's no excepted view
- target.mChildren = null;
+ target.mChildren.removeIf(childTree -> !hasStableId(childTree.mRoot));
+ setNextRecyclableChild(targetVg, 0, target.mChildren.size());
} else {
// Remove just the children which don't match the excepted view
target.mChildren.removeIf(childTree -> childTree.mRoot.getId() != mViewIdToKeep);
@@ -2184,7 +2364,11 @@
public void apply(View root, ViewGroup rootParent, InteractionHandler handler,
ColorResources colorResources) throws ActionException {
if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
- targetVg.removeAllViews();
+ for (int i = targetVg.getChildCount() - 1; i >= 0; i--) {
+ if (!hasStableId(targetVg.getChildAt(i))) {
+ targetVg.removeViewAt(i);
+ }
+ }
return;
}
@@ -3084,6 +3268,7 @@
}
mApplication = portrait.mApplication;
mLayoutId = portrait.mLayoutId;
+ mViewId = portrait.mViewId;
mLightBackgroundLayoutId = portrait.mLightBackgroundLayoutId;
mLandscape = landscape;
@@ -3136,6 +3321,7 @@
RemoteViews smallestView = findSmallestRemoteView();
mApplication = smallestView.mApplication;
mLayoutId = smallestView.mLayoutId;
+ mViewId = smallestView.mViewId;
mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
}
@@ -3253,6 +3439,7 @@
ApplicationInfo.CREATOR.createFromParcel(parcel);
mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel);
mLayoutId = parcel.readInt();
+ mViewId = parcel.readInt();
mLightBackgroundLayoutId = parcel.readInt();
readActionsFromParcel(parcel, depth);
@@ -3273,6 +3460,7 @@
RemoteViews smallestView = findSmallestRemoteView();
mApplication = smallestView.mApplication;
mLayoutId = smallestView.mLayoutId;
+ mViewId = smallestView.mViewId;
mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
} else {
// MODE_HAS_LANDSCAPE_AND_PORTRAIT
@@ -3281,6 +3469,7 @@
mClassCookies);
mApplication = mPortrait.mApplication;
mLayoutId = mPortrait.mLayoutId;
+ mViewId = mPortrait.mViewId;
mLightBackgroundLayoutId = mPortrait.mLightBackgroundLayoutId;
}
mApplyFlags = parcel.readInt();
@@ -3458,6 +3647,29 @@
}
/**
+ * Equivalent to calling {@link ViewGroup#addView(View)} after inflating the given
+ * {@link RemoteViews}. If the {@link RemoteViews} may be re-inflated or updated,
+ * {@link #removeAllViews(int)} must be called on the same {@code viewId
+ * } before the first call to this method for the behavior of this method to be predictable.
+ *
+ * The {@code stableId} will be used to identify a potential view to recycled when the remote
+ * view is inflated. Views can be re-used if inserted in the same order, potentially with
+ * some views appearing / disappearing.
+ *
+ * Note: if a view is re-used, all the actions will be re-applied on it. However, its properties
+ * are not reset, so what was applied in previous round will have an effect. As a view may be
+ * re-created at any time by the host, the RemoteViews should not rely on keeping information
+ * from previous applications and always re-set all the properties they need.
+ *
+ * @param viewId The id of the parent {@link ViewGroup} to add child into.
+ * @param nestedView {@link RemoteViews} that describes the child.
+ * @param stableId An id that is stable across different versions of RemoteViews.
+ */
+ public void addStableView(@IdRes int viewId, @NonNull RemoteViews nestedView, int stableId) {
+ addAction(new ViewGroupActionAdd(viewId, nestedView, -1 /* index */, stableId));
+ }
+
+ /**
* Equivalent to calling {@link ViewGroup#addView(View, int)} after inflating the
* given {@link RemoteViews}.
*
@@ -4870,23 +5082,24 @@
public CancellationSignal applyAsync(Context context, ViewGroup parent,
Executor executor, OnViewAppliedListener listener, InteractionHandler handler,
SizeF size) {
- return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */)
- .startTaskOnExecutor(executor);
+ return applyAsync(context, parent, executor, listener, handler, size,
+ null /* themeColors */);
}
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
- return getAsyncApplyTask(context, parent, listener, handler, size, colorResources)
- .startTaskOnExecutor(executor);
+ return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
+ handler, colorResources, null /* result */,
+ true /* topLevel */).startTaskOnExecutor(executor);
}
- private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
+ private AsyncApplyTask getInternalAsyncApplyTask(Context context, ViewGroup parent,
OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
- ColorResources colorResources) {
+ ColorResources colorResources, View result) {
return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
- handler, colorResources, null /* result */);
+ handler, colorResources, result, false /* topLevel */);
}
private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
@@ -4898,6 +5111,12 @@
final OnViewAppliedListener mListener;
final InteractionHandler mHandler;
final ColorResources mColorResources;
+ /**
+ * Whether the remote view is the top-level one (i.e. not within an action).
+ *
+ * This is only used if the result is specified (i.e. the view is being recycled).
+ */
+ final boolean mTopLevel;
private View mResult;
private ViewTree mTree;
@@ -4906,13 +5125,15 @@
private AsyncApplyTask(
RemoteViews rv, ViewGroup parent, Context context, OnViewAppliedListener listener,
- InteractionHandler handler, ColorResources colorResources, View result) {
+ InteractionHandler handler, ColorResources colorResources,
+ View result, boolean topLevel) {
mRV = rv;
mParent = parent;
mContext = context;
mListener = listener;
mColorResources = colorResources;
mHandler = handler;
+ mTopLevel = topLevel;
mResult = result;
}
@@ -4959,6 +5180,10 @@
a.apply(viewTree.mRoot, mParent, handler, mColorResources);
}
}
+ // If the parent of the view is has is a root, resolve the recycling.
+ if (mTopLevel && mResult instanceof ViewGroup) {
+ finalizeViewRecycling((ViewGroup) mResult);
+ }
} catch (Exception e) {
mError = e;
}
@@ -5011,6 +5236,14 @@
/** @hide */
public void reapply(Context context, View v, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
+ reapply(context, v, handler, size, colorResources, true);
+ }
+
+ // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls
+ // should set it to false.
+ private void reapply(Context context, View v, InteractionHandler handler, SizeF size,
+ ColorResources colorResources, boolean topLevel) {
+
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
// In the case that a view has this RemoteViews applied in one orientation or size, is
@@ -5025,6 +5258,11 @@
}
rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources);
+
+ // If the parent of the view is has is a root, resolve the recycling.
+ if (topLevel && v instanceof ViewGroup) {
+ finalizeViewRecycling((ViewGroup) v);
+ }
}
/**
@@ -5068,8 +5306,8 @@
}
return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
- context, listener, handler, colorResources, v).startTaskOnExecutor(
- executor);
+ context, listener, handler, colorResources, v, true /* topLevel */)
+ .startTaskOnExecutor(executor);
}
private void performApply(View v, ViewGroup parent, InteractionHandler handler,
@@ -5282,6 +5520,7 @@
mIdealSize.writeToParcel(dest, flags);
}
dest.writeInt(mLayoutId);
+ dest.writeInt(mViewId);
dest.writeInt(mLightBackgroundLayoutId);
writeActionsToParcel(dest);
} else if (hasSizedRemoteViews()) {
@@ -5470,6 +5709,14 @@
mChildren.add(index, child);
}
+ public void removeChildren(int start, int count) {
+ if (mChildren != null) {
+ for (int i = 0; i < count; i++) {
+ mChildren.remove(start);
+ }
+ }
+ }
+
private void addViewChild(View v) {
// ViewTree only contains Views which can be found using findViewById.
// If isRootNamespace is true, this view is skipped.
@@ -5500,6 +5747,28 @@
}
}
}
+
+ /** Find the first child for which the condition is true and return its index. */
+ public int findChildIndex(Predicate<View> condition) {
+ return findChildIndex(0, condition);
+ }
+
+ /**
+ * Find the first child, starting at {@code startIndex}, for which the condition is true and
+ * return its index.
+ */
+ public int findChildIndex(int startIndex, Predicate<View> condition) {
+ if (mChildren == null) {
+ return -1;
+ }
+
+ for (int i = startIndex; i < mChildren.size(); i++) {
+ if (condition.test(mChildren.get(i).mRoot)) {
+ return i;
+ }
+ }
+ return -1;
+ }
}
/**
@@ -5758,9 +6027,9 @@
}
/**
- * Set the ID of the top-level view of the XML layout.
+ * Set the ID of the top-level view of the XML layout.
*
- * Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout.
+ * Set to {@link View#NO_ID} to reset and simply keep the id defined in the XML layout.
*
* @throws UnsupportedOperationException if the method is called on a RemoteViews defined in
* term of other RemoteViews (e.g. {@link #RemoteViews(RemoteViews, RemoteViews)}).
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9e97f9a..dba7fa9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -503,7 +503,7 @@
private boolean mImeIsConsumingInput;
// Whether cursor is visible without regard to {@link mImeConsumesInput}.
- // {code true} is the default value.
+ // {@code true} is the default value.
private boolean mCursorVisibleFromAttr = true;
static class Drawables {
@@ -9317,7 +9317,7 @@
}
for (int i = 0; i < n; i++) {
- max = Math.max(max, layout.getLineWidth(i));
+ max = Math.max(max, layout.getLineMax(i));
}
return (int) Math.ceil(max);
@@ -10571,6 +10571,17 @@
return mEditor == null ? true : mEditor.mCursorVisible;
}
+ /**
+ * @return whether cursor is visible without regard to {@code mImeIsConsumingInput}.
+ * {@code true} is the default value.
+ *
+ * @see #setCursorVisible(boolean)
+ * @hide
+ */
+ public boolean isCursorVisibleFromAttr() {
+ return mCursorVisibleFromAttr;
+ }
+
private boolean canMarquee() {
int width = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
return width > 0 && (mLayout.getLineWidth(0) > width
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index 8f541d0..3eb35c2 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -18,6 +18,7 @@
import android.view.SurfaceControl;
import android.app.ActivityManager;
+import android.graphics.Rect;
import android.window.StartingWindowInfo;
import android.window.WindowContainerToken;
@@ -38,8 +39,12 @@
/**
* Called when the Task want to remove the starting window.
+ * @param leash A persistent leash for the top window in this task.
+ * @param frame Window frame of the top window.
+ * @param playRevealAnimation Play vanish animation.
*/
- void removeStartingWindow(int taskId);
+ void removeStartingWindow(int taskId, in SurfaceControl leash, in Rect frame,
+ in boolean playRevealAnimation);
/**
* Called when the Task want to copy the splash screen.
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 35ccfca..da445b8 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -46,6 +46,8 @@
import com.android.internal.R;
import com.android.internal.policy.DecorView;
+import java.util.function.Consumer;
+
/**
* <p>The view which allows an activity to customize its splash screen exit animation.</p>
*
@@ -77,7 +79,8 @@
private Animatable mAnimatableIcon;
private ValueAnimator mAnimator;
-
+ private Runnable mAnimationFinishListener;
+ private Consumer<Canvas> mOnDrawCallback;
// cache original window and status
private Window mWindow;
private boolean mDrawBarBackground;
@@ -85,7 +88,7 @@
private int mNavigationBarColor;
/**
- * Internal builder to create a SplashScreenWindowView object.
+ * Internal builder to create a SplashScreenView object.
* @hide
*/
public static class Builder {
@@ -391,7 +394,7 @@
* Get the initial background color of this view.
* @hide
*/
- @ColorInt int getInitBackgroundColor() {
+ public @ColorInt int getInitBackgroundColor() {
return mInitBackgroundColor;
}
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index d1c1e40..c7672dc 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -126,6 +126,12 @@
*/
public int splashScreenThemeResId;
+ /**
+ * Is keyguard occluded on default display.
+ * @hide
+ */
+ public boolean isKeyguardOccluded = false;
+
public StartingWindowInfo() {
}
@@ -147,6 +153,7 @@
dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
dest.writeTypedObject(mainWindowLayoutParams, flags);
dest.writeInt(splashScreenThemeResId);
+ dest.writeBoolean(isKeyguardOccluded);
}
void readFromParcel(@NonNull Parcel source) {
@@ -157,6 +164,7 @@
WindowManager.LayoutParams.CREATOR);
mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR);
splashScreenThemeResId = source.readInt();
+ isKeyguardOccluded = source.readBoolean();
}
@Override
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 04020ec..3340cf4 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -24,6 +24,7 @@
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityManager;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.SurfaceControl;
@@ -100,9 +101,14 @@
/**
* Called when the Task want to remove the starting window.
+ * @param leash A persistent leash for the top window in this task. Release it once exit
+ * animation has finished.
+ * @param frame Window frame of the top window.
+ * @param playRevealAnimation Play vanish animation.
*/
@BinderThread
- public void removeStartingWindow(int taskId) {}
+ public void removeStartingWindow(int taskId, @Nullable SurfaceControl leash,
+ @Nullable Rect frame, boolean playRevealAnimation) {}
/**
* Called when the Task want to copy the splash screen.
@@ -217,15 +223,16 @@
private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
@Override
-
public void addStartingWindow(StartingWindowInfo windowInfo,
IBinder appToken) {
mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
}
@Override
- public void removeStartingWindow(int taskId) {
- mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId));
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
+ mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId, leash, frame,
+ playRevealAnimation));
}
@Override
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index c1952c7..957e4169 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -166,4 +166,15 @@
/** {@hide} */
boolean setChargingStateUpdateDelayMillis(int delay);
+
+ /** Exposed as a test API. */
+ void setChargerAcOnline(boolean online, boolean forceUpdate);
+ /** Exposed as a test API. */
+ void setBatteryLevel(int level, boolean forceUpdate);
+ /** Exposed as a test API. */
+ void unplugBattery(boolean forceUpdate);
+ /** Exposed as a test API. */
+ void resetBattery(boolean forceUpdate);
+ /** Exposed as a test API. */
+ void suspendBatteryInput();
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index ccb980e..592f7c7 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -21,6 +21,7 @@
import android.media.permission.Identity;
import android.os.Bundle;
import android.os.RemoteCallback;
+import android.os.SharedMemory;
import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
@@ -225,14 +226,19 @@
IBinder client);
/**
- * Sets hotword detection configuration.
+ * Set configuration and pass read-only data to hotword detection service.
*
- * Note: Currently it will trigger hotword detection service after calling this function when
- * all conditions meet the requirements.
- *
- * @param options Config data.
- * @return {@link VoiceInteractionService#HOTWORD_CONFIG_SUCCESS} in case of success,
- * {@link VoiceInteractionService#HOTWORD_CONFIG_FAILURE} in case of failure.
+ * @param options Application configuration data provided by the
+ * {@link VoiceInteractionService}. The system strips out any remotable objects or other
+ * contents that can be used to communicate with other processes.
+ * @param sharedMemory The unrestricted data blob provided by the
+ * {@link VoiceInteractionService}. Use this to provide the hotword models data or other
+ * such data to the trusted process.
*/
- int setHotwordDetectionConfig(in Bundle options);
+ void setHotwordDetectionServiceConfig(in Bundle options, in SharedMemory sharedMemory);
+
+ /**
+ * Requests to shutdown hotword detection service.
+ */
+ void shutdownHotwordDetectionService();
}
diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
index 0b937fa..364db06 100644
--- a/core/java/com/android/internal/compat/AndroidBuildClassifier.java
+++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java
@@ -31,4 +31,14 @@
public boolean isFinalBuild() {
return "REL".equals(Build.VERSION.CODENAME);
}
+
+ /**
+ * The current platform SDK version.
+ */
+ public int platformTargetSdk() {
+ if (isFinalBuild()) {
+ return Build.VERSION.SDK_INT;
+ }
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
}
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index c0bbe50..e408be2 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -34,7 +34,8 @@
DISABLED_NON_TARGET_SDK,
DISABLED_TARGET_SDK_TOO_HIGH,
DEFERRED_VERIFICATION,
- LOGGING_ONLY_CHANGE
+ LOGGING_ONLY_CHANGE,
+ PLATFORM_TOO_OLD
})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
@@ -65,6 +66,10 @@
* Change is marked as logging only, and cannot be toggled.
*/
public static final int LOGGING_ONLY_CHANGE = 5;
+ /**
+ * Change is gated by a target sdk version newer than the current platform sdk version.
+ */
+ public static final int PLATFORM_TOO_OLD = 6;
@State
public final int state;
@@ -123,6 +128,11 @@
throw new SecurityException(String.format(
"Cannot override %1$d because it is marked as a logging-only change.",
changeId));
+ case PLATFORM_TOO_OLD:
+ throw new SecurityException(String.format(
+ "Cannot override %1$d for %2$s because the change's targetSdk threshold "
+ + "(%3$d) is above the platform sdk.",
+ changeId, packageName, changeIdTargetSdk));
}
}
@@ -170,6 +180,8 @@
return "DEFERRED_VERIFICATION";
case LOGGING_ONLY_CHANGE:
return "LOGGING_ONLY_CHANGE";
+ case PLATFORM_TOO_OLD:
+ return "PLATFORM_TOO_OLD";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
index b4f216b..1d865c2 100644
--- a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java
@@ -75,7 +75,7 @@
// Note: they don't _have_ to be ignored, for example, we could instead turn them
// opaque. Traditionally, including outside Android, quantizers ignore transparent
// pixels, so that strategy was chosen.
- int alpha = (pixel >> 24);
+ int alpha = (pixel >> 24) & 0xff;
if (alpha < 255) {
continue;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9ecb0ad..11466f4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6976,6 +6976,11 @@
return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_DOZE);
}
+ @Override
+ public long getCpuMeasuredBatteryConsumptionUC() {
+ return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
+ }
+
/**
* Returns the consumption (in microcoulombs) that the given standard power bucket consumed.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable
@@ -8482,6 +8487,11 @@
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON);
}
+ @Override
+ public long getCpuMeasuredBatteryConsumptionUC() {
+ return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_CPU);
+ }
+
void initNetworkActivityLocked() {
detachIfNotNull(mNetworkByteActivityCounters);
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 97f727b..b15543a 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -85,12 +85,14 @@
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
- calculateApp(app, app.getBatteryStatsUid(), result);
+ calculateApp(app, app.getBatteryStatsUid(), query, result);
}
}
- private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, Result result) {
- calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED, result);
+ private void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
+ BatteryUsageStatsQuery query, Result result) {
+ calculatePowerAndDuration(u, BatteryStats.STATS_SINCE_CHARGED,
+ query.shouldForceUsePowerProfileModel(), result);
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, result.powerMah)
.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, result.durationMs)
@@ -112,7 +114,7 @@
}
private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, Result result) {
- calculatePowerAndDuration(u, statsType, result);
+ calculatePowerAndDuration(u, statsType, false, result);
app.cpuPowerMah = result.powerMah;
app.cpuTimeMs = result.durationMs;
@@ -120,46 +122,16 @@
app.packageWithHighestDrain = result.packageWithHighestDrain;
}
- private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType, Result result) {
+ private void calculatePowerAndDuration(BatteryStats.Uid u, int statsType,
+ boolean forceUsePowerProfileModel, Result result) {
long durationMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
- // Constant battery drain when CPU is active
- double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
-
- // Additional per-cluster battery drain
- long[] cpuClusterTimes = u.getCpuClusterTimes();
- if (cpuClusterTimes != null) {
- if (cpuClusterTimes.length == mNumCpuClusters) {
- for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
- double power = calculatePerCpuClusterPowerMah(cluster,
- cpuClusterTimes[cluster]);
- powerMah += power;
- if (DEBUG) {
- Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
- + " clusterTimeMs=" + cpuClusterTimes[cluster]
- + " power=" + formatCharge(power));
- }
- }
- } else {
- Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
- + mNumCpuClusters + " actual # " + cpuClusterTimes.length);
- }
- }
-
- // Additional per-frequency battery drain
- for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
- final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length;
- for (int speed = 0; speed < speedsForCluster; speed++) {
- final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
- final double power = calculatePerCpuFreqPowerMah(cluster, speed,
- timeUs / 1000);
- if (DEBUG) {
- Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
- + speed + " timeUs=" + timeUs + " power="
- + formatCharge(power));
- }
- powerMah += power;
- }
+ final double powerMah;
+ final long consumptionUC = u.getCpuMeasuredBatteryConsumptionUC();
+ if (forceUsePowerProfileModel || consumptionUC == BatteryStats.POWER_DATA_UNAVAILABLE) {
+ powerMah = calculateUidModeledPowerMah(u, statsType);
+ } else {
+ powerMah = uCtoMah(consumptionUC);
}
if (DEBUG && (durationMs != 0 || powerMah != 0)) {
@@ -208,6 +180,48 @@
result.packageWithHighestDrain = packageWithHighestDrain;
}
+ private double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
+ // Constant battery drain when CPU is active
+ double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
+
+ // Additional per-cluster battery drain
+ long[] cpuClusterTimes = u.getCpuClusterTimes();
+ if (cpuClusterTimes != null) {
+ if (cpuClusterTimes.length == mNumCpuClusters) {
+ for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
+ double power = calculatePerCpuClusterPowerMah(cluster,
+ cpuClusterTimes[cluster]);
+ powerMah += power;
+ if (DEBUG) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster
+ + " clusterTimeMs=" + cpuClusterTimes[cluster]
+ + " power=" + formatCharge(power));
+ }
+ }
+ } else {
+ Log.w(TAG, "UID " + u.getUid() + " CPU cluster # mismatch: Power Profile # "
+ + mNumCpuClusters + " actual # " + cpuClusterTimes.length);
+ }
+ }
+
+ // Additional per-frequency battery drain
+ for (int cluster = 0; cluster < mNumCpuClusters; cluster++) {
+ final int speedsForCluster = mPerCpuFreqPowerEstimators[cluster].length;
+ for (int speed = 0; speed < speedsForCluster; speed++) {
+ final long timeUs = u.getTimeAtCpuSpeed(cluster, speed, statsType);
+ final double power = calculatePerCpuFreqPowerMah(cluster, speed,
+ timeUs / 1000);
+ if (DEBUG) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
+ + speed + " timeUs=" + timeUs + " power="
+ + formatCharge(power));
+ }
+ powerMah += power;
+ }
+ }
+ return powerMah;
+ }
+
/**
* Calculates active CPU power consumption.
*
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 200e0dd..fea0751 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -257,4 +257,12 @@
* file descriptor passed in.
*/
void passThroughShellCommand(in String[] args, in ParcelFileDescriptor pfd);
+
+ /**
+ * Enables/disables the navigation bar luma sampling.
+ *
+ * @param displayId the id of the display to notify.
+ * @param enable {@code true} if enable, otherwise set to {@code false}.
+ */
+ void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable);
}
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 85114e5..b57b4b9 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -72,5 +72,5 @@
void onBarringInfoChanged(in BarringInfo barringInfo);
void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs);
void onDataEnabledChanged(boolean enabled, int reason);
- void onAllowedNetworkTypesChanged(in Map allowedNetworkTypeList);
+ void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType);
}
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 95e0a3b..83691ee 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -95,5 +95,5 @@
void notifyPhysicalChannelConfigForSubscriber(in int subId,
in List<PhysicalChannelConfig> configs);
void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason);
- void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in Map allowedNetworkTypeList);
+ void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType);
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 19506a3..d0c807d 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -31,8 +31,10 @@
import android.util.imetracing.InputConnectionHelper;
import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
+import android.view.View;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.DumpableInputConnection;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
@@ -49,7 +51,9 @@
import com.android.internal.inputmethod.ISurroundingTextResultCallback;
import com.android.internal.os.SomeArgs;
-public abstract class IInputConnectionWrapper extends IInputContext.Stub {
+import java.lang.ref.WeakReference;
+
+public final class IInputConnectionWrapper extends IInputContext.Stub {
private static final String TAG = "IInputConnectionWrapper";
private static final boolean DEBUG = false;
@@ -90,10 +94,13 @@
private Looper mMainLooper;
private Handler mH;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private Object mLock = new Object();
+ private final Object mLock = new Object();
@GuardedBy("mLock")
private boolean mFinished = false;
+ private final InputMethodManager mParentInputMethodManager;
+ private final WeakReference<View> mServedView;
+
class MyHandler extends Handler {
MyHandler(Looper looper) {
super(looper);
@@ -104,11 +111,15 @@
executeMessage(msg);
}
}
-
- public IInputConnectionWrapper(Looper mainLooper, @NonNull InputConnection inputConnection) {
+
+ public IInputConnectionWrapper(@NonNull Looper mainLooper,
+ @NonNull InputConnection inputConnection,
+ @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) {
mInputConnection = inputConnection;
mMainLooper = mainLooper;
mH = new MyHandler(mMainLooper);
+ mParentInputMethodManager = inputMethodManager;
+ mServedView = new WeakReference<>(servedView);
}
@Nullable
@@ -118,21 +129,70 @@
}
}
- protected Looper getLooper() {
- synchronized (mMainLooper) {
- return mMainLooper;
- }
- }
-
- protected boolean isFinished() {
+ private boolean isFinished() {
synchronized (mLock) {
return mFinished;
}
}
- protected abstract boolean isActive();
+ public boolean isActive() {
+ return mParentInputMethodManager.isActive() && !isFinished();
+ }
- protected abstract InputMethodManager getIMM();
+ public View getServedView() {
+ return mServedView.get();
+ }
+
+ public void deactivate() {
+ if (isFinished()) {
+ // This is a small performance optimization. Still only the 1st call of
+ // reportFinish() will take effect.
+ return;
+ }
+ closeConnection();
+
+ // Notify the app that the InputConnection was closed.
+ final View servedView = mServedView.get();
+ if (servedView != null) {
+ final Handler handler = servedView.getHandler();
+ // The handler is null if the view is already detached. When that's the case, for
+ // now, we simply don't dispatch this callback.
+ if (handler != null) {
+ if (DEBUG) {
+ Log.v(TAG, "Calling View.onInputConnectionClosed: view=" + servedView);
+ }
+ if (handler.getLooper().isCurrentThread()) {
+ servedView.onInputConnectionClosedInternal();
+ } else {
+ handler.post(servedView::onInputConnectionClosedInternal);
+ }
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "IInputConnectionWrapper{"
+ + "connection=" + getInputConnection()
+ + " finished=" + isFinished()
+ + " mParentInputMethodManager.isActive()=" + mParentInputMethodManager.isActive()
+ + " mServedView=" + mServedView.get()
+ + "}";
+ }
+
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ synchronized (mLock) {
+ // Check that the call is initiated in the main thread of the current InputConnection
+ // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
+ // executed on this thread. Otherwise the messages are dispatched to the correct thread
+ // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
+ // reasons.
+ if ((mInputConnection instanceof DumpableInputConnection)
+ && Looper.myLooper() == mMainLooper) {
+ ((DumpableInputConnection) mInputConnection).dumpDebug(proto, fieldId);
+ }
+ }
+ }
public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
@@ -161,6 +221,10 @@
dispatchMessage(mH.obtainMessage(DO_GET_SURROUNDING_TEXT, flags, 0 /* unused */, args));
}
+ public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ // no-op
+ }
+
public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
dispatchMessage(
mH.obtainMessage(DO_GET_CURSOR_CAPS_MODE, reqModes, 0 /* unused */, callback));
@@ -309,7 +373,7 @@
icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
msg.arg2, result);
ImeTracing.getInstance().triggerClientDump(
- TAG + "#getTextAfterCursor", getIMM(), icProto);
+ TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
@@ -339,7 +403,7 @@
icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
msg.arg2, result);
ImeTracing.getInstance().triggerClientDump(
- TAG + "#getTextBeforeCursor", getIMM(), icProto);
+ TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
@@ -368,7 +432,7 @@
if (ImeTracing.getInstance().isEnabled()) {
icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
ImeTracing.getInstance().triggerClientDump(
- TAG + "#getSelectedText", getIMM(), icProto);
+ TAG + "#getSelectedText", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
@@ -402,7 +466,7 @@
icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
afterLength, flags, result);
ImeTracing.getInstance().triggerClientDump(
- TAG + "#getSurroundingText", getIMM(), icProto);
+ TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
@@ -432,7 +496,7 @@
icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
result);
ImeTracing.getInstance().triggerClientDump(
- TAG + "#getCursorCapsMode", getIMM(), icProto);
+ TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
@@ -464,7 +528,7 @@
icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
msg.arg1, result);
ImeTracing.getInstance().triggerClientDump(
- TAG + "#getExtractedText", getIMM(), icProto);
+ TAG + "#getExtractedText", mParentInputMethodManager, icProto);
}
try {
callback.onResult(result);
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index d284d51..8e68be0 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -1,4 +1,6 @@
per-file PointerLocationView.java = michaelwr@google.com, svv@google.com
+per-file RecyclerView.java = mount@google.com
+per-file ViewPager.java = mount@google.com
# LockSettings related
per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3bc0ef4e..94ac183 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -637,6 +637,12 @@
char saveResolvedClassesDelayMsOptsBuf[
sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];
char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
+ char madviseWillNeedFileSizeVdex[
+ sizeof("-XMadviseWillNeedVdexFileSize:")-1 + PROPERTY_VALUE_MAX];
+ char madviseWillNeedFileSizeOdex[
+ sizeof("-XMadviseWillNeedOdexFileSize:")-1 + PROPERTY_VALUE_MAX];
+ char madviseWillNeedFileSizeArt[
+ sizeof("-XMadviseWillNeedArtFileSize:")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -845,6 +851,22 @@
parseRuntimeOption("dalvik.vm.madvise-random", madviseRandomOptsBuf, "-XX:MadviseRandomAccess:");
/*
+ * Use default platform configuration as limits for madvising,
+ * when no properties are specified.
+ */
+ parseRuntimeOption("dalvik.vm.madvise.vdexfile.size",
+ madviseWillNeedFileSizeVdex,
+ "-XMadviseWillNeedVdexFileSize:");
+
+ parseRuntimeOption("dalvik.vm.madvise.odexfile.size",
+ madviseWillNeedFileSizeOdex,
+ "-XMadviseWillNeedOdexFileSize:");
+
+ parseRuntimeOption("dalvik.vm.madvise.artfile.size",
+ madviseWillNeedFileSizeArt,
+ "-XMadviseWillNeedArtFileSize:");
+
+ /*
* Profile related options.
*/
parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
diff --git a/core/jni/android_os_incremental_IncrementalManager.cpp b/core/jni/android_os_incremental_IncrementalManager.cpp
index 2384efa..413bcef 100644
--- a/core/jni/android_os_incremental_IncrementalManager.cpp
+++ b/core/jni/android_os_incremental_IncrementalManager.cpp
@@ -41,6 +41,10 @@
return (jboolean)IncFs_IsIncFsPath(path.c_str());
}
+static jboolean nativeIsIncrementalFd(JNIEnv* env, jobject clazz, jint fd) {
+ return (jboolean)IncFs_IsIncFsFd(fd);
+}
+
static jbyteArray nativeUnsafeGetFileSignature(JNIEnv* env, jobject clazz, jstring javaPath) {
ScopedUtfChars path(env, javaPath);
@@ -61,6 +65,7 @@
{{"nativeIsEnabled", "()Z", (void*)nativeIsEnabled},
{"nativeIsV2Available", "()Z", (void*)nativeIsV2Available},
{"nativeIsIncrementalPath", "(Ljava/lang/String;)Z", (void*)nativeIsIncrementalPath},
+ {"nativeIsIncrementalFd", "(I)Z", (void*)nativeIsIncrementalFd},
{"nativeUnsafeGetFileSignature", "(Ljava/lang/String;)[B",
(void*)nativeUnsafeGetFileSignature}};
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 96326f5..9746a07 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -34,8 +34,6 @@
#include "core_jni_helpers.h"
-using android::base::Result;
-
namespace android {
// Log debug messages about the dispatch cycle.
@@ -199,9 +197,16 @@
ScopedLocalRef<jobject> senderObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
- Result<InputPublisher::Finished> result = mInputPublisher.receiveFinishedSignal();
- if (!result.ok()) {
- const status_t status = result.error().code();
+ uint32_t publishedSeq;
+ bool handled;
+ std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)> callback =
+ [&publishedSeq, &handled](uint32_t inSeq, bool inHandled,
+ nsecs_t inConsumeTime) -> void {
+ publishedSeq = inSeq;
+ handled = inHandled;
+ };
+ status_t status = mInputPublisher.receiveFinishedSignal(callback);
+ if (status) {
if (status == WOULD_BLOCK) {
return OK;
}
@@ -210,7 +215,7 @@
return status;
}
- auto it = mPublishedSeqMap.find(result->seq);
+ auto it = mPublishedSeqMap.find(publishedSeq);
if (it == mPublishedSeqMap.end()) {
continue;
}
@@ -220,9 +225,9 @@
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, "
- "pendingEvents=%zu.",
- getInputChannelName().c_str(), seq, result->handled ? "true" : "false",
- mPublishedSeqMap.size());
+ "pendingEvents=%zu.",
+ getInputChannelName().c_str(), seq, handled ? "true" : "false",
+ mPublishedSeqMap.size());
}
if (!skipCallbacks) {
@@ -236,9 +241,8 @@
}
env->CallVoidMethod(senderObj.get(),
- gInputEventSenderClassInfo.dispatchInputEventFinished,
- static_cast<jint>(result->seq),
- static_cast<jboolean>(result->handled));
+ gInputEventSenderClassInfo.dispatchInputEventFinished,
+ jint(seq), jboolean(handled));
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching finished signal.");
skipCallbacks = true;
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index ebc507a..469e577 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -16,9 +16,10 @@
#include <android_runtime/AndroidRuntime.h>
-#include <input/KeyCharacterMap.h>
-#include <input/Input.h>
#include <binder/Parcel.h>
+#include <input/Input.h>
+#include <input/InputDevice.h>
+#include <input/KeyCharacterMap.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
@@ -75,6 +76,10 @@
reinterpret_cast<jlong>(nativeMap));
}
+static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) {
+ return android_view_KeyCharacterMap_create(env, deviceId, nullptr);
+}
+
static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (!parcel) {
@@ -224,33 +229,37 @@
return result;
}
+static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) {
+ const std::shared_ptr<KeyCharacterMap>& map1 =
+ (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap();
+ const std::shared_ptr<KeyCharacterMap>& map2 =
+ (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap();
+ if (map1 == nullptr || map2 == nullptr) {
+ return map1 == map2;
+ }
+ return static_cast<jboolean>(*map1 == *map2);
+}
/*
* JNI registration.
*/
static const JNINativeMethod g_methods[] = {
- /* name, signature, funcPtr */
- { "nativeReadFromParcel", "(Landroid/os/Parcel;)J",
- (void*)nativeReadFromParcel },
- { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
- (void*)nativeWriteToParcel },
- { "nativeDispose", "(J)V",
- (void*)nativeDispose },
- { "nativeGetCharacter", "(JII)C",
- (void*)nativeGetCharacter },
- { "nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z",
- (void*)nativeGetFallbackAction },
- { "nativeGetNumber", "(JI)C",
- (void*)nativeGetNumber },
- { "nativeGetMatch", "(JI[CI)C",
- (void*)nativeGetMatch },
- { "nativeGetDisplayLabel", "(JI)C",
- (void*)nativeGetDisplayLabel },
- { "nativeGetKeyboardType", "(J)I",
- (void*)nativeGetKeyboardType },
- { "nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;",
- (void*)nativeGetEvents },
+ /* name, signature, funcPtr */
+ {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel},
+ {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel},
+ {"nativeDispose", "(J)V", (void*)nativeDispose},
+ {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter},
+ {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z",
+ (void*)nativeGetFallbackAction},
+ {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber},
+ {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch},
+ {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel},
+ {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType},
+ {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents},
+ {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;",
+ (void*)nativeObtainEmptyKeyCharacterMap},
+ {"nativeEquals", "(JJ)Z", (void*)nativeEquals},
};
int register_android_view_KeyCharacterMap(JNIEnv* env)
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index cf96fe6..0bed29b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -193,7 +193,7 @@
* If it exceeds 2s, PROC_START_TIMEOUT_MSG will kill the starting app anyway,
* so it's fine to assume max retries is 5 mins.
*/
-static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 60 * 5;
+static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5;
/**
* A helper class containing accounting information for USAPs.
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index e62b5c1..ea5e7f72 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -14,9 +14,10 @@
# Frameworks
ogunwale@google.com
jjaggi@google.com
+kwekua@google.com
roosa@google.com
per-file package_item_info.proto = toddke@google.com
-per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
+per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/android/app/usage/OWNERS
per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
# Biometrics
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index f26bf7c..a7127ad 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -346,6 +346,7 @@
optional int32 proc_id = 29;
optional bool translucent = 30;
optional bool pip_auto_enter_enabled = 31;
+ optional bool in_size_compat_mode = 32;
}
/* represents WindowToken */
@@ -406,7 +407,7 @@
optional int64 finished_seamless_rotation_frame = 40;
optional WindowFramesProto window_frames = 41;
optional bool force_seamless_rotation = 42;
- optional bool in_size_compat_mode = 43;
+ optional bool has_compat_scale = 43;
optional float global_scale = 44;
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7c446a9..5412db6 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8173,7 +8173,7 @@
<flag name="hide_from_picker" value="0x2" />
<!-- The widget provides a default configuration. The host may decide not to launch
the provided configuration activity. -->
- <flag name="configuration_optional" value="0x3" />
+ <flag name="configuration_optional" value="0x4" />
</attr>
<!-- A resource identifier for a string containing a short description of the widget. -->
<attr name="description" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cc52655ad7..601d66e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -829,7 +829,6 @@
{@code FLAG_ACTIVITY_MULTIPLE_TASK} is set.-->
<enum name="singleInstancePerTask" value="4" />
</attr>
-
<!-- Specify the orientation an activity should be run in. If not
specified, it will run in the current preferred orientation
of the screen.
@@ -1603,6 +1602,12 @@
<enum name="sync" value="2" />
</attr>
+ <!-- Attribution tag to be used for permission sub-attribution if a
+ permission is checked in {@link android.content.Context#sendBroadcast(Intent, String)}.
+ Multiple tags can be specified separated by '|'.
+ -->
+ <attr name="attributionTags" format="string" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -2825,6 +2830,10 @@
<p> See {@link android.content.pm.ActivityInfo#FLAG_PREFER_MINIMAL_POST_PROCESSING} -->
<attr name="preferMinimalPostProcessing" format="boolean"/>
+ <!-- Specify the attributionTags to be used if a permission is required due to
+ {@link android.content.Context#sendBroadcast(Intent, String)} being used.
+ Multiple tags can be specified separated by '|'. -->
+ <attr name="attributionTags"/>
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 397c646..f6fee88 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -324,9 +324,6 @@
<item>"0,1"</item>
</string-array>
- <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
- <integer name="config_networkTransitionTimeout">60000</integer>
-
<!-- Whether/how to notify the user on network switches. See LingerMonitor.java. -->
<integer translatable="false" name="config_networkNotifySwitchType">0</integer>
@@ -339,16 +336,6 @@
Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
<integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
- <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
- If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
- and if that value is empty, the framework will use a hard-coded default.
- This is *NOT* a URL that will always be used by the system network validation to detect
- captive portals: NetworkMonitor may use different strategies and will not necessarily use
- this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
- instead. -->
- <!--suppress CheckTagEmptyBody -->
- <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
-
<!-- If the hardware supports specially marking packets that caused a wakeup of the
main CPU, set this value to the mark used. -->
<integer name="config_networkWakeupPacketMark">0</integer>
@@ -456,14 +443,6 @@
apps requested it. -->
<bool name="config_vehicleInternalNetworkAlwaysRequested">false</bool>
- <!-- Configuration of network interfaces that support WakeOnLAN -->
- <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
- <!--
- <item>wlan0</item>
- <item>eth0</item>
- -->
- </string-array>
-
<!-- This setting is deprecated, please use
com.android.networkstack.tethering.R.array.config_mobile_hotspot_provision_app instead. -->
<string-array translatable="false" name="config_mobile_hotspot_provision_app">
@@ -4743,4 +4722,97 @@
<!-- Whether to allow the caching of the SIM PIN for verification after unattended reboot -->
<bool name="config_allow_pin_storage_for_unattended_reboot">true</bool>
+
+ <!-- CEC Configuration -->
+ <bool name="config_cecHdmiCecEnabled_userConfigurable">true</bool>
+ <bool name="config_cecHdmiCecControlEnabled_allowed">true</bool>
+ <bool name="config_cecHdmiCecControlEnabled_default">true</bool>
+ <bool name="config_cecHdmiCecControlDisabled_allowed">true</bool>
+ <bool name="config_cecHdmiCecControlDisabled_default">false</bool>
+
+ <bool name="config_cecHdmiCecVersion_userConfigurable">true</bool>
+ <bool name="config_cecHdmiCecVersion14b_allowed">true</bool>
+ <bool name="config_cecHdmiCecVersion14b_default">true</bool>
+ <bool name="config_cecHdmiCecVersion20_allowed">true</bool>
+ <bool name="config_cecHdmiCecVersion20_default">false</bool>
+
+ <bool name="config_cecSendStandbyOnSleep_userConfigurable">true</bool>
+ <bool name="config_cecPowerControlModeTv_allowed">true</bool>
+ <bool name="config_cecPowerControlModeTv_default">true</bool>
+ <bool name="config_cecPowerControlModeBroadcast_allowed">true</bool>
+ <bool name="config_cecPowerControlModeBroadcast_default">false</bool>
+ <bool name="config_cecPowerControlModeNone_allowed">true</bool>
+ <bool name="config_cecPowerControlModeNone_default">false</bool>
+
+ <bool name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostNone_default">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed">true</bool>
+ <bool name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default">false</bool>
+
+ <bool name="config_cecSystemAudioModeMuting_userConfigurable">true</bool>
+ <bool name="config_cecSystemAudioModeMutingEnabled_allowed">true</bool>
+ <bool name="config_cecSystemAudioModeMutingEnabled_default">true</bool>
+ <bool name="config_cecSystemAudioModeMutingDisabled_allowed">true</bool>
+ <bool name="config_cecSystemAudioModeMutingDisabled_default">false</bool>
+
+ <bool name="config_cecVolumeControlMode_userConfigurable">true</bool>
+ <bool name="config_cecVolumeControlModeEnabled_allowed">true</bool>
+ <bool name="config_cecVolumeControlModeEnabled_default">true</bool>
+ <bool name="config_cecVolumeControlModeDisabled_allowed">true</bool>
+ <bool name="config_cecVolumeControlModeDisabled_default">false</bool>
+
+ <bool name="config_cecTvWakeOnOneTouchPlay_userConfigurable">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayEnabled_allowed">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayEnabled_default">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayDisabled_allowed">true</bool>
+ <bool name="config_cecTvWakeOnOneTouchPlayDisabled_default">false</bool>
+
+ <bool name="config_cecTvSendStandbyOnSleep_userConfigurable">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepEnabled_allowed">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepEnabled_default">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepDisabled_allowed">true</bool>
+ <bool name="config_cecTvSendStandbyOnSleepDisabled_default">false</bool>
+
+ <bool name="config_cecRcProfileTv_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileTvNone_allowed">true</bool>
+ <bool name="config_cecRcProfileTvNone_default">true</bool>
+ <bool name="config_cecRcProfileTvOne_allowed">true</bool>
+ <bool name="config_cecRcProfileTvOne_default">false</bool>
+ <bool name="config_cecRcProfileTvTwo_allowed">true</bool>
+ <bool name="config_cecRcProfileTvTwo_default">false</bool>
+ <bool name="config_cecRcProfileTvThree_allowed">true</bool>
+ <bool name="config_cecRcProfileTvThree_default">false</bool>
+ <bool name="config_cecRcProfileTvFour_allowed">true</bool>
+ <bool name="config_cecRcProfileTvFour_default">false</bool>
+
+ <bool name="config_cecRcProfileSourceRootMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuHandled_default">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceRootMenuNotHandled_default">false</bool>
+
+ <bool name="config_cecRcProfileSourceSetupMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuHandled_default">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceSetupMenuNotHandled_default">false</bool>
+
+ <bool name="config_cecRcProfileSourceContentsMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuHandled_default">false</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceContentsMenuNotHandled_default">true</bool>
+
+ <bool name="config_cecRcProfileSourceTopMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceTopMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceTopMenuHandled_default">false</bool>
+ <bool name="config_cecRcProfileSourceTopMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceTopMenuNotHandled_default">true</bool>
+
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable">true</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default">false</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed">true</bool>
+ <bool name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default">true</bool>
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 3a41d5f..7bc4663 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -247,4 +247,10 @@
<!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_IME_ENTER}. -->
<item type="id" name="accessibilityActionImeEnter" />
+
+ <!-- View tag for remote views to store the index of the next child when adding nested remote views dynamically. -->
+ <item type="id" name="remote_views_next_child" />
+
+ <!-- View tag associating a view with its stable id for potential recycling. -->
+ <item type="id" name = "remote_views_stable_id" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e0a728c..40c80db 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3087,6 +3087,7 @@
<public name="passwordsActivity"/>
<public name="selectableAsDefault"/>
<public name="isAccessibilityTool"/>
+ <public name="attributionTags"/>
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4af561b..387c065 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3691,6 +3691,8 @@
<string name="ext_media_checking_notification_title">Checking <xliff:g id="name" example="SD card">%s</xliff:g>\u2026</string>
<!-- Notification body when external media is being checked [CHAR LIMIT=NONE] -->
<string name="ext_media_checking_notification_message">Reviewing current content</string>
+ <!-- TV specific notification body when external media is being checked [CHAR LIMIT=75] -->
+ <string name="ext_media_checking_notification_message" product="tv">Analyzing media storage</string>
<!-- Notification body when new external media is detected [CHAR LIMIT=30] -->
<string name="ext_media_new_notification_title">New <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3698,11 +3700,15 @@
<string name="ext_media_new_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when new external media is detected [CHAR LIMIT=NONE] -->
<string name="ext_media_new_notification_message">Tap to set up</string>
+ <!-- TV specific notification body when new external media is detected [CHAR LIMIT=75] -->
+ <string name="ext_media_new_notification_message" product="tv">Select to set up</string>
<!-- Automotive specific notification body when new external media is detected. [CHAR LIMIT=NONE] -->
<string name="ext_media_new_notification_message" product="automotive">You may need to reformat the device. Tap to eject.</string>
<!-- Notification body when external media is ready for use [CHAR LIMIT=NONE] -->
<string name="ext_media_ready_notification_message">For transferring photos and media</string>
+ <!-- TV specific notification body when external media is ready for use [CHAR LIMIT=75] -->
+ <string name="ext_media_ready_notification_message" product="tv">Browse media files</string>
<!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
<string name="ext_media_unmountable_notification_title">Issue with <xliff:g id="name" example="SD card">%s</xliff:g></string>
@@ -3721,8 +3727,8 @@
<string name="ext_media_unsupported_notification_title" product="automotive"><xliff:g id="name" example="SD card">%s</xliff:g> isn\u2019t working</string>
<!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string>
- <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
- <string name="ext_media_unsupported_notification_message" product="tv">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Select to set up in a supported format.</string>
+ <!-- TV-specific notification body when external media is unsupported [CHAR LIMIT=75] -->
+ <string name="ext_media_unsupported_notification_message" product="tv">Select to set up <xliff:g id="name" example="SD card">%s</xliff:g> in a supported format.</string>
<!-- Automotive specific notification body when external media is unsupported [CHAR LIMIT=NONE] -->
<string name="ext_media_unsupported_notification_message" product="automotive">You may need to reformat the device</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5f4063b..5a7b1fa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -692,7 +692,6 @@
<java-symbol type="string" name="not_checked" />
<java-symbol type="array" name="config_ethernet_interfaces" />
<java-symbol type="bool" name="config_vehicleInternalNetworkAlwaysRequested" />
- <java-symbol type="array" name="config_wakeonlan_supported_interfaces" />
<java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
<java-symbol type="string" name="config_mms_user_agent" />
<java-symbol type="string" name="config_mms_user_agent_profile_url" />
@@ -1972,11 +1971,9 @@
<java-symbol type="integer" name="config_lowBatteryCloseWarningBump" />
<java-symbol type="integer" name="config_lowBatteryWarningLevel" />
<java-symbol type="integer" name="config_networkPolicyDefaultWarning" />
- <java-symbol type="integer" name="config_networkTransitionTimeout" />
<java-symbol type="integer" name="config_networkNotifySwitchType" />
<java-symbol type="array" name="config_networkNotifySwitches" />
<java-symbol type="integer" name="config_networkAvoidBadWifi" />
- <java-symbol type="string" name="config_networkCaptivePortalServerUrl" />
<java-symbol type="integer" name="config_networkWakeupPacketMark" />
<java-symbol type="integer" name="config_networkWakeupPacketMask" />
<java-symbol type="bool" name="config_apfDrop802_3Frames" />
@@ -4227,4 +4224,100 @@
<java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
<java-symbol type="bool" name="config_enableOneHandedKeyguard" />
+
+ <!-- CEC Configuration -->
+ <java-symbol type="bool" name="config_cecHdmiCecEnabled_userConfigurable" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlEnabled_default" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecControlDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecHdmiCecVersion_userConfigurable" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion14b_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion14b_default" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion20_allowed" />
+ <java-symbol type="bool" name="config_cecHdmiCecVersion20_default" />
+
+ <java-symbol type="bool" name="config_cecSendStandbyOnSleep_userConfigurable" />
+ <java-symbol type="bool" name="config_cecPowerControlModeTv_allowed" />
+ <java-symbol type="bool" name="config_cecPowerControlModeTv_default" />
+ <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_allowed" />
+ <java-symbol type="bool" name="config_cecPowerControlModeBroadcast_default" />
+ <java-symbol type="bool" name="config_cecPowerControlModeNone_allowed" />
+ <java-symbol type="bool" name="config_cecPowerControlModeNone_default" />
+
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLost_userConfigurable" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_allowed" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostNone_default" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed" />
+ <java-symbol type="bool" name="config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default" />
+
+ <java-symbol type="bool" name="config_cecSystemAudioModeMuting_userConfigurable" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingEnabled_default" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecSystemAudioModeMutingDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecVolumeControlMode_userConfigurable" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeEnabled_default" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecVolumeControlModeDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlay_userConfigurable" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayEnabled_default" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvWakeOnOneTouchPlayDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleep_userConfigurable" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepEnabled_default" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileTv_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileTvNone_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvNone_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvOne_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvOne_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvTwo_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvTwo_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvThree_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvThree_default" />
+ <java-symbol type="bool" name="config_cecRcProfileTvFour_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileTvFour_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceRootMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceSetupMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceContentsMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceTopMenuNotHandled_default" />
+
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed" />
+ <java-symbol type="bool" name="config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default" />
+
+ <java-symbol type="id" name="remote_views_next_child" />
+ <java-symbol type="id" name="remote_views_stable_id" />
</resources>
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
index f6e02bc..28f9ccc 100644
--- a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -41,7 +41,9 @@
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import android.content.res.TypedArray;
import android.text.Selection;
@@ -356,4 +358,71 @@
.perform(clearText());
}
}
+
+ @Test
+ public void testCursorVisibility() {
+ final TextView textView = getActivity().findViewById(R.id.textview);
+ final String text = "abc";
+
+ assertTrue(textView.isCursorVisible());
+
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(),
+ new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
+ setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1);
+ showSuggestionsPopup();
+
+ assertSuggestionsPopupIsDisplayed();
+ assertSuggestionsPopupContainsItem("ABC");
+ assertFalse(textView.isCursorVisible());
+
+ // Delete an item.
+ clickSuggestionsPopupItem(
+ getActivity().getString(com.android.internal.R.string.delete));
+ assertSuggestionsPopupIsNotDisplayed();
+ assertTrue(textView.isCursorVisible());
+ }
+
+ @Test
+ public void testCursorVisibilityWhenImeConsumesInput() {
+ final TextView textView = getActivity().findViewById(R.id.textview);
+ final String text = "abc";
+
+ assertTrue(textView.isCursorVisible());
+
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(replaceText(text));
+ setImeConsumesInputWithExpect(textView, true /* imeConsumesInput */,
+ false /* expectedCursorVisibility */);
+ final SuggestionSpan suggestionSpan = new SuggestionSpan(getActivity(),
+ new String[]{"ABC"}, SuggestionSpan.FLAG_AUTO_CORRECTION);
+ setSuggestionSpan(suggestionSpan, text.indexOf('a'), text.indexOf('c') + 1);
+ showSuggestionsPopup();
+
+ assertSuggestionsPopupIsDisplayed();
+ assertSuggestionsPopupContainsItem("ABC");
+ assertFalse(textView.isCursorVisible());
+
+ // Delete an item.
+ clickSuggestionsPopupItem(
+ getActivity().getString(com.android.internal.R.string.delete));
+ assertSuggestionsPopupIsNotDisplayed();
+ assertFalse(textView.isCursorVisible());
+
+ // Set IME not consumes input, cursor should be back to visible.
+ setImeConsumesInputWithExpect(textView, false /* imeConsumesInput */,
+ true /* expectedCursorVisibility */);
+ }
+
+ private void setImeConsumesInputWithExpect(
+ final TextView textView, boolean imeConsumesInput, boolean expectedCursorVisibility) {
+ textView.post(() -> textView.setImeConsumesInput(imeConsumesInput));
+ getInstrumentation().waitForIdleSync();
+ if (expectedCursorVisibility) {
+ assertTrue(textView.isCursorVisible());
+ } else {
+ assertFalse(textView.isCursorVisible());
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
index 7088890..10ff3a4 100644
--- a/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/CpuPowerCalculatorTest.java
@@ -19,18 +19,22 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.os.BatteryConsumer;
+import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.power.MeasuredEnergyStats;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -81,6 +85,10 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
+ final boolean[] supportedPowerBuckets =
+ new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
+ supportedPowerBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
+
mStatsRule.getBatteryStats()
.setUserInfoProvider(mMockUserInfoProvider)
.setKernelCpuSpeedReaders(mMockKernelCpuSpeedReaders)
@@ -88,7 +96,8 @@
.setKernelCpuUidClusterTimeReader(mMockKernelCpuUidClusterTimeReader)
.setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader)
.setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader)
- .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader);
+ .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
+ .initMeasuredEnergyStatsLocked(supportedPowerBuckets, 0);
}
@Test
@@ -103,28 +112,28 @@
// User/System CPU time
doAnswer(invocation -> {
- final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0);
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
// User/system time in microseconds
callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000});
callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000});
return null;
- }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(any());
+ }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
// Active CPU time
doAnswer(invocation -> {
- final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(0);
+ final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
callback.onUidCpuTime(APP_UID1, 1111L);
callback.onUidCpuTime(APP_UID2, 3333L);
return null;
- }).when(mMockKerneCpuUidActiveTimeReader).readDelta(any());
+ }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
// Per-cluster CPU time
doAnswer(invocation -> {
- final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(0);
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
return null;
- }).when(mMockKernelCpuUidClusterTimeReader).readDelta(any());
+ }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, null);
@@ -134,7 +143,8 @@
CpuPowerCalculator calculator =
new CpuPowerCalculator(mStatsRule.getPowerProfile());
- mStatsRule.apply(calculator);
+ mStatsRule.apply(new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build(),
+ calculator);
UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
@@ -150,4 +160,64 @@
.isWithin(PRECISION).of(2.672322);
assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
}
+
+ @Test
+ public void testMeasuredEnergyBasedModel() {
+ when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
+
+ when(mMockKernelCpuSpeedReaders[0].readDelta()).thenReturn(new long[]{1000, 2000});
+ when(mMockKernelCpuSpeedReaders[1].readDelta()).thenReturn(new long[]{3000, 4000});
+
+ when(mMockCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(false);
+
+ // User/System CPU time
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+ // User/system time in microseconds
+ callback.onUidCpuTime(APP_UID1, new long[]{1111000, 2222000});
+ callback.onUidCpuTime(APP_UID2, new long[]{3333000, 4444000});
+ return null;
+ }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
+
+ // Active CPU time
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, 1111L);
+ callback.onUidCpuTime(APP_UID2, 3333L);
+ return null;
+ }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
+
+ // Per-cluster CPU time
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
+ callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
+ return null;
+ }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
+
+ final long[] clusterChargesUC = new long[]{13577531, 24688642};
+ mStatsRule.getBatteryStats().updateCpuTimeLocked(true, true, clusterChargesUC);
+
+ mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("foo").addCpuTimeLocked(4321, 1234);
+ mStatsRule.getUidStats(APP_UID1).getProcessStatsLocked("bar").addCpuTimeLocked(5432, 2345);
+
+ CpuPowerCalculator calculator =
+ new CpuPowerCalculator(mStatsRule.getPowerProfile());
+
+ mStatsRule.apply(calculator);
+
+ UidBatteryConsumer uidConsumer1 = mStatsRule.getUidBatteryConsumer(APP_UID1);
+ assertThat(uidConsumer1.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+ .isEqualTo(3333);
+ assertThat(uidConsumer1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
+ .isWithin(PRECISION).of(3.18877);
+ assertThat(uidConsumer1.getPackageWithHighestDrain()).isEqualTo("bar");
+
+ UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
+ assertThat(uidConsumer2.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU))
+ .isEqualTo(7777);
+ assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU))
+ .isWithin(PRECISION).of(7.44072);
+ assertThat(uidConsumer2.getPackageWithHighestDrain()).isNull();
+ }
}
diff --git a/core/tests/mockingcoretests/src/android/view/DisplayTests.java b/core/tests/mockingcoretests/src/android/view/DisplayTests.java
index 678f21f..a036db2 100644
--- a/core/tests/mockingcoretests/src/android/view/DisplayTests.java
+++ b/core/tests/mockingcoretests/src/android/view/DisplayTests.java
@@ -73,6 +73,11 @@
private static Rect sAppBoundsPortrait = buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT);
private static Rect sAppBoundsLandscape = buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH);
+ // Bounds of the device.
+ private static Rect sDeviceBoundsPortrait = new Rect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
+ private static Rect sDeviceBoundsLandscape = new Rect(0, 0, LOGICAL_HEIGHT, LOGICAL_WIDTH);
+
+
private StaticMockitoSession mMockitoSession;
private DisplayManagerGlobal mDisplayManagerGlobal;
@@ -278,29 +283,57 @@
}
@Test
- public void testGetRealSize_resourcesPortraitSandboxed_matchesSandboxBounds() {
+ public void testGetRealSize_resourcesPortraitSandboxed_matchesAppSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsPortrait);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
- verifyRealSizeMatchesApp(display, sAppBoundsPortrait);
+ verifyRealSizeMatchesBounds(display, sAppBoundsPortrait);
}
@Test
- public void testGetRealSize_resourcesLandscapeSandboxed_matchesSandboxBounds() {
+ public void testGetRealSize_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is not rotated.
+ setDisplayInfoPortrait(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealSizeMatchesBounds(display, sDeviceBoundsPortrait);
+ }
+
+ @Test
+ public void testGetRealSize_resourcesLandscapeSandboxed_matchesAppSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsLandscape);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
- verifyRealSizeMatchesApp(display, sAppBoundsLandscape);
+ verifyRealSizeMatchesBounds(display, sAppBoundsLandscape);
+ }
+
+ @Test
+ public void testGetRealSize_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is rotated.
+ setDisplayInfoLandscape(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealSizeMatchesBounds(display, sDeviceBoundsLandscape);
}
@Test
@@ -396,29 +429,57 @@
}
@Test
- public void testGetRealMetrics_resourcesPortraitSandboxed_matchesSandboxBounds() {
+ public void testGetRealMetrics_resourcesPortraitSandboxed_matchesAppSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsPortrait);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
- verifyRealMetricsMatchesApp(display, sAppBoundsPortrait);
+ verifyRealMetricsMatchesBounds(display, sAppBoundsPortrait);
}
@Test
- public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesSandboxBounds() {
+ public void testGetRealMetrics_resourcesPortraitSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is not rotated.
+ setDisplayInfoPortrait(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsPortrait);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealMetricsMatchesBounds(display, sDeviceBoundsPortrait);
+ }
+
+ @Test
+ public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesAppSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
- setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
- sAppBoundsLandscape);
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
- verifyRealMetricsMatchesApp(display, sAppBoundsLandscape);
+ verifyRealMetricsMatchesBounds(display, sAppBoundsLandscape);
+ }
+
+ @Test
+ public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesDisplayAreaSandboxBounds() {
+ // GIVEN display is rotated.
+ setDisplayInfoLandscape(mDisplayInfo);
+ // GIVEN max bounds reflect DisplayArea size, which is the same size as the display.
+ setMaxBoundsSandboxed(mApplicationContext.getResources(), sDeviceBoundsLandscape);
+ // GIVEN app bounds do not stretch to include the full DisplayArea.
+ mApplicationContext.getResources().getConfiguration().windowConfiguration
+ .setAppBounds(buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH - 10));
+ final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
+ mApplicationContext.getResources());
+ // THEN real metrics matches max bounds for the DisplayArea.
+ verifyRealMetricsMatchesBounds(display, sDeviceBoundsLandscape);
}
// Given rotated display dimensions, calculate the letterboxed app bounds.
@@ -450,8 +511,8 @@
* Set max bounds to be sandboxed to the app bounds, indicating the app is in
* size compat mode or letterbox.
*/
- private static void setMaxBoundsSandboxedToMatchAppBounds(Resources resources, Rect appBounds) {
- resources.getConfiguration().windowConfiguration.setMaxBounds(appBounds);
+ private static void setMaxBoundsSandboxed(Resources resources, Rect bounds) {
+ resources.getConfiguration().windowConfiguration.setMaxBounds(bounds);
}
/**
@@ -492,17 +553,17 @@
assertThat(metrics.heightPixels).isEqualTo(LOGICAL_HEIGHT);
}
- private static void verifyRealSizeMatchesApp(Display display, Rect appBounds) {
+ private static void verifyRealSizeMatchesBounds(Display display, Rect bounds) {
Point size = new Point();
display.getRealSize(size);
- assertThat(size).isEqualTo(new Point(appBounds.width(), appBounds.height()));
+ assertThat(size).isEqualTo(new Point(bounds.width(), bounds.height()));
}
- private static void verifyRealMetricsMatchesApp(Display display, Rect appBounds) {
+ private static void verifyRealMetricsMatchesBounds(Display display, Rect bounds) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
- assertThat(metrics.widthPixels).isEqualTo(appBounds.width());
- assertThat(metrics.heightPixels).isEqualTo(appBounds.height());
+ assertThat(metrics.widthPixels).isEqualTo(bounds.width());
+ assertThat(metrics.heightPixels).isEqualTo(bounds.height());
}
private static FixedRotationAdjustments setOverrideFixedRotationAdjustments(
diff --git a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
index c01bb75..e41805d 100644
--- a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
+++ b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
@@ -22,7 +22,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -32,6 +31,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.concurrent.Executor;
@@ -42,51 +42,23 @@
@RunWith(AndroidJUnit4.class)
public class RangingManagerTest {
- private static final IUwbAdapter ADAPTER = mock(IUwbAdapter.class);
private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
private static final PersistableBundle PARAMS = new PersistableBundle();
private static final @RangingChangeReason int REASON = RangingChangeReason.UNKNOWN;
@Test
public void testOpenSession_OpenRangingInvoked() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
- verify(ADAPTER, times(1)).openRanging(eq(rangingManager), eq(PARAMS));
- }
-
- @Test
- public void testOpenSession_ErrorIfSameSessionHandleReturned() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
-
- rangingManager.openSession(PARAMS, EXECUTOR, callback);
-
- // Calling openSession will cause the same session handle to be returned. The onClosed
- // callback should be invoked
- RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- rangingManager.openSession(PARAMS, EXECUTOR, callback2);
- verify(callback, times(0)).onClosed(anyInt(), any());
- verify(callback2, times(1)).onClosed(anyInt(), any());
- }
-
- @Test
- public void testOnRangingOpened_ValidSessionHandle() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
-
- rangingManager.openSession(PARAMS, EXECUTOR, callback);
- rangingManager.onRangingOpened(handle);
- verify(callback, times(1)).onOpened(any());
+ verify(adapter, times(1)).openRanging(any(), eq(rangingManager), eq(PARAMS));
}
@Test
public void testOnRangingOpened_InvalidSessionHandle() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
rangingManager.onRangingOpened(new SessionHandle(2));
@@ -95,18 +67,20 @@
@Test
public void testOnRangingOpened_MultipleSessionsRegistered() throws RemoteException {
- SessionHandle sessionHandle1 = new SessionHandle(1);
- SessionHandle sessionHandle2 = new SessionHandle(2);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
- when(ADAPTER.openRanging(any(), any()))
- .thenReturn(sessionHandle1)
- .thenReturn(sessionHandle2);
-
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ RangingManager rangingManager = new RangingManager(adapter);
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
+
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
rangingManager.onRangingOpened(sessionHandle1);
verify(callback1, times(1)).onOpened(any());
@@ -119,12 +93,17 @@
@Test
public void testCorrectCallbackInvoked() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
+
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle handle = sessionHandleCaptor.getValue();
+
rangingManager.onRangingOpened(handle);
verify(callback, times(1)).onOpened(any());
@@ -156,20 +135,23 @@
@Test
public void testOnRangingClosed_MultipleSessionsRegistered() throws RemoteException {
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
// Verify that if multiple sessions are registered, only the session that is
// requested to close receives the associated callbacks
- SessionHandle sessionHandle1 = new SessionHandle(1);
- SessionHandle sessionHandle2 = new SessionHandle(2);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- when(ADAPTER.openRanging(any(), any()))
- .thenReturn(sessionHandle1)
- .thenReturn(sessionHandle2);
+ RangingManager rangingManager = new RangingManager(adapter);
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
- RangingManager rangingManager = new RangingManager(ADAPTER);
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
+
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
rangingManager.onRangingClosed(sessionHandle1, REASON, PARAMS);
verify(callback1, times(1)).onClosed(anyInt(), any());
@@ -182,19 +164,22 @@
@Test
public void testOnRangingReport_MultipleSessionsRegistered() throws RemoteException {
- SessionHandle sessionHandle1 = new SessionHandle(1);
- SessionHandle sessionHandle2 = new SessionHandle(2);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- when(ADAPTER.openRanging(any(), any()))
- .thenReturn(sessionHandle1)
- .thenReturn(sessionHandle2);
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ RangingManager rangingManager = new RangingManager(adapter);
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
+
rangingManager.onRangingStarted(sessionHandle1, PARAMS);
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
rangingManager.onRangingStarted(sessionHandle2, PARAMS);
rangingManager.onRangingResult(sessionHandle1, UwbTestUtils.getRangingReports(1));
@@ -232,17 +217,24 @@
private void runReason(@RangingChangeReason int reasonIn,
@RangingSession.Callback.Reason int reasonOut) throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingManager rangingManager = new RangingManager(adapter);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
+
+ ArgumentCaptor<SessionHandle> sessionHandleCaptor =
+ ArgumentCaptor.forClass(SessionHandle.class);
+
rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ verify(adapter, times(1)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ SessionHandle handle = sessionHandleCaptor.getValue();
rangingManager.onRangingOpenFailed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onOpenFailed(eq(reasonOut), eq(PARAMS));
// Open a new session
rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ verify(adapter, times(2)).openRanging(sessionHandleCaptor.capture(), any(), any());
+ handle = sessionHandleCaptor.getValue();
rangingManager.onRangingOpened(handle);
rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS);
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
index 8e7f7c56..75c6924 100644
--- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -16,34 +16,23 @@
package android.uwb;
-import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.SystemClock;
-import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.Executor;
public class UwbTestUtils {
private UwbTestUtils() {}
- public static boolean isUwbSupported(Context context) {
- PackageManager packageManager = context.getPackageManager();
- return packageManager.hasSystemFeature(PackageManager.FEATURE_UWB);
- }
-
public static AngleMeasurement getAngleMeasurement() {
- return new AngleMeasurement.Builder()
- .setRadians(getDoubleInRange(-Math.PI, Math.PI))
- .setErrorRadians(getDoubleInRange(0, Math.PI))
- .setConfidenceLevel(getDoubleInRange(0, 1))
- .build();
+ return new AngleMeasurement(
+ getDoubleInRange(-Math.PI, Math.PI),
+ getDoubleInRange(0, Math.PI),
+ getDoubleInRange(0, 1));
}
public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
- return new AngleOfArrivalMeasurement.Builder()
+ return new AngleOfArrivalMeasurement.Builder(getAngleMeasurement())
.setAltitude(getAngleMeasurement())
- .setAzimuth(getAngleMeasurement())
.build();
}
@@ -69,14 +58,6 @@
.build();
}
- public static List<RangingMeasurement> getRangingMeasurements(int num) {
- List<RangingMeasurement> result = new ArrayList<>();
- for (int i = 0; i < num; i++) {
- result.add(getRangingMeasurement());
- }
- return result;
- }
-
public static RangingReport getRangingReports(int numMeasurements) {
RangingReport.Builder builder = new RangingReport.Builder();
for (int i = 0; i < numMeasurements; i++) {
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 77a38a9..b3a180d 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -154,6 +154,7 @@
<assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="media" />
<assign-permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" uid="media" />
+ <assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="media" />
<assign-permission name="android.permission.INTERNET" uid="media" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c49fe85..a7b6636 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -488,6 +488,8 @@
<permission name="android.permission.MANAGE_UI_TRANSLATION" />
<!-- Permission required for CTS test - ClipboardManagerTest -->
<permission name="android.permission.SET_CLIP_SOURCE" />
+ <!-- Permission required for CTS test - FontManagerTest -->
+ <permission name="android.permission.UPDATE_FONTS" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index c807882..2a6bbf3 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -25,6 +25,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.annotation.UiThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
@@ -169,6 +170,21 @@
Collections.emptyMap();
/**
+ * Returns the shared memory that used for creating Typefaces.
+ *
+ * @return A SharedMemory used for creating Typeface. Maybe null if the lazy initialization is
+ * disabled or inside SystemServer or Zygote.
+ * @hide
+ */
+ @TestApi
+ public static @Nullable SharedMemory getSystemFontMapSharedMemory() {
+ if (ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ Objects.requireNonNull(sSystemFontMapSharedMemory);
+ }
+ return sSystemFontMapSharedMemory;
+ }
+
+ /**
* @hide
*/
@UnsupportedAppUsage
@@ -1196,8 +1212,13 @@
}
}
- /** @hide */
- public static SharedMemory serializeFontMap(Map<String, Typeface> fontMap)
+ /**
+ * Create a serialized system font mappings.
+ *
+ * @hide
+ */
+ @TestApi
+ public static @NonNull SharedMemory serializeFontMap(@NonNull Map<String, Typeface> fontMap)
throws IOException, ErrnoException {
long[] nativePtrs = new long[fontMap.size()];
// The name table will not be large, so let's create a byte array in memory.
@@ -1229,9 +1250,14 @@
}
// buffer's byte order should be BIG_ENDIAN.
- /** @hide */
- @VisibleForTesting
- public static Map<String, Typeface> deserializeFontMap(ByteBuffer buffer) throws IOException {
+ /**
+ * Deserialize the font mapping from the serialized byte buffer.
+ *
+ * @hide
+ */
+ @TestApi
+ public static @NonNull Map<String, Typeface> deserializeFontMap(@NonNull ByteBuffer buffer)
+ throws IOException {
Map<String, Typeface> fontMap = new ArrayMap<>();
int typefacesBytesCount = buffer.getInt();
long[] nativePtrs = nativeReadTypefaces(buffer.slice());
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index 2549277..657a32c 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -61,53 +61,6 @@
+ " return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n"
+ "}\n"
+ "\n"
- + "float softRing(vec2 uv, vec2 xy, float radius, float blur) {\n"
- + " float thickness = 0.4;\n"
- + " float circle_outer = softCircle(uv, xy, radius + thickness * 0.5, blur);\n"
- + " float circle_inner = softCircle(uv, xy, radius - thickness * 0.5, blur);\n"
- + " return circle_outer - circle_inner;\n"
- + "}\n"
- + "\n"
- + "struct Viewport {\n"
- + " float aspect;\n"
- + " vec2 uv;\n"
- + " vec2 resolution_pixels;\n"
- + "};\n"
- + "\n"
- + "Viewport getViewport(vec2 frag_coord, vec2 resolution_pixels) {\n"
- + " Viewport v;\n"
- + " v.aspect = resolution_pixels.y / resolution_pixels.x;\n"
- + " v.uv = frag_coord / resolution_pixels;\n"
- + " v.uv.y = (1.0 - v.uv.y) * v.aspect;\n"
- + " v.resolution_pixels = resolution_pixels;\n"
- + " return v;\n"
- + "}\n"
- + "\n"
- + "vec2 getTouch(vec2 touch_position_pixels, Viewport viewport) {\n"
- + " vec2 touch = touch_position_pixels / viewport.resolution_pixels;\n"
- + " touch.y *= viewport.aspect;\n"
- + " return touch;\n"
- + "}\n"
- + "\n"
- + "struct Wave {\n"
- + " float ring;\n"
- + " float circle;\n"
- + "};\n"
- + "\n"
- + "Wave getWave(Viewport viewport, vec2 touch, float progress) {\n"
- + " float fade = pow((clamp(progress, 0.8, 1.0)), 8.);\n"
- + " Wave w;\n"
- + " w.ring = max(softRing(viewport.uv, touch, progress, 0.45) - fade, 0.);\n"
- + " w.circle = softCircle(viewport.uv, touch, 2.0 * progress, 0.2) - progress;\n"
- + " return w;\n"
- + "}\n"
- + "\n"
- + "vec4 getRipple(vec4 color, float loudness, float sparkle, Wave wave) {\n"
- + " float alpha = wave.ring * sparkle * loudness\n"
- + " + wave.circle * color.a;\n"
- + " return vec4(color.rgb, saturate(alpha));\n"
- + "}\n"
- + "\n"
+ "float getRingMask(vec2 frag, vec2 center, float r, float progress) {\n"
+ " float dist = distance(frag, center);\n"
+ " float expansion = r * .6;\n"
@@ -126,19 +79,15 @@
+ " float fadeIn = subProgress(0., 0.175, in_progress);\n"
+ " float fadeOutNoise = subProgress(0.375, 1., in_progress);\n"
+ " float fadeOutRipple = subProgress(0.375, 0.75, in_progress);\n"
- + " Viewport vp = getViewport(p, in_resolution);\n"
- + " vec2 touch = getTouch(in_origin, vp);\n"
- + " Wave w = getWave(vp, touch, in_progress * 0.25);\n"
+ " float ring = getRingMask(p, in_origin, in_maxRadius, fadeIn);\n"
+ " float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
+ " float sparkle = sparkles(p, in_progress * 0.25 + in_secondsOffset)\n"
+ " * ring * alpha;\n"
- + " vec4 r = getRipple(in_color, 1., sparkle, w);\n"
+ " float fade = min(fadeIn, 1.-fadeOutRipple);\n"
- + " vec4 circle = vec4(in_color.rgb, softCircle(p, in_origin, in_maxRadius "
- + " * fadeIn, 0.2) * fade * in_color.a);\n"
+ + " vec4 circle = in_color * (softCircle(p, in_origin, in_maxRadius "
+ + " * fadeIn, 0.2) * fade);\n"
+ " float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n"
- + " return mix(circle, vec4(1.), sparkle * mask);\n"
+ + " return mix(circle, vec4(sparkle), sparkle) * mask;\n"
+ "}";
private static final String SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN;
diff --git a/graphics/java/android/graphics/fonts/FontFileUtil.java b/graphics/java/android/graphics/fonts/FontFileUtil.java
index af49619..917eef2 100644
--- a/graphics/java/android/graphics/fonts/FontFileUtil.java
+++ b/graphics/java/android/graphics/fonts/FontFileUtil.java
@@ -183,6 +183,23 @@
return nIsPostScriptType1Font(buffer, index);
}
+ /**
+ * Analyze the file content and returns 1 if the font file is an OpenType collection file, 0 if
+ * the font file is a OpenType font file, -1 otherwise.
+ */
+ public static int isCollectionFont(@NonNull ByteBuffer buffer) {
+ ByteBuffer copied = buffer.slice();
+ copied.order(ByteOrder.BIG_ENDIAN);
+ int magicNumber = copied.getInt(0);
+ if (magicNumber == TTC_TAG) {
+ return 1;
+ } else if (magicNumber == SFNT_VERSION_1 || magicNumber == SFNT_VERSION_OTTO) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
@FastNative
private static native long nGetFontRevision(@NonNull ByteBuffer buffer,
@IntRange(from = 0) int index);
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 5501569..35b1c16 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -121,4 +121,22 @@
return SYSTEM_ERROR;
}
}
+
+ /**
+ * Queries user state from Keystore 2.0.
+ *
+ * @param userId - Android user id of the user.
+ * @return UserState enum variant as integer if successful or an error
+ */
+ public static int getState(int userId) {
+ try {
+ return getService().getState(userId);
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "getState failed", e);
+ return e.errorCode;
+ } catch (Exception e) {
+ Log.e(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ }
+ }
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 93658e6..937f01c 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -43,6 +43,7 @@
import android.security.keystore.KeyProperties;
import android.security.keystore.KeystoreResponse;
import android.security.keystore.UserNotAuthenticatedException;
+import android.security.maintenance.UserState;
import android.system.keystore2.Domain;
import android.util.Log;
@@ -196,6 +197,19 @@
public State state(int userId) {
final int ret;
try {
+ if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
+ int userState = AndroidKeyStoreMaintenance.getState(userId);
+ switch (userState) {
+ case UserState.UNINITIALIZED:
+ return KeyStore.State.UNINITIALIZED;
+ case UserState.LSKF_UNLOCKED:
+ return KeyStore.State.UNLOCKED;
+ case UserState.LSKF_LOCKED:
+ return KeyStore.State.LOCKED;
+ default:
+ throw new AssertionError(KeyStore.VALUE_CORRUPTED);
+ }
+ }
ret = mBinder.getState(userId);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index c0bc73d..d2b3cf6 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -18,4 +18,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wm.shell">
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
</manifest>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index 2419865..c2f591b 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -51,4 +51,10 @@
<!-- maximum animation duration for the icon when entering the starting window -->
<integer name="max_starting_window_intro_icon_anim_duration">1000</integer>
+
+ <!-- Animation duration when exit starting window: icon going away -->
+ <integer name="starting_window_icon_exit_anim_duration">166</integer>
+
+ <!-- Animation duration when exit starting window: reveal app -->
+ <integer name="starting_window_app_reveal_anim_duration">333</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 75bed37..3ced8d3 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -188,4 +188,13 @@
<!-- The height of the brand image on staring surface. -->
<dimen name="starting_surface_brand_image_height">80dp</dimen>
+
+ <!-- The length of the shift of main window when exit starting window. -->
+ <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen>
+
+ <!-- The distance of the shift icon when normal exit starting window. -->
+ <dimen name="starting_surface_normal_exit_icon_distance">120dp</dimen>
+
+ <!-- The distance of the shift icon when early exit starting window. -->
+ <dimen name="starting_surface_early_exit_icon_distance">32dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index cb04bd7..fcb53cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -31,6 +31,7 @@
import android.app.TaskInfo;
import android.content.Context;
import android.content.LocusId;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.util.ArrayMap;
@@ -307,9 +308,10 @@
}
@Override
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
if (mStartingSurface != null) {
- mStartingSurface.removeStartingWindow(taskId);
+ mStartingSurface.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 46884fe..7d65a08 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -83,6 +83,7 @@
private boolean mIsInitialized;
private Listener mListener;
private Executor mListenerExecutor;
+ private Rect mObscuredTouchRect;
private final Rect mTmpRect = new Rect();
private final Rect mTmpRootRect = new Rect();
@@ -161,6 +162,15 @@
}
/**
+ * Indicates a region of the view that is not touchable.
+ *
+ * @param obscuredRect the obscured region of the view.
+ */
+ public void setObscuredTouchRect(Rect obscuredRect) {
+ mObscuredTouchRect = obscuredRect;
+ }
+
+ /**
* Call when view position or size has changed. Do not call when animating.
*/
public void onLocationChanged() {
@@ -384,6 +394,10 @@
mTmpRect.set(mTmpLocation[0], mTmpLocation[1],
mTmpLocation[0] + getWidth(), mTmpLocation[1] + getHeight());
inoutInfo.touchableRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+
+ if (mObscuredTouchRect != null) {
+ inoutInfo.touchableRegion.union(mObscuredTouchRect);
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 64a44ca..16ede73 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -41,7 +41,6 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.graphics.Region;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -1046,6 +1045,7 @@
}
};
+ // TODO: Create ManageMenuView and move setup / animations there
private void setUpManageMenu() {
if (mManageMenu != null) {
removeView(mManageMenu);
@@ -2146,50 +2146,6 @@
}
/**
- * This method is called by {@link android.app.ActivityView} because the BubbleStackView has a
- * higher Z-index than the ActivityView (so that dragged-out bubbles are visible over the AV).
- * ActivityView is asking BubbleStackView to subtract the stack's bounds from the provided
- * touchable region, so that the ActivityView doesn't consume events meant for the stack. Due to
- * the special nature of ActivityView, it does not respect the standard
- * {@link #dispatchTouchEvent} and {@link #onInterceptTouchEvent} methods typically used for
- * this purpose.
- *
- * BubbleStackView is MATCH_PARENT, so that bubbles can be positioned via their translation
- * properties for performance reasons. This means that the default implementation of this method
- * subtracts the entirety of the screen from the ActivityView's touchable region, resulting in
- * it not receiving any touch events. This was previously addressed by returning false in the
- * stack's {@link View#canReceivePointerEvents()} method, but this precluded the use of any
- * touch handlers in the stack or its child views.
- *
- * To support touch handlers, we're overriding this method to leave the ActivityView's touchable
- * region alone. The only touchable part of the stack that can ever overlap the AV is a
- * dragged-out bubble that is animating back into the row of bubbles. It's not worth continually
- * updating the touchable region to allow users to grab a bubble while it completes its ~50ms
- * animation back to the bubble row.
- *
- * NOTE: Any future additions to the stack that obscure the ActivityView region will need their
- * bounds subtracted here in order to receive touch events.
- */
- @Override
- public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
- // If the notification shade is expanded, or the manage menu is open, or we are showing
- // manage bubbles user education, we shouldn't let the ActivityView steal any touch events
- // from any location.
- if (!mIsExpanded
- || mShowingManage
- || (mManageEduView != null
- && mManageEduView.getVisibility() == VISIBLE)) {
- touchableRegion.setEmpty();
- }
- }
-
- /**
- * If you're here because you're not receiving touch events on a view that is a descendant of
- * BubbleStackView, and you think BSV is intercepting them - it's not! You need to subtract the
- * bounds of the view in question in {@link #subtractObscuredTouchableRegion}. The ActivityView
- * consumes all touch events within its bounds, even for views like the BubbleStackView that are
- * above it. It ignores typical view touch handling methods like this one and
- * dispatchTouchEvent.
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -2539,6 +2495,11 @@
}
mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
+ if (mExpandedBubble.getExpandedView().getTaskView() != null) {
+ mExpandedBubble.getExpandedView().getTaskView().setObscuredTouchRect(mShowingManage
+ ? new Rect(0, 0, getWidth(), getHeight())
+ : null);
+ }
final boolean isLtr =
getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
index 7ce9014..57a9dd2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerImeController.java
@@ -143,14 +143,14 @@
@ImeAnimationFlags
public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) {
- mHiddenTop = hiddenTop;
- mShownTop = shownTop;
- mTargetShown = imeShouldShow;
if (!isDividerVisible()) {
return 0;
}
- final boolean splitIsVisible = !getView().isHidden();
+ mHiddenTop = hiddenTop;
+ mShownTop = shownTop;
+ mTargetShown = imeShouldShow;
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
+ final boolean splitIsVisible = !getView().isHidden();
final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
&& !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
&& !mSplits.mSplitScreenController.isMinimized();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
new file mode 100644
index 0000000..5bc2afd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -0,0 +1,328 @@
+/*
+ * 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.wm.shell.startingsurface;
+
+import static android.view.View.GONE;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.BlendMode;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.view.animation.Transformation;
+import android.view.animation.TranslateYAnimation;
+import android.window.SplashScreenView;
+
+import com.android.wm.shell.common.TransactionPool;
+
+/**
+ * Default animation for exiting the splash screen window.
+ * @hide
+ */
+public class SplashScreenExitAnimation implements Animator.AnimatorListener {
+ private static final boolean DEBUG_EXIT_ANIMATION = false;
+ private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
+ private static final String TAG = StartingSurfaceDrawer.TAG;
+
+ private static final Interpolator ICON_EXIT_INTERPOLATOR = new PathInterpolator(1f, 0f, 1f, 1f);
+ private static final Interpolator APP_EXIT_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);
+
+ private static final int EXTRA_REVEAL_DELAY = 133;
+ private final Matrix mTmpTransform = new Matrix();
+ private final float[] mTmpFloat9 = new float[9];
+ private SurfaceControl mFirstWindowSurface;
+ private final Rect mFirstWindowFrame = new Rect();
+ private final SplashScreenView mSplashScreenView;
+ private final int mMainWindowShiftLength;
+ private final int mIconShiftLength;
+ private final int mAppDuration;
+ private final int mIconDuration;
+ private final TransactionPool mTransactionPool;
+
+ private ValueAnimator mMainAnimator;
+ private Animation mShiftUpAnimation;
+ private AnimationSet mIconAnimationSet;
+ private Runnable mFinishCallback;
+
+ SplashScreenExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame,
+ int appDuration, int iconDuration, int mainWindowShiftLength, int iconShiftLength,
+ TransactionPool pool, Runnable handleFinish) {
+ mSplashScreenView = view;
+ mFirstWindowSurface = leash;
+ if (frame != null) {
+ mFirstWindowFrame.set(frame);
+ }
+ mAppDuration = appDuration;
+ mIconDuration = iconDuration;
+ mMainWindowShiftLength = mainWindowShiftLength;
+ mIconShiftLength = iconShiftLength;
+ mFinishCallback = handleFinish;
+ mTransactionPool = pool;
+ }
+
+ void prepareAnimations() {
+ prepareRevealAnimation();
+ prepareShiftAnimation();
+ }
+
+ void startAnimations() {
+ if (mIconAnimationSet != null) {
+ mIconAnimationSet.start();
+ }
+ if (mMainAnimator != null) {
+ mMainAnimator.start();
+ }
+ if (mShiftUpAnimation != null) {
+ mShiftUpAnimation.start();
+ }
+ }
+
+ // reveal splash screen, shift up main window
+ private void prepareRevealAnimation() {
+ // splash screen
+ mMainAnimator = ValueAnimator.ofFloat(0f, 1f);
+ mMainAnimator.setDuration(mAppDuration);
+ mMainAnimator.setInterpolator(APP_EXIT_INTERPOLATOR);
+ mMainAnimator.addListener(this);
+
+ final int startDelay = mIconDuration + EXTRA_REVEAL_DELAY;
+ final float transparentRatio = 0.95f;
+ final int globalHeight = mSplashScreenView.getHeight();
+ final int verticalCircleCenter = 0;
+ final int finalVerticalLength = globalHeight - verticalCircleCenter;
+ final int halfWidth = mSplashScreenView.getWidth() / 2;
+ final int endRadius = (int) (0.5 + (1f / transparentRatio * (int)
+ Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth)));
+ final RadialVanishAnimation radialVanishAnimation = new RadialVanishAnimation(
+ mSplashScreenView, mMainAnimator);
+ radialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter);
+ radialVanishAnimation.setRadius(0/* initRadius */, endRadius);
+ final int[] colors = {Color.TRANSPARENT, Color.TRANSPARENT, Color.WHITE};
+ final float[] stops = {0f, transparentRatio, 1f};
+ radialVanishAnimation.setRadialPaintParam(colors, stops);
+ radialVanishAnimation.setReady();
+ mMainAnimator.setStartDelay(startDelay);
+
+ if (mFirstWindowSurface != null) {
+ // shift up main window
+ View occludeHoleView = new View(mSplashScreenView.getContext());
+ if (DEBUG_EXIT_ANIMATION_BLEND) {
+ occludeHoleView.setBackgroundColor(Color.BLUE);
+ } else {
+ occludeHoleView.setBackgroundColor(mSplashScreenView.getInitBackgroundColor());
+ }
+ final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
+ WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength);
+ mSplashScreenView.addView(occludeHoleView, params);
+
+ mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength);
+ mShiftUpAnimation.setDuration(mAppDuration);
+ mShiftUpAnimation.setInterpolator(APP_EXIT_INTERPOLATOR);
+ mShiftUpAnimation.setStartOffset(startDelay);
+
+ occludeHoleView.setAnimation(mShiftUpAnimation);
+ }
+ }
+
+ // shift down icon and branding view
+ private void prepareShiftAnimation() {
+ final View iconView = mSplashScreenView.getIconView();
+ if (iconView == null) {
+ return;
+ }
+ if (mIconShiftLength > 0) {
+ mIconAnimationSet = new AnimationSet(true /* shareInterpolator */);
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "first exit animation, shift length: " + mIconShiftLength);
+ }
+ mIconAnimationSet.addAnimation(new TranslateYAnimation(0, mIconShiftLength));
+ mIconAnimationSet.addAnimation(new AlphaAnimation(1, 0));
+ mIconAnimationSet.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "first exit animation finished");
+ }
+ iconView.post(() -> iconView.setVisibility(GONE));
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ // ignore
+ }
+ });
+ mIconAnimationSet.setDuration(mIconDuration);
+ mIconAnimationSet.setInterpolator(ICON_EXIT_INTERPOLATOR);
+ iconView.setAnimation(mIconAnimationSet);
+ final View brandingView = mSplashScreenView.getBrandingView();
+ if (brandingView != null) {
+ brandingView.setAnimation(mIconAnimationSet);
+ }
+ }
+ }
+
+ private static class RadialVanishAnimation extends View {
+ private SplashScreenView mView;
+ private int mInitRadius;
+ private int mFinishRadius;
+ private boolean mReady;
+
+ private final Point mCircleCenter = new Point();
+ private final Matrix mVanishMatrix = new Matrix();
+ private final Paint mVanishPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ RadialVanishAnimation(SplashScreenView target, ValueAnimator animator) {
+ super(target.getContext());
+ mView = target;
+ animator.addUpdateListener((animation) -> {
+ if (mVanishPaint.getShader() == null) {
+ return;
+ }
+ final float value = (float) animation.getAnimatedValue();
+ final float scale = (mFinishRadius - mInitRadius) * value + mInitRadius;
+ mVanishMatrix.setScale(scale, scale);
+ mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y);
+ mVanishPaint.getShader().setLocalMatrix(mVanishMatrix);
+ mView.postInvalidate();
+ });
+ mView.addView(this);
+ }
+
+ void setRadius(int initRadius, int finishRadius) {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "RadialVanishAnimation setRadius init: " + initRadius
+ + " final " + finishRadius);
+ }
+ mInitRadius = initRadius;
+ mFinishRadius = finishRadius;
+ }
+
+ void setCircleCenter(int x, int y) {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "RadialVanishAnimation setCircleCenter x: " + x + " y " + y);
+ }
+ mCircleCenter.set(x, y);
+ }
+
+ void setRadialPaintParam(int[] colors, float[] stops) {
+ // setup gradient shader
+ final RadialGradient rShader =
+ new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP);
+ mVanishPaint.setShader(rShader);
+ if (!DEBUG_EXIT_ANIMATION_BLEND) {
+ mVanishPaint.setBlendMode(BlendMode.MODULATE);
+ }
+ }
+
+ void setReady() {
+ mReady = true;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mReady) {
+ canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint);
+ }
+ }
+ }
+
+ private final class ShiftUpAnimation extends TranslateYAnimation {
+ ShiftUpAnimation(float fromYDelta, float toYDelta) {
+ super(fromYDelta, toYDelta);
+ }
+
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ super.applyTransformation(interpolatedTime, t);
+
+ if (mFirstWindowSurface == null) {
+ return;
+ }
+ mTmpTransform.set(t.getMatrix());
+ final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+ mTmpTransform.postTranslate(mFirstWindowFrame.left,
+ mFirstWindowFrame.top + mMainWindowShiftLength);
+ tx.setMatrix(mFirstWindowSurface, mTmpTransform, mTmpFloat9);
+ // TODO set the vsyncId to ensure the transaction doesn't get applied too early.
+ // Additionally, do you want to have this synchronized with your view animations?
+ // If so, you'll need to use SyncRtSurfaceTransactionApplier
+ tx.apply();
+ mTransactionPool.release(tx);
+ }
+ }
+
+ private void reset() {
+ if (DEBUG_EXIT_ANIMATION) {
+ Slog.v(TAG, "vanish animation finished");
+ }
+ mSplashScreenView.post(() -> {
+ mSplashScreenView.setVisibility(GONE);
+ if (mFinishCallback != null) {
+ mFinishCallback.run();
+ mFinishCallback = null;
+ }
+ });
+ if (mFirstWindowSurface != null) {
+ final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+ tx.setWindowCrop(mFirstWindowSurface, null);
+ tx.apply();
+ mFirstWindowSurface.release();
+ mFirstWindowSurface = null;
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // ignore
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ reset();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ reset();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ // ignore
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 2973b50..3f9c271 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -31,12 +31,14 @@
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.Slog;
+import android.view.SurfaceControl;
import android.window.SplashScreenView;
import com.android.internal.R;
import com.android.internal.graphics.palette.Palette;
import com.android.internal.graphics.palette.Quantizer;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
+import com.android.wm.shell.common.TransactionPool;
import java.util.List;
@@ -56,15 +58,25 @@
// also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
private final Context mContext;
- private final int mMaxIconAnimationDuration;
+ private final int mMaxAnimatableIconDuration;
private int mIconSize;
private int mBrandingImageWidth;
private int mBrandingImageHeight;
+ private final int mAppRevealDuration;
+ private final int mIconExitDuration;
+ private int mMainWindowShiftLength;
+ private int mIconNormalExitDistance;
+ private int mIconEarlyExitDistance;
+ private final TransactionPool mTransactionPool;
- SplashscreenContentDrawer(Context context, int maxIconAnimationDuration) {
+ SplashscreenContentDrawer(Context context, int maxAnimatableIconDuration,
+ int iconExitAnimDuration, int appRevealAnimDuration, TransactionPool pool) {
mContext = context;
- mMaxIconAnimationDuration = maxIconAnimationDuration;
+ mMaxAnimatableIconDuration = maxAnimatableIconDuration;
+ mAppRevealDuration = appRevealAnimDuration;
+ mIconExitDuration = iconExitAnimDuration;
+ mTransactionPool = pool;
}
private void updateDensity() {
@@ -74,6 +86,12 @@
com.android.wm.shell.R.dimen.starting_surface_brand_image_width);
mBrandingImageHeight = mContext.getResources().getDimensionPixelSize(
com.android.wm.shell.R.dimen.starting_surface_brand_image_height);
+ mMainWindowShiftLength = mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.starting_surface_exit_animation_window_shift_length);
+ mIconNormalExitDistance = mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.starting_surface_normal_exit_icon_distance);
+ mIconEarlyExitDistance = mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.starting_surface_early_exit_icon_distance);
}
private int getSystemBGColor() {
@@ -119,7 +137,7 @@
if (attrs.mReplaceIcon != null) {
iconDrawable = attrs.mReplaceIcon;
animationDuration = Math.max(0,
- Math.min(attrs.mAnimationDuration, mMaxIconAnimationDuration));
+ Math.min(attrs.mAnimationDuration, mMaxAnimatableIconDuration));
} else {
iconDrawable = iconRes != 0 ? context.getDrawable(iconRes)
: context.getPackageManager().getDefaultActivityIcon();
@@ -439,8 +457,8 @@
}
/**
- * For ColorDrawable only.
- * There will be only one color so don't spend too much resource for it.
+ * For ColorDrawable only. There will be only one color so don't spend too much resource for
+ * it.
*/
private static class SingleColorTester implements ColorTester {
private final ColorDrawable mColorDrawable;
@@ -472,9 +490,8 @@
}
/**
- * For any other Drawable except ColorDrawable.
- * This will use the Palette API to check the color information and use a quantizer to
- * filter out transparent colors when needed.
+ * For any other Drawable except ColorDrawable. This will use the Palette API to check the
+ * color information and use a quantizer to filter out transparent colors when needed.
*/
private static class ComplexDrawableTester implements ColorTester {
private static final int MAX_BITMAP_SIZE = 40;
@@ -593,4 +610,17 @@
}
}
}
+
+ /**
+ * Create and play the default exit animation for splash screen view.
+ */
+ void applyExitAnimation(SplashScreenView view, SurfaceControl leash,
+ Rect frame, boolean isEarlyExit, Runnable finishCallback) {
+ final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(view, leash,
+ frame, mAppRevealDuration, mIconExitDuration, mMainWindowShiftLength,
+ isEarlyExit ? mIconEarlyExitDistance : mIconNormalExitDistance, mTransactionPool,
+ finishCallback);
+ animation.prepareAnimations();
+ animation.startAnimations();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index a594a9f..f258286 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -16,7 +16,9 @@
package com.android.wm.shell.startingsurface;
+import android.graphics.Rect;
import android.os.IBinder;
+import android.view.SurfaceControl;
import android.window.StartingWindowInfo;
import java.util.function.BiConsumer;
@@ -31,7 +33,8 @@
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- void removeStartingWindow(int taskId);
+ void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation);
/**
* Called when the Task wants to copy the splash screen.
* @param taskId
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 2d1d65b..14fbaac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -29,14 +29,18 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
+import android.os.SystemClock;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.Choreographer;
import android.view.Display;
+import android.view.SurfaceControl;
import android.view.View;
-import android.view.Window;
import android.view.WindowManager;
import android.window.SplashScreenView;
import android.window.SplashScreenView.SplashScreenViewParcelable;
@@ -46,6 +50,7 @@
import com.android.internal.R;
import com.android.internal.policy.PhoneWindow;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TransactionPool;
import java.util.function.Consumer;
@@ -62,23 +67,23 @@
private final DisplayManager mDisplayManager;
private final ShellExecutor mSplashScreenExecutor;
private final SplashscreenContentDrawer mSplashscreenContentDrawer;
- protected Choreographer mChoreographer;
// TODO(b/131727939) remove this when clearing ActivityRecord
private static final int REMOVE_WHEN_TIMEOUT = 2000;
- public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor) {
+ public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
+ TransactionPool pool) {
mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mSplashScreenExecutor = splashScreenExecutor;
- final int maxIconAnimDuration = context.getResources().getInteger(
+ final int maxAnimatableIconDuration = context.getResources().getInteger(
com.android.wm.shell.R.integer.max_starting_window_intro_icon_anim_duration);
- mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, maxIconAnimDuration);
- mSplashScreenExecutor.execute(this::initChoreographer);
- }
-
- protected void initChoreographer() {
- mChoreographer = Choreographer.getInstance();
+ final int iconExitAnimDuration = context.getResources().getInteger(
+ com.android.wm.shell.R.integer.starting_window_icon_exit_anim_duration);
+ final int appRevealAnimDuration = context.getResources().getInteger(
+ com.android.wm.shell.R.integer.starting_window_app_reveal_anim_duration);
+ mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext,
+ maxAnimatableIconDuration, iconExitAnimDuration, appRevealAnimDuration, pool);
}
private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
@@ -195,6 +200,7 @@
}
final PhoneWindow win = new PhoneWindow(context);
+ win.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
win.setIsStartingWindow(true);
CharSequence label = context.getResources().getText(labelRes, null);
@@ -211,7 +217,7 @@
// the keyguard is being hidden. This is okay because starting windows never show
// secret information.
// TODO(b/113840485): Occluded may not only happen on default display
- if (displayId == DEFAULT_DISPLAY) {
+ if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) {
windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
}
@@ -247,6 +253,7 @@
// Setting as trusted overlay to let touches pass through. This is safe because this
// window is controlled by the system.
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+ params.format = PixelFormat.RGBA_8888;
final Resources res = context.getResources();
final boolean supportsScreen = res != null && (res.getCompatibilityInfo() != null
@@ -257,98 +264,25 @@
params.setTitle("Splash Screen " + activityInfo.packageName);
- // TODO(b/173975965) If the target activity doesn't request FLAG_HARDWARE_ACCELERATED, we
- // cannot replace the content view after first view was drawn, sounds like an issue.
- new AddSplashScreenViewRunnable(taskInfo.taskId, win, context, appToken, params, iconRes,
- splashscreenContentResId[0], enableHardAccelerated).run();
- }
-
- private class AddSplashScreenViewRunnable implements Runnable {
- private final int mTaskId;
- private final Window mWin;
- private final IBinder mAppToken;
- private final WindowManager.LayoutParams mLayoutParams;
- private final Context mContext;
- private final int mIconRes;
- private final int mSplashscreenContentResId;
- private final boolean mReplaceSplashScreenView;
- private int mSequence;
-
- AddSplashScreenViewRunnable(int taskId, Window window, Context context,
- IBinder appToken, WindowManager.LayoutParams params, int iconRes,
- int splashscreenContentResId, boolean replaceSplashScreenView) {
- mTaskId = taskId;
- mWin = window;
- mAppToken = appToken;
- mContext = context;
- mLayoutParams = params;
- mIconRes = iconRes;
- mSplashscreenContentResId = splashscreenContentResId;
- mReplaceSplashScreenView = replaceSplashScreenView;
- }
-
- private void createInitialView() {
- View tempView = new View(mContext);
- mWin.setContentView(tempView);
- mSequence++;
- final View view = mWin.getDecorView();
+ // TODO(b/173975965) tracking performance
+ final int taskId = taskInfo.taskId;
+ SplashScreenView sView = null;
+ try {
+ sView = mSplashscreenContentDrawer.makeSplashScreenContentView(context, iconRes,
+ splashscreenContentResId[0]);
+ final View view = win.getDecorView();
final WindowManager wm = mContext.getSystemService(WindowManager.class);
- if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) {
- mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, this, null);
+ if (postAddWindow(taskId, appToken, view, wm, params)) {
+ win.setContentView(sView);
+ sView.cacheRootWindow(win);
}
- }
-
- private SplashScreenView replaceRealView() {
- final SplashScreenView sView =
- mSplashscreenContentDrawer.makeSplashScreenContentView(mContext,
- mIconRes, mSplashscreenContentResId);
- mWin.setContentView(sView);
- sView.cacheRootWindow(mWin);
- return sView;
- }
-
- private SplashScreenView initiateOnce() {
- final SplashScreenView sView =
- mSplashscreenContentDrawer.makeSplashScreenContentView(mContext, mIconRes,
- mSplashscreenContentResId);
- final View view = mWin.getDecorView();
- final WindowManager wm = mContext.getSystemService(WindowManager.class);
- if (postAddWindow(mTaskId, mAppToken, view, wm, mLayoutParams)) {
- mWin.setContentView(sView);
- sView.cacheRootWindow(mWin);
- }
- return sView;
- }
-
- @Override
- public void run() {
- SplashScreenView view = null;
- boolean setRecord = false;
- try {
- if (mReplaceSplashScreenView) {
- // Tricky way to make animation start faster... create the real content after
- // first window drawn. The first empty window won't been see because wm will
- // still need to wait for transition ready.
- if (mSequence == 0) {
- createInitialView();
- } else if (mSequence == 1) {
- setRecord = true;
- view = replaceRealView();
- }
- } else {
- setRecord = true;
- view = initiateOnce();
- }
- } catch (RuntimeException e) {
- // don't crash if something else bad happens, for example a
- // failure loading resources because we are loading from an app
- // on external storage that has been unmounted.
- Slog.w(TAG, " failed creating starting window", e);
- } finally {
- if (setRecord) {
- setSplashScreenRecord(mTaskId, view);
- }
- }
+ } catch (RuntimeException e) {
+ // don't crash if something else bad happens, for example a
+ // failure loading resources because we are loading from an app
+ // on external storage that has been unmounted.
+ Slog.w(TAG, " failed creating starting window", e);
+ } finally {
+ setSplashScreenRecord(taskId, sView);
}
}
@@ -359,8 +293,10 @@
TaskSnapshot snapshot) {
final int taskId = startingWindowInfo.taskInfo.taskId;
final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
- snapshot, mSplashScreenExecutor, () -> removeWindowSynced(taskId));
- mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ snapshot, mSplashScreenExecutor,
+ () -> removeWindowNoAnimate(taskId));
+ mSplashScreenExecutor.executeDelayed(() -> removeWindowNoAnimate(taskId),
+ REMOVE_WHEN_TIMEOUT);
final StartingWindowRecord tView =
new StartingWindowRecord(null/* decorView */, surface);
mStartingWindowRecords.put(taskId, tView);
@@ -369,11 +305,12 @@
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
}
- removeWindowSynced(taskId);
+ removeWindowSynced(taskId, leash, frame, playRevealAnimation);
}
/**
@@ -383,13 +320,6 @@
public void copySplashScreenView(int taskId) {
final StartingWindowRecord preView = mStartingWindowRecords.get(taskId);
SplashScreenViewParcelable parcelable;
- if (preView != null) {
- if (preView.isWaitForContent()) {
- mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
- () -> copySplashScreenView(taskId), null);
- return;
- }
- }
if (preView != null && preView.mContentView != null
&& preView.mContentView.isCopyable()) {
parcelable = new SplashScreenViewParcelable(preView.mContentView);
@@ -413,12 +343,6 @@
Slog.w(TAG, appToken + " already running, starting window not displayed. "
+ e.getMessage());
shouldSaveView = false;
- } catch (RuntimeException e) {
- // don't crash if something else bad happens, for example a
- // failure loading resources because we are loading from an app
- // on external storage that has been unmounted.
- Slog.w(TAG, appToken + " failed creating starting window", e);
- shouldSaveView = false;
} finally {
if (view != null && view.getParent() == null) {
Slog.w(TAG, "view not successfully added to wm, removing view");
@@ -427,9 +351,9 @@
}
}
if (shouldSaveView) {
- removeWindowSynced(taskId);
- mSplashScreenExecutor.executeDelayed(() -> removeWindowSynced(taskId),
- REMOVE_WHEN_TIMEOUT);
+ removeWindowNoAnimate(taskId);
+ mSplashScreenExecutor.executeDelayed(
+ () -> removeWindowNoAnimate(taskId), REMOVE_WHEN_TIMEOUT);
saveSplashScreenRecord(taskId, view);
}
return shouldSaveView;
@@ -449,24 +373,30 @@
}
}
- protected void removeWindowSynced(int taskId) {
+ private void removeWindowNoAnimate(int taskId) {
+ removeWindowSynced(taskId, null, null, false);
+ }
+
+ protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
if (record != null) {
- if (record.isWaitForContent()) {
- if (DEBUG_SPLASH_SCREEN) {
- Slog.v(TAG, "splash screen window haven't been draw yet");
- }
- mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT,
- () -> removeWindowSynced(taskId), null);
- return;
- }
if (record.mDecorView != null) {
if (DEBUG_SPLASH_SCREEN) {
Slog.v(TAG, "Removing splash screen window for task: " + taskId);
}
- final WindowManager wm = record.mDecorView.getContext()
- .getSystemService(WindowManager.class);
- wm.removeView(record.mDecorView);
+ if (record.mContentView != null) {
+ final HandleExitFinish exitFinish = new HandleExitFinish(record.mDecorView);
+ if (leash != null || playRevealAnimation) {
+ mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
+ leash, frame, record.isEarlyExit(), exitFinish);
+ mSplashScreenExecutor.executeDelayed(exitFinish, REMOVE_WHEN_TIMEOUT);
+ } else {
+ // the SplashScreenView has been copied to client, skip default exit
+ // animation
+ exitFinish.run();
+ }
+ }
}
if (record.mTaskSnapshotWindow != null) {
if (DEBUG_TASK_SNAPSHOT) {
@@ -478,6 +408,26 @@
}
}
+ private static class HandleExitFinish implements Runnable {
+ private View mDecorView;
+
+ HandleExitFinish(View decorView) {
+ mDecorView = decorView;
+ }
+
+ @Override
+ public void run() {
+ if (mDecorView == null) {
+ return;
+ }
+ final WindowManager wm = mDecorView.getContext().getSystemService(WindowManager.class);
+ if (wm != null) {
+ wm.removeView(mDecorView);
+ }
+ mDecorView = null;
+ }
+ }
+
private void getWindowResFromContext(Context ctx, Consumer<TypedArray> consumer) {
final TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window);
consumer.accept(a);
@@ -488,10 +438,12 @@
* Record the view or surface for a starting window.
*/
private static class StartingWindowRecord {
+ private static final long EARLY_START_MINIMUM_TIME_MS = 250;
private final View mDecorView;
private final TaskSnapshotWindow mTaskSnapshotWindow;
private SplashScreenView mContentView;
private boolean mSetSplashScreen;
+ private long mContentCreateTime;
StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
mDecorView = decorView;
@@ -503,11 +455,12 @@
return;
}
mContentView = splashScreenView;
+ mContentCreateTime = SystemClock.uptimeMillis();
mSetSplashScreen = true;
}
- private boolean isWaitForContent() {
- return mDecorView != null && !mSetSplashScreen;
+ boolean isEarlyExit() {
+ return SystemClock.uptimeMillis() - mContentCreateTime < EARLY_START_MINIMUM_TIME_MS;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 5eb7071..a694e52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -28,14 +28,17 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import android.view.SurfaceControl;
import android.window.StartingWindowInfo;
import android.window.TaskOrganizer;
import android.window.TaskSnapshot;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TransactionPool;
import java.util.function.BiConsumer;
@@ -67,8 +70,16 @@
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
private final ShellExecutor mSplashScreenExecutor;
+ // For Car Launcher
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
- mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor);
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
+ new TransactionPool());
+ mSplashScreenExecutor = splashScreenExecutor;
+ }
+
+ public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
+ TransactionPool pool) {
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
mSplashScreenExecutor = splashScreenExecutor;
}
@@ -112,7 +123,8 @@
+ " allowTaskSnapshot " + allowTaskSnapshot
+ " activityCreated " + activityCreated);
}
- if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ if ((newTask || !processRunning || (taskSwitch && !activityCreated))
+ && windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
}
if (taskSwitch && allowTaskSnapshot) {
@@ -198,8 +210,9 @@
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- void removeStartingWindow(int taskId) {
- mStartingSurfaceDrawer.removeStartingWindow(taskId);
+ void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
+ mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
}
private class StartingSurfaceImpl implements StartingSurface {
@@ -211,9 +224,11 @@
}
@Override
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
mSplashScreenExecutor.execute(() ->
- StartingWindowController.this.removeStartingWindow(taskId));
+ StartingWindowController.this.removeStartingWindow(taskId, leash, frame,
+ playRevealAnimation));
}
@Override
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index f06d57c..ad4ccc0 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -11,6 +11,8 @@
<option name="force-skip-system-props" value="true" />
<!-- set WM tracing verbose level to all -->
<option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
<!-- restart launcher to activate TAPL -->
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
</target_preparer>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index 90e7137..63968f3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -18,6 +18,7 @@
import android.os.SystemClock
import android.platform.test.annotations.Presubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -59,6 +60,14 @@
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
@Presubmit
@Test
fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index dc51b4f..63e9a78 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -56,6 +56,14 @@
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
@Presubmit
@Test
fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 5bb9b2f..234dda4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -61,6 +61,14 @@
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
@Presubmit
@Test
fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index 91e080f..128560a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -20,19 +20,23 @@
import android.platform.test.annotations.Presubmit
import android.system.helpers.ActivityHelper
import android.util.Log
+import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
import com.android.compatibility.common.util.SystemUtil
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -134,17 +138,39 @@
@Presubmit
@Test
- open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible()
+ }
@Presubmit
@Test
- open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible()
+ }
@Presubmit
@Test
- open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
@Presubmit
@Test
- open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
+ testSpec.config.endRotation)
+ }
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index 5f003ba..d341bb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -27,8 +27,6 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.appPairsDividerIsVisible
import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
@@ -75,16 +73,6 @@
@Test
fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0,
- testSpec.config.endRotation)
-
- @Presubmit
- @Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
- testSpec.config.endRotation)
-
@FlakyTest(bugId = 172776659)
@Test
fun appPairsPrimaryBoundsIsVisible() =
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index d479208..3bf0296 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -27,16 +27,13 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.appPairsDividerIsVisible
import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
-import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -67,20 +64,10 @@
@Presubmit
@Test
- fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0,
- testSpec.config.endRotation)
-
- @Presubmit
- @Test
fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
@Presubmit
@Test
- fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
- Surface.ROTATION_0, testSpec.config.endRotation)
-
- @Presubmit
- @Test
override fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index 75c33c6..0333227 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -23,13 +23,7 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,7 +42,6 @@
testSpec: FlickerTestParameter
) : PipTransition(testSpec) {
private val testApp = FixedAppHelper(instrumentation)
- private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = true) {
@@ -84,14 +77,6 @@
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
fun showBothAppLayersThenHidePip() {
testSpec.assertLayers {
isVisible(testApp.defaultWindowName)
@@ -118,14 +103,6 @@
}
}
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 2f08db1b7..4847c98 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -24,14 +25,6 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.startRotation
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,15 +50,7 @@
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun pipWindowBecomesVisible() {
+ fun pipAppWindowAlwaysVisible() {
testSpec.assertWm {
this.showsAppWindow(pipApp.defaultWindowName)
}
@@ -73,34 +58,37 @@
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
- @Presubmit
- @Test
fun pipLayerBecomesVisible() {
testSpec.assertLayers {
this.isVisible(pipApp.launcherName)
}
}
- @FlakyTest(bugId = 140855415)
+ @Postsubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun pipWindowBecomesVisible() {
+ testSpec.assertWm {
+ invoke("pipWindowIsNotVisible") { !it.wmState.hasPipWindow() }
+ .then()
+ .invoke("pipWindowIsVisible") { it.wmState.hasPipWindow() }
+ }
+ }
@FlakyTest(bugId = 140855415)
@Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
@FlakyTest(bugId = 140855415)
@Test
- fun noUncoveredRegions() =
- testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
+ @FlakyTest(bugId = 140855415)
+ @Test
+ override fun noUncoveredRegions() = super.noUncoveredRegions()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 9011f1a..ba88ee5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -18,16 +18,13 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -83,6 +80,14 @@
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
@Presubmit
@Test
fun pipAppWindowIsAlwaysOnTop() {
@@ -109,14 +114,6 @@
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
fun pipAppLayerHidesTestApp() {
testSpec.assertLayersStart {
coversExactly(startingBounds, pipApp.defaultWindowName)
@@ -132,14 +129,6 @@
}
}
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
index 3e33176..eae7e97 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
@@ -24,14 +24,7 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.Test
import org.junit.runners.Parameterized
@@ -52,22 +45,6 @@
@Presubmit
@Test
- open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
open fun pipWindowBecomesInvisible() {
testSpec.assertWm {
this.showsAppWindow(PIP_WINDOW_TITLE)
@@ -86,21 +63,6 @@
}
}
- @Presubmit
- @Test
- open fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
- @Presubmit
- @Test
- open fun noUncoveredRegions() =
- testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
-
- @Presubmit
- @Test
- open fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
@FlakyTest(bugId = 151179149)
@Test
open fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 97afc65..3309e10 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -24,17 +24,11 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.removeAllTasksButHome
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.FixMethodOrder
@@ -55,7 +49,6 @@
class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val imeApp = ImeAppHelper(instrumentation)
private val testApp = FixedAppHelper(instrumentation)
- private val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
@@ -105,11 +98,11 @@
@Postsubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
@Postsubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
@Postsubmit
@Test
@@ -130,11 +123,11 @@
@Postsubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
@Postsubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
companion object {
const val TEST_REPETITIONS = 2
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
index 4c95da2..d011419 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipMovesInAllApps.kt
@@ -24,8 +24,6 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.google.common.truth.Truth
import org.junit.FixMethodOrder
import org.junit.Test
@@ -59,11 +57,11 @@
@Postsubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
@Postsubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
@Postsubmit
@Test
@@ -71,6 +69,14 @@
@Postsubmit
@Test
+ fun pipLayerInsideDisplay() {
+ testSpec.assertLayersStart {
+ coversAtMost(displayBounds, pipApp.defaultWindowName)
+ }
+ }
+
+ @Postsubmit
+ @Test
fun pipWindowMovesUp() = testSpec.assertWmEnd {
val initialState = this.trace?.first()?.wmState
?: error("Trace should not be empty")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index df835d2..49a1055 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -29,10 +29,6 @@
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.statusBarLayerRotatesScales
@@ -77,34 +73,18 @@
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
testSpec.config.endRotation, allStates = false)
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
@FlakyTest(bugId = 140855415)
@Test
- fun navBarLayerRotatesAndScales() =
+ override fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
testSpec.config.endRotation)
@FlakyTest(bugId = 140855415)
@Test
- fun statusBarLayerRotatesScales() =
+ override fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
testSpec.config.endRotation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index 1bb1d28..945a20b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -26,14 +26,7 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -68,22 +61,6 @@
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
fun appReplacesPipWindow() {
testSpec.assertWm {
this.showsAppWindow(PIP_WINDOW_TITLE)
@@ -94,11 +71,6 @@
@Presubmit
@Test
- fun statusBarLayerRotatesScales() =
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
-
- @Presubmit
- @Test
fun appReplacesPipLayer() {
testSpec.assertLayers {
this.isVisible(PIP_WINDOW_TITLE)
@@ -107,15 +79,13 @@
}
}
- @Presubmit
+ @FlakyTest
@Test
- fun noUncoveredRegions() =
- testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() =
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ fun testAppCoversFullScreen() {
+ testSpec.assertLayersStart {
+ coversExactly(displayBounds, pipApp.defaultWindowName)
+ }
+ }
@FlakyTest(bugId = 151179149)
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index b0a9afe..7dc7e7d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -18,27 +18,37 @@
import android.app.Instrumentation
import android.content.Intent
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.helpers.PipAppHelper
import com.android.wm.shell.flicker.removeAllTasksButHome
import com.android.wm.shell.flicker.testapp.Components
+import org.junit.Test
abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
protected val isRotated = testSpec.config.startRotation.isRotated()
protected val pipApp = PipAppHelper(instrumentation)
+ protected val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
protected abstract val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
-
// Helper class to process test actions by broadcast.
protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) {
private fun createIntentWithAction(broadcastAction: String): Intent {
@@ -148,4 +158,35 @@
extraSpec(this, configuration)
}
}
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+
+ @Presubmit
+ @Test
+ open fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+
+ @Presubmit
+ @Test
+ open fun noUncoveredRegions() =
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 7916ce5..67e1768 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -25,10 +26,6 @@
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
@@ -83,6 +80,14 @@
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
@Presubmit
@Test
fun pipWindowInsideDisplay() {
@@ -101,20 +106,18 @@
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
fun pipLayerInsideDisplay() {
testSpec.assertLayersStart {
coversAtMost(startingBounds, pipApp.defaultWindowName)
}
}
+ @Postsubmit
+ @Test
+ fun pipAlwaysVisible() = testSpec.assertWm {
+ this.showsAppWindow(pipApp.windowName)
+ }
+
@Presubmit
@Test
fun pipAppLayerCoversFullScreen() {
@@ -123,14 +126,6 @@
}
}
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index a531ef5..207db9e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package unittest.src.com.android.wm.shell.startingsurface;
+package com.android.wm.shell.startingsurface;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -33,11 +33,12 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.testing.TestableContext;
-import android.view.Choreographer;
+import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowMetrics;
@@ -49,7 +50,7 @@
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
+import com.android.wm.shell.common.TransactionPool;
import org.junit.Before;
import org.junit.Test;
@@ -68,7 +69,7 @@
@Mock
private WindowManager mMockWindowManager;
@Mock
- private static Choreographer sFakeChoreographer;
+ private TransactionPool mTransactionPool;
TestStartingSurfaceDrawer mStartingSurfaceDrawer;
@@ -76,13 +77,9 @@
int mAddWindowForTask = 0;
int mViewThemeResId;
- TestStartingSurfaceDrawer(Context context, ShellExecutor executor) {
- super(context, executor);
- }
-
- @Override
- protected void initChoreographer() {
- mChoreographer = sFakeChoreographer;
+ TestStartingSurfaceDrawer(Context context, ShellExecutor animExecutor,
+ TransactionPool pool) {
+ super(context, animExecutor, pool);
}
@Override
@@ -95,7 +92,8 @@
}
@Override
- protected void removeWindowSynced(int taskId) {
+ protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
// listen for removeView
if (mAddWindowForTask == taskId) {
mAddWindowForTask = 0;
@@ -123,7 +121,8 @@
doNothing().when(mMockWindowManager).addView(any(), any());
mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context,
- new HandlerExecutor(new Handler(Looper.getMainLooper()))));
+ new HandlerExecutor(new Handler(Looper.getMainLooper())),
+ mTransactionPool));
}
@Test
@@ -137,9 +136,9 @@
verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
- mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId);
+ mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId, null, null, false);
waitHandlerIdle(mainLoop);
- verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId));
+ verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId), any(), any(), eq(false));
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
index 27e5f51..b908df2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package unittest.src.com.android.wm.shell.startingsurface;
+package com.android.wm.shell.startingsurface;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -48,7 +48,6 @@
import androidx.test.filters.SmallTest;
import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index c0ef7be..7e45f95 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -226,8 +226,6 @@
}
void AssetManager2::DumpToLog() const {
- base::ScopedLogSeverity _log(base::INFO);
-
LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this);
std::string list;
@@ -1721,7 +1719,6 @@
}
void Theme::Dump() const {
- base::ScopedLogSeverity _log(base::INFO);
LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
for (int p = 0; p < packages_.size(); p++) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9793300..800c580 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -576,6 +576,7 @@
if (requireSwap) {
if (mExpectSurfaceStats) {
+ reportMetricsWithPresentTime();
std::lock_guard lock(mLast4FrameInfosMutex);
std::pair<FrameInfo*, int64_t>& next = mLast4FrameInfos.next();
next.first = mCurrentFrameInfo;
@@ -656,8 +657,6 @@
}
}
- instance->reportMetricsWithPresentTime();
-
if (frameInfo != nullptr) {
if (gpuCompleteTime == -1) {
gpuCompleteTime = frameInfo->get(FrameInfoIndex::SwapBuffersCompleted);
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index f8b4bdb..50e0d33 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -99,8 +99,8 @@
__func__);
break;
}
- int sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize);
- ALOGV("%s: read %d", __func__, sampleSize);
+ ssize_t sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize);
+ ALOGV("%s: read %zd", __func__, sampleSize);
if (sampleSize < 0) {
sampleSize = 0;
sawInputEOS = true;
@@ -124,8 +124,8 @@
}
AMediaCodecBufferInfo info;
- const int status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1);
- ALOGV("%s: dequeueoutput returned: %d", __func__, status);
+ const ssize_t status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1);
+ ALOGV("%s: dequeueoutput returned: %zd", __func__, status);
if (status >= 0) {
if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
ALOGV("%s: output EOS", __func__);
@@ -167,10 +167,10 @@
} else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
ALOGV("%s: no output buffer right now", __func__);
} else if (status <= AMEDIA_ERROR_BASE) {
- ALOGE("%s: decode error: %d", __func__, status);
+ ALOGE("%s: decode error: %zd", __func__, status);
break;
} else {
- ALOGV("%s: unexpected info code: %d", __func__, status);
+ ALOGV("%s: unexpected info code: %zd", __func__, status);
}
}
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index abb0f12..95fe000 100644
--- a/media/jni/soundpool/Stream.cpp
+++ b/media/jni/soundpool/Stream.cpp
@@ -320,7 +320,8 @@
// audio track while the new one is being started and avoids processing them with
// wrong audio audio buffer size (mAudioBufferSize)
auto toggle = mToggle ^ 1;
- void* userData = (void*)((uintptr_t)this | toggle);
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ void* userData = reinterpret_cast<void*>((uintptr_t)this | toggle);
audio_channel_mask_t soundChannelMask = sound->getChannelMask();
// When sound contains a valid channel mask, use it as is.
// Otherwise, use stream count to calculate channel mask.
@@ -391,6 +392,7 @@
void Stream::staticCallback(int event, void* user, void* info)
{
const auto userAsInt = (uintptr_t)user;
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
auto stream = reinterpret_cast<Stream*>(userAsInt & ~1);
stream->callback(event, info, int(userAsInt & 1), 0 /* tries */);
}
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 502ee00..8b84bf3 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -330,7 +330,7 @@
// streams on mProcessingStreams are undergoing processing by the StreamManager thread
// and do not participate in normal stream migration.
- return found;
+ return (ssize_t)found;
}
void StreamManager::addToRestartQueue_l(Stream *stream) {
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 357cc63..a66d99f 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -34,7 +34,8 @@
jclass mSoundPoolClass;
} fields;
static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) {
- return (SoundPool*)env->GetLongField(thiz, fields.mNativeContext);
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ return reinterpret_cast<SoundPool*>(env->GetLongField(thiz, fields.mNativeContext));
}
static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
struct audio_attributes_fields_t {
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index a8f1a4d..243e4ca 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -143,6 +143,7 @@
public static class ConnectivityManager.NetworkCallback {
ctor public ConnectivityManager.NetworkCallback();
+ ctor public ConnectivityManager.NetworkCallback(int);
method public void onAvailable(@NonNull android.net.Network);
method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
@@ -150,6 +151,7 @@
method public void onLosing(@NonNull android.net.Network, int);
method public void onLost(@NonNull android.net.Network);
method public void onUnavailable();
+ field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1
}
public static interface ConnectivityManager.OnNetworkActiveListener {
@@ -293,6 +295,7 @@
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public int getOwnerUid();
method public int getSignalStrength();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
@@ -399,6 +402,11 @@
method public android.net.NetworkRequest.Builder removeTransportType(int);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+ method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ field public String response;
}
public class ProxyInfo implements android.os.Parcelable {
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index 6df57c1..4b33366 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -7,8 +7,9 @@
public class ConnectivityManager {
method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot();
+ method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
}
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index a732430..a98f14e 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -296,6 +296,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
+ method @NonNull public android.net.NetworkCapabilities.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index bbf4559..7189be1 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -16,10 +16,10 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.IpSecManager.INVALID_RESOURCE_ID;
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.LISTEN;
import static android.net.NetworkRequest.Type.REQUEST;
+import static android.net.NetworkRequest.Type.TRACK_BEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
import static android.net.QosCallback.QosCallbackRegistrationException;
@@ -43,6 +43,7 @@
import android.net.TetheringManager.StartTetheringCallback;
import android.net.TetheringManager.TetheringEventCallback;
import android.net.TetheringManager.TetheringRequest;
+import android.net.wifi.WifiNetworkSuggestion;
import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
@@ -1314,7 +1315,7 @@
}
/**
- * Returns an array of {@link android.net.NetworkCapabilities} objects, representing
+ * Returns an array of {@link NetworkCapabilities} objects, representing
* the Networks that applications run by the given user will use by default.
* @hide
*/
@@ -1394,11 +1395,19 @@
}
/**
- * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This
+ * Get the {@link NetworkCapabilities} for the given {@link Network}. This
* will return {@code null} if the network is unknown.
*
+ * This will remove any location sensitive data in {@link TransportInfo} embedded in
+ * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like
+ * {@link android.net.wifi.WifiInfo} contain location sensitive information. Retrieving
+ * this location sensitive information (subject to app's location permissions) will be
+ * noted by system. To include any location sensitive data in {@link TransportInfo},
+ * use a {@link NetworkCallback} with
+ * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag.
+ *
* @param network The {@link Network} object identifying the network in question.
- * @return The {@link android.net.NetworkCapabilities} for the network, or {@code null}.
+ * @return The {@link NetworkCapabilities} for the network, or {@code null}.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@Nullable
@@ -1996,7 +2005,7 @@
dup = createInvalidFd();
}
return new NattSocketKeepalive(mService, network, dup,
- INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback);
+ -1 /* Unused */, source, destination, executor, callback);
}
/**
@@ -3244,6 +3253,54 @@
*/
public static class NetworkCallback {
/**
+ * No flags associated with this callback.
+ * @hide
+ */
+ public static final int FLAG_NONE = 0;
+ /**
+ * Use this flag to include any location sensitive data in {@link NetworkCapabilities} sent
+ * via {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}.
+ * <p>
+ * These include:
+ * <li> Some transport info instances (retrieved via
+ * {@link NetworkCapabilities#getTransportInfo()}) like {@link android.net.wifi.WifiInfo}
+ * contain location sensitive information.
+ * <li> OwnerUid (retrieved via {@link NetworkCapabilities#getOwnerUid()} is location
+ * sensitive for wifi suggestor apps (i.e using {@link WifiNetworkSuggestion}).</li>
+ * </p>
+ * <p>
+ * Note:
+ * <li> Retrieving this location sensitive information (subject to app's location
+ * permissions) will be noted by system. </li>
+ * <li> Without this flag any {@link NetworkCapabilities} provided via the callback does
+ * not include location sensitive info.
+ * </p>
+ */
+ public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "FLAG_", value = {
+ FLAG_NONE,
+ FLAG_INCLUDE_LOCATION_INFO
+ })
+ public @interface Flag { }
+
+ /**
+ * All the valid flags for error checking.
+ */
+ private static final int VALID_FLAGS = FLAG_INCLUDE_LOCATION_INFO;
+
+ public NetworkCallback() {
+ this(FLAG_NONE);
+ }
+
+ public NetworkCallback(@Flag int flags) {
+ Preconditions.checkArgument((flags & VALID_FLAGS) == flags);
+ mFlags = flags;
+ }
+
+ /**
* Called when the framework connects to a new network to evaluate whether it satisfies this
* request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable}
* callback. There is no guarantee that this new network will satisfy any requests, or that
@@ -3380,7 +3437,7 @@
* calling these methods while in a callback may return an outdated or even a null object.
*
* @param network The {@link Network} whose capabilities have changed.
- * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
+ * @param networkCapabilities The new {@link NetworkCapabilities} for this
* network.
*/
public void onCapabilitiesChanged(@NonNull Network network,
@@ -3449,6 +3506,7 @@
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
private NetworkRequest networkRequest;
+ private final int mFlags;
}
/**
@@ -3638,14 +3696,15 @@
}
Messenger messenger = new Messenger(handler);
Binder binder = new Binder();
+ final int callbackFlags = callback.mFlags;
if (reqType == LISTEN) {
request = mService.listenForNetwork(
- need, messenger, binder, callingPackageName,
+ need, messenger, binder, callbackFlags, callingPackageName,
getAttributionTag());
} else {
request = mService.requestNetwork(
need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
- callingPackageName, getAttributionTag());
+ callbackFlags, callingPackageName, getAttributionTag());
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -3692,7 +3751,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* <p>This method will attempt to find the best network that matches the passed
* {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
@@ -3776,7 +3835,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)}
* but runs all the callbacks on the passed Handler.
@@ -3798,7 +3857,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
* by a timeout.
*
* This function behaves identically to the non-timed-out version
@@ -3833,7 +3892,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
* by a timeout.
*
* This method behaves identically to
@@ -3878,7 +3937,7 @@
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This function behaves identically to the version that takes a NetworkCallback, but instead
* of {@link NetworkCallback} a {@link PendingIntent} is used. This means
@@ -4190,6 +4249,18 @@
}
/**
+ * @hide
+ */
+ // TODO: Make it public api.
+ @SuppressLint("ExecutorRegistration")
+ public void registerBestMatchingNetworkCallback(@NonNull NetworkRequest request,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
+ final NetworkCapabilities nc = request.networkCapabilities;
+ final CallbackHandler cbHandler = new CallbackHandler(handler);
+ sendRequestForNetwork(nc, networkCallback, 0, TRACK_BEST, TYPE_NONE, cbHandler);
+ }
+
+ /**
* Requests bandwidth update for a given {@link Network} and returns whether the update request
* is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying
* network connection for updated bandwidth information. The caller will be notified via
@@ -4898,7 +4969,7 @@
}
/**
- * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, but
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, but
* does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
* be used to request that the system provide a network without causing the network to be
* in the foreground.
@@ -4979,10 +5050,10 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
})
public void requestBackgroundNetwork(@NonNull NetworkRequest request,
- @Nullable Handler handler, @NonNull NetworkCallback networkCallback) {
+ @NonNull Handler handler, @NonNull NetworkCallback networkCallback) {
final NetworkCapabilities nc = request.networkCapabilities;
sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
- TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
+ TYPE_NONE, new CallbackHandler(handler));
}
/**
@@ -5040,4 +5111,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ // The first network ID of IPSec tunnel interface.
+ private static final int TUN_INTF_NETID_START = 0xFC00;
+ // The network ID range of IPSec tunnel interface.
+ private static final int TUN_INTF_NETID_RANGE = 0x0400;
+
+ /**
+ * Get the network ID range reserved for IPSec tunnel interfaces.
+ *
+ * @return A Range which indicates the network ID range of IPSec tunnel interface.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ public static Range<Integer> getIpSecNetIdRange() {
+ return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index cd49258..f9393e3 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -143,7 +143,7 @@
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
- String callingPackageName, String callingAttributionTag);
+ int callbackFlags, String callingPackageName, String callingAttributionTag);
NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation, String callingPackageName, String callingAttributionTag);
@@ -151,7 +151,7 @@
void releasePendingNetworkRequest(in PendingIntent operation);
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, in IBinder binder, String callingPackageName,
+ in Messenger messenger, in IBinder binder, int callbackFlags, String callingPackageName,
String callingAttributionTag);
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index c82cd3b..058f3c9 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.wifi.WifiNetworkSuggestion;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -131,6 +132,7 @@
mPrivateDnsBroken = false;
mRequestorUid = Process.INVALID_UID;
mRequestorPackageName = null;
+ mSubIds = new ArraySet<>();
}
/**
@@ -159,6 +161,7 @@
mPrivateDnsBroken = nc.mPrivateDnsBroken;
mRequestorUid = nc.mRequestorUid;
mRequestorPackageName = nc.mRequestorPackageName;
+ mSubIds = new ArraySet<>(nc.mSubIds);
}
/**
@@ -1048,6 +1051,16 @@
*
* Instances of NetworkCapabilities sent to apps without the appropriate permissions will have
* this field cleared out.
+ *
+ * <p>
+ * This field will only be populated for VPN and wifi network suggestor apps (i.e using
+ * {@link WifiNetworkSuggestion}), and only for the network they own.
+ * In the case of wifi network suggestors apps, this field is also location sensitive, so the
+ * app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
+ * app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
+ * also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
+ * callback. The app will be blamed for location access if this field is included.
+ * </p>
*/
public int getOwnerUid() {
return mOwnerUid;
@@ -1655,6 +1668,7 @@
combineSSIDs(nc);
combineRequestor(nc);
combineAdministratorUids(nc);
+ combineSubIds(nc);
}
/**
@@ -1674,8 +1688,9 @@
&& satisfiedBySpecifier(nc)
&& (onlyImmutable || satisfiedBySignalStrength(nc))
&& (onlyImmutable || satisfiedByUids(nc))
- && (onlyImmutable || satisfiedBySSID(nc)))
- && (onlyImmutable || satisfiedByRequestor(nc));
+ && (onlyImmutable || satisfiedBySSID(nc))
+ && (onlyImmutable || satisfiedByRequestor(nc))
+ && (onlyImmutable || satisfiedBySubIds(nc)));
}
/**
@@ -1771,7 +1786,8 @@
&& equalsOwnerUid(that)
&& equalsPrivateDnsBroken(that)
&& equalsRequestor(that)
- && equalsAdministratorUids(that);
+ && equalsAdministratorUids(that)
+ && equalsSubIds(that);
}
@Override
@@ -1793,7 +1809,8 @@
+ Objects.hashCode(mPrivateDnsBroken) * 47
+ Objects.hashCode(mRequestorUid) * 53
+ Objects.hashCode(mRequestorPackageName) * 59
- + Arrays.hashCode(mAdministratorUids) * 61;
+ + Arrays.hashCode(mAdministratorUids) * 61
+ + Objects.hashCode(mSubIds) * 67;
}
@Override
@@ -1827,6 +1844,7 @@
dest.writeInt(mOwnerUid);
dest.writeInt(mRequestorUid);
dest.writeString(mRequestorPackageName);
+ dest.writeIntArray(CollectionUtils.toIntArray(mSubIds));
}
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1850,6 +1868,11 @@
netCap.mOwnerUid = in.readInt();
netCap.mRequestorUid = in.readInt();
netCap.mRequestorPackageName = in.readString();
+ netCap.mSubIds = new ArraySet<>();
+ final int[] subIdInts = Objects.requireNonNull(in.createIntArray());
+ for (int i = 0; i < subIdInts.length; i++) {
+ netCap.mSubIds.add(subIdInts[i]);
+ }
return netCap;
}
@Override
@@ -1933,11 +1956,14 @@
sb.append(" SSID: ").append(mSSID);
}
-
if (mPrivateDnsBroken) {
sb.append(" PrivateDnsBroken");
}
+ if (!mSubIds.isEmpty()) {
+ sb.append(" SubscriptionIds: ").append(mSubIds);
+ }
+
sb.append("]");
return sb.toString();
}
@@ -2251,6 +2277,67 @@
}
/**
+ * Set of the subscription IDs that identifies the network or request, empty if none.
+ */
+ @NonNull
+ private ArraySet<Integer> mSubIds = new ArraySet<>();
+
+ /**
+ * Sets the subscription ID set that associated to this network or request.
+ *
+ * @hide
+ */
+ @NonNull
+ public NetworkCapabilities setSubIds(@NonNull Set<Integer> subIds) {
+ mSubIds = new ArraySet(Objects.requireNonNull(subIds));
+ return this;
+ }
+
+ /**
+ * Gets the subscription ID set that associated to this network or request.
+ * @return
+ */
+ @NonNull
+ public Set<Integer> getSubIds() {
+ return new ArraySet<>(mSubIds);
+ }
+
+ /**
+ * Tests if the subscription ID set of this network is the same as that of the passed one.
+ */
+ private boolean equalsSubIds(@NonNull NetworkCapabilities nc) {
+ return Objects.equals(mSubIds, nc.mSubIds);
+ }
+
+ /**
+ * Check if the subscription ID set requirements of this object are matched by the passed one.
+ * If specified in the request, the passed one need to have at least one subId and at least
+ * one of them needs to be in the request set.
+ */
+ private boolean satisfiedBySubIds(@NonNull NetworkCapabilities nc) {
+ if (mSubIds.isEmpty()) return true;
+ if (nc.mSubIds.isEmpty()) return false;
+ for (final Integer subId : nc.mSubIds) {
+ if (mSubIds.contains(subId)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Combine subscription ID set of the capabilities.
+ *
+ * <p>This is only legal if the subscription Ids are equal.
+ *
+ * <p>If both subscription IDs are not equal, they belong to different subscription
+ * (or no subscription). In this case, it would not make sense to add them together.
+ */
+ private void combineSubIds(@NonNull NetworkCapabilities nc) {
+ if (!Objects.equals(mSubIds, nc.mSubIds)) {
+ throw new IllegalStateException("Can't combine two subscription ID sets");
+ }
+ }
+
+ /**
* Builder class for NetworkCapabilities.
*
* This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
@@ -2556,6 +2643,18 @@
}
/**
+ * Set the subscription ID set.
+ *
+ * @param subIds a set that represent the subscription IDs. Empty if clean up.
+ * @return this builder.
+ */
+ @NonNull
+ public Builder setSubIds(@NonNull final Set<Integer> subIds) {
+ mCaps.setSubIds(subIds);
+ return this;
+ }
+
+ /**
* Builds the instance of the capabilities.
*
* @return the built instance of NetworkCapabilities.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
index d752901..bb23494 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkInfo.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
@@ -21,7 +21,6 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Annotation.NetworkType;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -164,7 +163,7 @@
* @param typeName a human-readable string for the network type, or an empty string or null.
* @param subtypeName a human-readable string for the subtype, or an empty string or null.
*/
- public NetworkInfo(int type, @NetworkType int subtype,
+ public NetworkInfo(int type, int subtype,
@Nullable String typeName, @Nullable String subtypeName) {
if (!ConnectivityManager.isNetworkTypeValid(type)
&& type != ConnectivityManager.TYPE_NONE) {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index 17a8ee1..3fd95ee 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -114,6 +114,10 @@
* for the network (if any) that satisfies the default Internet
* request.
*
+ * - TRACK_BEST, which causes the framework to send callbacks about
+ * the single, highest scoring current network (if any) that matches
+ * the specified NetworkCapabilities.
+ *
* - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
* to retain the NET_CAPABILITY_FOREGROUND capability. A network with
* no foreground requests is in the background. A network that has
@@ -136,6 +140,7 @@
REQUEST,
BACKGROUND_REQUEST,
TRACK_SYSTEM_DEFAULT,
+ TRACK_BEST,
};
/**
@@ -456,6 +461,21 @@
}
nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
}
+
+ /**
+ * Sets the optional subscription ID set.
+ * <p>
+ * This specify the subscription IDs requirement.
+ * A network will satisfy this request only if it matches one of the subIds in this set.
+ * An empty set matches all networks, including those without a subId.
+ *
+ * @param subIds A {@code Set} that represents subscription IDs.
+ */
+ @NonNull
+ public Builder setSubIds(@NonNull Set<Integer> subIds) {
+ mNetworkCapabilities.setSubIds(subIds);
+ return this;
+ }
}
// implement the Parcelable interface
diff --git a/packages/Connectivity/framework/src/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java
index d010265..9b69674 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkState.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkState.java
@@ -22,7 +22,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Slog;
+import android.util.Log;
/**
* Snapshot of network state.
@@ -83,7 +83,7 @@
if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) {
if (networkInfo.isRoaming() == networkCapabilities
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
- Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+ Log.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+ " and " + networkCapabilities);
}
}
diff --git a/core/java/android/net/ParseException.java b/packages/Connectivity/framework/src/android/net/ParseException.java
similarity index 100%
rename from core/java/android/net/ParseException.java
rename to packages/Connectivity/framework/src/android/net/ParseException.java
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
index d37c469..53d9669 100644
--- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
+++ b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
@@ -92,7 +92,7 @@
Objects.requireNonNull(socket, "socket cannot be null");
mNetwork = Objects.requireNonNull(network, "network cannot be null");
- mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+ mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
mLocalSocketAddress =
new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
}
@@ -114,10 +114,10 @@
try {
return new InetSocketAddress(InetAddress.getByAddress(address), port);
} catch (final UnknownHostException e) {
- /* The catch block was purposely left empty. UnknownHostException will never be thrown
+ /* This can never happen. UnknownHostException will never be thrown
since the address provided is numeric and non-null. */
+ throw new RuntimeException("UnknownHostException on numeric address", e);
}
- return new InetSocketAddress();
}
@Override
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index 856f3b8..f630cea 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -60,6 +60,7 @@
"services.core",
"services.net",
"unsupportedappusage",
+ "ServiceConnectivityResources",
],
static_libs: [
"modules-utils-os",
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
new file mode 100644
index 0000000..f2446b7
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// APK to hold all the wifi overlayable resources.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "ServiceConnectivityResources",
+ sdk_version: "system_current",
+ resource_dirs: [
+ "res",
+ ],
+ privileged: true,
+ export_package_resources: true,
+ apex_available: [
+ "com.android.tethering",
+ ],
+ // TODO: use a dedicated cert once generated
+ certificate: "platform",
+}
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml b/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml
new file mode 100644
index 0000000..2c30302
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<!-- Manifest for connectivity resources APK -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.connectivity.resources"
+ coreApp="true"
+ android:versionCode="1"
+ android:versionName="S-initial">
+ <application
+ android:label="@string/connectivityResourcesAppLabel"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
+ <!-- This is only used to identify this app by resolving the action.
+ The activity is never actually triggered. -->
+ <activity android:name="android.app.Activity" android:exported="true" android:enabled="true">
+ <intent-filter>
+ <action android:name="com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
new file mode 100644
index 0000000..7d98c76
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+
+ <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
+ If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+ and if that value is empty, the framework will use a hard-coded default.
+ This is *NOT* a URL that will always be used by the system network validation to detect
+ captive portals: NetworkMonitor may use different strategies and will not necessarily use
+ this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
+ instead. -->
+ <!--suppress CheckTagEmptyBody -->
+ <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
+
+ <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
+ <integer name="config_networkTransitionTimeout">60000</integer>
+
+ <!-- Configuration of network interfaces that support WakeOnLAN -->
+ <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
+ <!--
+ <item>wlan0</item>
+ <item>eth0</item>
+ -->
+ </string-array>
+
+</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
new file mode 100644
index 0000000..00ec2df
--- /dev/null
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <overlayable name="ServiceConnectivityResourcesConfig">
+ <policy type="product|system|vendor">
+ <!-- Configuration values for ConnectivityService -->
+ <item type="string" name="config_networkCaptivePortalServerUrl"/>
+ <item type="integer" name="config_networkTransitionTimeout"/>
+ <item type="array" name="config_wakeonlan_supported_interfaces"/>
+
+
+ </policy>
+ </overlayable>
+</resources>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
similarity index 62%
copy from packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
copy to packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
index f32faa0..2c7b992 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
+++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
@@ -14,9 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/udfps_animation_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
+<resources>
+ <!-- The System Connectivity Resources package is an internal system package that provides
+ configuration values for system networking that were pre-configured in the device. This
+ is the name of the package to display in the list of system apps. [CHAR LIMIT=40] -->
+ <string name="connectivityResourcesAppLabel">System Connectivity Resources</string>
+</resources>
\ No newline at end of file
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index 180dfb6..784a747 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index d87ea7f..5b7bda4 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index 180dfb6..784a747 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 3124651..780cb8a 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index c1dca5d..16a946d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -138,9 +138,6 @@
private long mCurrentPartitionSize;
private long mCurrentPartitionInstalledSize;
- private boolean mJustCancelledByUser;
- private boolean mKeepNotification;
-
// This is for testing only now
private boolean mEnableWhenCompleted;
@@ -174,11 +171,6 @@
if (cache != null) {
cache.flush();
}
-
- if (!mKeepNotification) {
- // Cancel the persistent notification.
- mNM.cancel(NOTIFICATION_ID);
- }
}
@Override
@@ -231,9 +223,11 @@
return;
}
+ boolean removeNotification = false;
switch (result) {
case RESULT_CANCELLED:
postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+ removeNotification = true;
break;
case RESULT_ERROR_IO:
@@ -251,7 +245,7 @@
}
// if it's not successful, reset the task and stop self.
- resetTaskAndStop();
+ resetTaskAndStop(removeNotification);
}
private void executeInstallCommand(Intent intent) {
@@ -302,12 +296,12 @@
return;
}
- stopForeground(true);
- mJustCancelledByUser = true;
-
if (mInstallTask.cancel(false)) {
- // Will stopSelf() in onResult()
+ // onResult() would call resetTaskAndStop() upon task completion.
Log.d(TAG, "Cancel request filed successfully");
+ // Dismiss the notification as soon as possible as DynamicSystemManager.remove() may
+ // block.
+ stopForeground(STOP_FOREGROUND_REMOVE);
} else {
Log.e(TAG, "Trying to cancel installation while it's already completed.");
}
@@ -322,8 +316,7 @@
if (!isDynamicSystemInstalled() && (getStatus() != STATUS_READY)) {
Log.e(TAG, "Trying to discard AOT while there is no complete installation");
// Stop foreground state and dismiss stale notification.
- stopForeground(STOP_FOREGROUND_REMOVE);
- resetTaskAndStop();
+ resetTaskAndStop(true);
return;
}
@@ -331,8 +324,8 @@
getString(R.string.toast_dynsystem_discarded),
Toast.LENGTH_LONG).show();
- resetTaskAndStop();
postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+ resetTaskAndStop(true);
mDynSystem.remove();
}
@@ -412,12 +405,13 @@
}
private void resetTaskAndStop() {
- mInstallTask = null;
+ resetTaskAndStop(/* removeNotification= */ false);
+ }
- new Handler().postDelayed(() -> {
- stopForeground(STOP_FOREGROUND_DETACH);
- stopSelf();
- }, 50);
+ private void resetTaskAndStop(boolean removeNotification) {
+ mInstallTask = null;
+ stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : STOP_FOREGROUND_DETACH);
+ stopSelf();
}
private void prepareNotification() {
@@ -525,7 +519,7 @@
private void postStatus(int status, int cause, Throwable detail) {
String statusString;
String causeString;
- mKeepNotification = false;
+ boolean notifyOnNotificationBar = true;
switch (status) {
case STATUS_NOT_STARTED:
@@ -551,18 +545,16 @@
break;
case CAUSE_INSTALL_CANCELLED:
causeString = "INSTALL_CANCELLED";
+ notifyOnNotificationBar = false;
break;
case CAUSE_ERROR_IO:
causeString = "ERROR_IO";
- mKeepNotification = true;
break;
case CAUSE_ERROR_INVALID_URL:
causeString = "ERROR_INVALID_URL";
- mKeepNotification = true;
break;
case CAUSE_ERROR_EXCEPTION:
causeString = "ERROR_EXCEPTION";
- mKeepNotification = true;
break;
default:
causeString = "CAUSE_NOT_SPECIFIED";
@@ -571,16 +563,6 @@
Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
- boolean notifyOnNotificationBar = true;
-
- if (status == STATUS_NOT_STARTED
- && cause == CAUSE_INSTALL_CANCELLED
- && mJustCancelledByUser) {
- // if task is cancelled by user, do not notify them
- notifyOnNotificationBar = false;
- mJustCancelledByUser = false;
- }
-
if (notifyOnNotificationBar) {
mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail));
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a28a1e3..b4194fd 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -426,6 +426,9 @@
<!-- Permission required for CTS test - ClipboardManagerTest -->
<uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
+ <!-- Permission required for CTS test - FontManagerTest -->
+ <uses-permission android:name="android.permission.UPDATE_FONTS" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 4fc1973..0d348e2 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -44,7 +44,7 @@
/**
* Returns true if the FalsingManager thinks the last gesure was not a valid tap.
*
- * Accepts one parameter, robustCheck, that distinctly changes behavior. When set to false,
+ * The first parameter, robustCheck, distinctly changes behavior. When set to false,
* this method simply looks at the last gesture and returns whether it is a tap or not, (as
* opposed to a swipe or other non-tap gesture). When set to true, a more thorough analysis
* is performed that can include historical interactions and other contextual cues to see
@@ -53,8 +53,11 @@
* Set robustCheck to true if you want to validate a tap for launching an action, like opening
* a notification. Set to false if you simply want to know if the last gesture looked like a
* tap.
+ *
+ * The second parameter, falsePenalty, indicates how much this should affect future gesture
+ * classifications if this tap looks like a false.
*/
- boolean isFalseTap(boolean robustCheck);
+ boolean isFalseTap(boolean robustCheck, double falsePenalty);
/**
* Returns true if the last two gestures do not look like a double tap.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index 53f7e44..ca13204 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -50,4 +50,8 @@
public abstract void onStateChanged(State state);
public abstract int getDetailY();
+
+ public View getLabelContainer() {
+ return null;
+ }
}
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml b/packages/SystemUI/res/drawable/qs_tile_background.xml
similarity index 66%
copy from packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
copy to packages/SystemUI/res/drawable/qs_tile_background.xml
index f32faa0..265f575 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_background.xml
@@ -14,9 +14,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/udfps_animation_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask"
+ android:drawable="@drawable/qs_tile_background_shape" />
+ <item android:id="@id/background"
+ android:drawable="@drawable/qs_tile_background_shape"/>
+</ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml b/packages/SystemUI/res/drawable/qs_tile_background_shape.xml
similarity index 68%
copy from packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
copy to packages/SystemUI/res/drawable/qs_tile_background_shape.xml
index f32faa0..f6b6834 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_background_shape.xml
@@ -14,9 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/udfps_animation_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/qs_corner_radius" />
+ <solid android:color="#FFFFFF" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml b/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
deleted file mode 100644
index 644d1ada..0000000
--- a/packages/SystemUI/res/layout/udfps_animation_view_keyguard.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<com.android.systemui.biometrics.UdfpsAnimationViewKeyguard
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/udfps_animation_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewKeyguard>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_bp.xml b/packages/SystemUI/res/layout/udfps_bp_view.xml
similarity index 88%
rename from packages/SystemUI/res/layout/udfps_animation_view_bp.xml
rename to packages/SystemUI/res/layout/udfps_bp_view.xml
index 0cfbf2e..f1c55ef 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_bp.xml
+++ b/packages/SystemUI/res/layout/udfps_bp_view.xml
@@ -14,9 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsAnimationViewBp
+<com.android.systemui.biometrics.UdfpsBpView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/udfps_animation_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewBp>
+</com.android.systemui.biometrics.UdfpsBpView>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml b/packages/SystemUI/res/layout/udfps_enroll_view.xml
similarity index 79%
rename from packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
rename to packages/SystemUI/res/layout/udfps_enroll_view.xml
index 9b5752d..4035305 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_enroll.xml
+++ b/packages/SystemUI/res/layout/udfps_enroll_view.xml
@@ -14,13 +14,13 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsAnimationViewEnroll
+<com.android.systemui.biometrics.UdfpsEnrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/udfps_animation_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <!-- Enrollment progress bar-->
+ <!-- Enrollment progress bar -->
<com.android.systemui.biometrics.UdfpsProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
@@ -31,4 +31,9 @@
android:layout_gravity="center"
android:visibility="gone"/>
-</com.android.systemui.biometrics.UdfpsAnimationViewEnroll>
+ <!-- Fingerprint -->
+ <ImageView
+ android:id="@+id/udfps_enroll_animation_fp_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</com.android.systemui.biometrics.UdfpsEnrollView>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml b/packages/SystemUI/res/layout/udfps_fpm_other_view.xml
similarity index 74%
rename from packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
rename to packages/SystemUI/res/layout/udfps_fpm_other_view.xml
index f32faa0..6ecbb47 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
+++ b/packages/SystemUI/res/layout/udfps_fpm_other_view.xml
@@ -14,9 +14,15 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
+<com.android.systemui.biometrics.UdfpsFpmOtherView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/udfps_animation_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
+
+ <!-- Fingerprint -->
+ <ImageView
+ android:id="@+id/udfps_fpm_other_fp_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</com.android.systemui.biometrics.UdfpsFpmOtherView>
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
similarity index 71%
copy from packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
copy to packages/SystemUI/res/layout/udfps_keyguard_view.xml
index f32faa0..0199ccb 100644
--- a/packages/SystemUI/res/layout/udfps_animation_view_fpm_other.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -14,9 +14,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.UdfpsAnimationViewFpmOther
+<com.android.systemui.biometrics.UdfpsKeyguardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/udfps_animation_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
-</com.android.systemui.biometrics.UdfpsAnimationViewFpmOther>
+
+ <!-- TODO: add background protection -->
+
+ <!-- Fingerprint -->
+ <ImageView
+ android:id="@+id/udfps_keyguard_animation_fp_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</com.android.systemui.biometrics.UdfpsKeyguardView>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index e24c9e9..50b2f20 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -22,6 +22,11 @@
android:layout_height="match_parent"
systemui:sensorTouchAreaCoefficient="0.5">
+ <ViewStub
+ android:id="@+id/animation_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
<com.android.systemui.biometrics.UdfpsSurfaceView
android:id="@+id/hbm_view"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 885cd254..2062104 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -512,6 +512,7 @@
<!-- The size of the gesture span needed to activate the "pull" notification expansion -->
<dimen name="pull_span_min">25dp</dimen>
+ <dimen name="qs_corner_radius">14dp</dimen>
<dimen name="qs_tile_height">96dp</dimen>
<!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
<dimen name="qs_tile_layout_margin_side">18dp</dimen>
@@ -528,6 +529,8 @@
<dimen name="qs_tile_margin_top">0dp</dimen>
<dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
<dimen name="qs_tile_background_size">44dp</dimen>
+ <dimen name="qs_icon_size">20dp</dimen>
+ <dimen name="qs_label_container_margin">10dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index ebb6e30..e9e9b24 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -289,15 +289,19 @@
/**
* Returns the visible width to height ratio. Returns 0f if snapshot data is not available.
*/
- public float getVisibleThumbnailRatio() {
+ public float getVisibleThumbnailRatio(boolean clipInsets) {
if (lastSnapshotData.taskSize == null || lastSnapshotData.contentInsets == null) {
return 0f;
}
- float availableWidth = lastSnapshotData.taskSize.x - (lastSnapshotData.contentInsets.left
- + lastSnapshotData.contentInsets.right);
- float availableHeight = lastSnapshotData.taskSize.y - (lastSnapshotData.contentInsets.top
- + lastSnapshotData.contentInsets.bottom);
+ float availableWidth = lastSnapshotData.taskSize.x;
+ float availableHeight = lastSnapshotData.taskSize.y;
+ if (clipInsets) {
+ availableWidth -=
+ (lastSnapshotData.contentInsets.left + lastSnapshotData.contentInsets.right);
+ availableHeight -=
+ (lastSnapshotData.contentInsets.top + lastSnapshotData.contentInsets.bottom);
+ }
return availableWidth / availableHeight;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index af7c5da..c2d52a7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -16,11 +16,11 @@
package com.android.systemui.shared.system;
-import android.window.TaskSnapshot;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.IRecentsAnimationController;
+import android.window.TaskSnapshot;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -141,9 +141,9 @@
/**
* @see IRecentsAnimationController#detachNavigationBarFromApp
*/
- public void detachNavigationBarFromApp() {
+ public void detachNavigationBarFromApp(boolean moveHomeToTop) {
try {
- mAnimationController.detachNavigationBarFromApp();
+ mAnimationController.detachNavigationBarFromApp(moveHomeToTop);
} catch (RemoteException e) {
Log.e(TAG, "Failed to detach the navigation bar from app", e);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 1569fff..3f0e3eb 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -45,6 +45,7 @@
private int mLockScreenColor;
private boolean mIsDozing;
+ private float mDozeAmount;
private Locale mLocale;
private final NumberFormat mBurmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my"));
@@ -59,6 +60,7 @@
super(view);
mStatusBarStateController = statusBarStateController;
mIsDozing = mStatusBarStateController.isDozing();
+ mDozeAmount = mStatusBarStateController.getDozeAmount();
mBroadcastDispatcher = broadcastDispatcher;
mBurmeseNumerals = mBurmeseNf.format(FORMAT_NUMBER);
@@ -82,6 +84,7 @@
new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
mStatusBarStateController.addCallback(mStatusBarStateListener);
mIsDozing = mStatusBarStateController.isDozing();
+ mDozeAmount = mStatusBarStateController.getDozeAmount();
refreshTime();
initColors();
}
@@ -136,9 +139,15 @@
private final StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
- public void onDozingChanged(boolean isDozing) {
- mIsDozing = isDozing;
- mView.animateDoze(mIsDozing, true);
+ public void onDozeAmountChanged(float linear, float eased) {
+ boolean noAnimation = (mDozeAmount == 0f && linear == 1f)
+ || (mDozeAmount == 1f && linear == 0f);
+ boolean isDozing = linear > mDozeAmount;
+ mDozeAmount = linear;
+ if (mIsDozing != isDozing) {
+ mIsDozing = isDozing;
+ mView.animateDoze(mIsDozing, !noAnimation);
+ }
}
};
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 5760565..a580663 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -35,12 +35,15 @@
import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingClassifier;
+import com.android.systemui.classifier.FalsingCollector;
public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKeyInputView>
extends KeyguardInputViewController<T> {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final LockPatternUtils mLockPatternUtils;
private final LatencyTracker mLatencyTracker;
+ private final FalsingCollector mFalsingCollector;
private CountDownTimer mCountdownTimer;
protected KeyguardMessageAreaController mMessageAreaController;
private boolean mDismissing;
@@ -70,11 +73,12 @@
LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker) {
+ LatencyTracker latencyTracker, FalsingCollector falsingCollector) {
super(view, securityMode, keyguardSecurityCallback);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
+ mFalsingCollector = falsingCollector;
KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
mMessageAreaController = messageAreaControllerFactory.create(kma);
}
@@ -256,6 +260,7 @@
}
protected void onUserInput() {
+ mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.passed(0.6));
getKeyguardSecurityCallback().userActivity();
getKeyguardSecurityCallback().onUserInput();
mMessageAreaController.setMessage("");
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
index 5e02e04..de64f07 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
@@ -26,16 +26,11 @@
import androidx.annotation.Nullable;
import com.android.internal.jank.InteractionJankMonitor;
-import com.android.systemui.Gefingerpoken;
-
-import java.util.ArrayList;
-import java.util.List;
/**
* A Base class for all Keyguard password/pattern/pin related inputs.
*/
public abstract class KeyguardInputView extends LinearLayout {
- private final List<Gefingerpoken> mMotionEventListener = new ArrayList<>();
public KeyguardInputView(Context context) {
super(context);
@@ -53,7 +48,6 @@
abstract CharSequence getTitle();
void animateForIme(float interpolatedFraction) {
- return;
}
boolean disallowInterceptTouch(MotionEvent event) {
@@ -66,27 +60,6 @@
return false;
}
- void addMotionEventListener(Gefingerpoken listener) {
- mMotionEventListener.add(listener);
- }
-
- void removeMotionEventListener(Gefingerpoken listener) {
- mMotionEventListener.remove(listener);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return mMotionEventListener.stream().anyMatch(listener -> listener.onTouchEvent(event))
- || super.onTouchEvent(event);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- return mMotionEventListener.stream().anyMatch(
- listener -> listener.onInterceptTouchEvent(event))
- || super.onInterceptTouchEvent(event);
- }
-
protected AnimatorListenerAdapter getAnimationListener(int cuj) {
return new AnimatorListenerAdapter() {
private boolean mIsCancel;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 957882d..05f33a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -155,8 +155,8 @@
private final InputMethodManager mInputMethodManager;
private final DelayableExecutor mMainExecutor;
private final Resources mResources;
- private LiftToActivateListener mLiftToActivateListener;
- private TelephonyManager mTelephonyManager;
+ private final LiftToActivateListener mLiftToActivateListener;
+ private final TelephonyManager mTelephonyManager;
private final FalsingCollector mFalsingCollector;
private final boolean mIsNewLayoutEnabled;
@@ -167,8 +167,7 @@
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
@Main Resources resources, LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager,
- FalsingCollector falsingCollector,
+ TelephonyManager telephonyManager, FalsingCollector falsingCollector,
FeatureFlags featureFlags) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -189,12 +188,13 @@
if (keyguardInputView instanceof KeyguardPatternView) {
return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
- keyguardSecurityCallback, mLatencyTracker, mMessageAreaControllerFactory);
+ keyguardSecurityCallback, mLatencyTracker, mFalsingCollector,
+ mMessageAreaControllerFactory);
} else if (keyguardInputView instanceof KeyguardPasswordView) {
return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mInputMethodManager, mMainExecutor, mResources);
+ mInputMethodManager, mMainExecutor, mResources, mFalsingCollector);
} else if (keyguardInputView instanceof KeyguardPINView) {
return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
@@ -204,14 +204,14 @@
return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager,
- mFalsingCollector, mIsNewLayoutEnabled);
+ mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
+ mIsNewLayoutEnabled);
} else if (keyguardInputView instanceof KeyguardSimPukView) {
return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager,
- mFalsingCollector, mIsNewLayoutEnabled);
+ mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
+ mIsNewLayoutEnabled);
}
throw new RuntimeException("Unable to find controller for " + keyguardInputView);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 0f1c3c8..57b8cf0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -40,6 +40,7 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -112,9 +113,10 @@
LatencyTracker latencyTracker,
InputMethodManager inputMethodManager,
@Main DelayableExecutor mainExecutor,
- @Main Resources resources) {
+ @Main Resources resources,
+ FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker);
+ messageAreaControllerFactory, latencyTracker, falsingCollector);
mKeyguardSecurityCallback = keyguardSecurityCallback;
mInputMethodManager = inputMethodManager;
mMainExecutor = mainExecutor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 2aaf748..4f48bb4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -23,6 +23,7 @@
import android.os.AsyncTask;
import android.os.CountDownTimer;
import android.os.SystemClock;
+import android.view.MotionEvent;
import android.view.View;
import com.android.internal.util.LatencyTracker;
@@ -35,6 +36,8 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingClassifier;
+import com.android.systemui.classifier.FalsingCollector;
import java.util.List;
@@ -50,6 +53,7 @@
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final LockPatternUtils mLockPatternUtils;
private final LatencyTracker mLatencyTracker;
+ private final FalsingCollector mFalsingCollector;
private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
private KeyguardMessageAreaController mMessageAreaController;
@@ -102,6 +106,11 @@
final int userId = KeyguardUpdateMonitor.getCurrentUser();
if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
+ // Treat single-sized patterns as erroneous taps.
+ if (pattern.size() == 1) {
+ mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.falsed(
+ 0.7, "empty pattern input"));
+ }
mLockPatternView.enableInput();
onPatternChecked(userId, false, 0, false /* not valid - too short */);
return;
@@ -179,11 +188,13 @@
LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
LatencyTracker latencyTracker,
+ FalsingCollector falsingCollector,
KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
super(view, securityMode, keyguardSecurityCallback);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
+ mFalsingCollector = falsingCollector;
mMessageAreaControllerFactory = messageAreaControllerFactory;
KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
mMessageAreaController = mMessageAreaControllerFactory.create(kma);
@@ -205,6 +216,12 @@
KeyguardUpdateMonitor.getCurrentUser()));
// vibrate mode will be the same for the life of this screen
mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
+ mLockPatternView.setOnTouchListener((v, event) -> {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mFalsingCollector.avoidGesture();
+ }
+ return false;
+ });
EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
if (button != null) {
@@ -224,6 +241,7 @@
protected void onViewDetached() {
super.onViewDetached();
mLockPatternView.setOnPatternListener(null);
+ mLockPatternView.setOnTouchListener(null);
EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
if (button != null) {
button.setCallback(null);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 4e06491..09fb8ef 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -164,6 +164,10 @@
reloadColors();
}
+ NumPadKey[] getButtons() {
+ return mButtons;
+ }
+
/**
* By default, the new layout will be enabled. When false, revert to the old style.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index f247948..b156f81 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -25,7 +25,6 @@
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
@@ -50,19 +49,6 @@
return false;
};
- private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- mFalsingCollector.avoidGesture();
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- return false;
- }
- };
-
protected KeyguardPinBasedInputViewController(T view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
SecurityMode securityMode,
@@ -73,7 +59,7 @@
LiftToActivateListener liftToActivateListener,
FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker);
+ messageAreaControllerFactory, latencyTracker, falsingCollector);
mLiftToActivateListener = liftToActivateListener;
mFalsingCollector = falsingCollector;
mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
@@ -83,8 +69,14 @@
protected void onViewAttached() {
super.onViewAttached();
- mView.addMotionEventListener(mGlobalTouchListener);
-
+ for (NumPadKey button: mView.getButtons()) {
+ button.setOnTouchListener((v, event) -> {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mFalsingCollector.avoidGesture();
+ }
+ return false;
+ });
+ }
mPasswordEntry.setOnKeyListener(mOnKeyListener);
mPasswordEntry.setUserActivityListener(this::onUserInput);
@@ -123,7 +115,10 @@
@Override
protected void onViewDetached() {
super.onViewDetached();
- mView.removeMotionEventListener(mGlobalTouchListener);
+
+ for (NumPadKey button: mView.getButtons()) {
+ button.setOnTouchListener(null);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index a2d7707..eaf8516 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -58,10 +58,12 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import java.util.ArrayList;
import java.util.List;
public class KeyguardSecurityContainer extends FrameLayout {
@@ -97,6 +99,7 @@
private final ViewConfiguration mViewConfiguration;
private final SpringAnimation mSpringAnimation;
private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+ private final List<Gefingerpoken> mMotionEventListeners = new ArrayList<>();
private float mLastTouchY = -1;
private int mActivePointerId = -1;
@@ -388,6 +391,10 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ boolean result = mMotionEventListeners.stream().anyMatch(
+ listener -> listener.onInterceptTouchEvent(event))
+ || super.onInterceptTouchEvent(event);
+
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
int pointerIndex = event.getActionIndex();
@@ -418,12 +425,17 @@
mIsDragging = false;
break;
}
- return false;
+ return result;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
+
+ boolean result = mMotionEventListeners.stream()
+ .anyMatch(listener -> listener.onTouchEvent(event))
+ || super.onTouchEvent(event);
+
switch (action) {
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
@@ -469,6 +481,14 @@
return true;
}
+ void addMotionEventListener(Gefingerpoken listener) {
+ mMotionEventListeners.add(listener);
+ }
+
+ void removeMotionEventListener(Gefingerpoken listener) {
+ mMotionEventListeners.remove(listener);
+ }
+
private void handleTap(MotionEvent event) {
// If we're using a fullscreen security mode, skip
if (!mOneHandedMode) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index fdab8db..7eac903 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -33,6 +33,7 @@
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
+import android.view.MotionEvent;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -46,6 +47,8 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.utils.ThreadUtils;
+import com.android.systemui.Gefingerpoken;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -71,9 +74,44 @@
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
private final SecurityCallback mSecurityCallback;
private final ConfigurationController mConfigurationController;
+ private final KeyguardViewController mKeyguardViewController;
+ private final FalsingManager mFalsingManager;
private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
+ private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
+ private MotionEvent mTouchDown;
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // Do just a bit of our own falsing. People should only be tapping on the input, not
+ // swiping.
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ if (mTouchDown != null) {
+ mTouchDown.recycle();
+ mTouchDown = null;
+ }
+ mTouchDown = MotionEvent.obtain(ev);
+ } else if (mTouchDown != null) {
+ boolean tapResult = mFalsingManager.isFalseTap(true, 0.6);
+ if (tapResult
+ || ev.getActionMasked() == MotionEvent.ACTION_UP
+ || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
+ if (tapResult) {
+ mKeyguardViewController.reset(true);
+ }
+ mTouchDown.recycle();
+ mTouchDown = null;
+ }
+ }
+ return false;
+ }
+ };
+
private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
public void userActivity() {
if (mSecurityCallback != null) {
@@ -169,7 +207,9 @@
KeyguardStateController keyguardStateController,
SecurityCallback securityCallback,
KeyguardSecurityViewFlipperController securityViewFlipperController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ KeyguardViewController keyguardViewController,
+ FalsingManager falsingManager) {
super(view);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -182,6 +222,8 @@
mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
mKeyguardSecurityCallback);
mConfigurationController = configurationController;
+ mKeyguardViewController = keyguardViewController;
+ mFalsingManager = falsingManager;
}
@Override
@@ -192,12 +234,14 @@
@Override
protected void onViewAttached() {
mView.setSwipeListener(mSwipeListener);
+ mView.addMotionEventListener(mGlobalTouchListener);
mConfigurationController.addCallback(mConfigurationListener);
}
@Override
protected void onViewDetached() {
mConfigurationController.removeCallback(mConfigurationListener);
+ mView.removeMotionEventListener(mGlobalTouchListener);
}
/** */
@@ -479,6 +523,8 @@
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
private final ConfigurationController mConfigurationController;
+ private final KeyguardViewController mKeyguardViewController;
+ private final FalsingManager mFalsingManager;
@Inject
Factory(KeyguardSecurityContainer view,
@@ -491,7 +537,9 @@
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
KeyguardSecurityViewFlipperController securityViewFlipperController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ KeyguardViewController keyguardViewController,
+ FalsingManager falsingManager) {
mView = view;
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
mLockPatternUtils = lockPatternUtils;
@@ -502,6 +550,8 @@
mKeyguardStateController = keyguardStateController;
mSecurityViewFlipperController = securityViewFlipperController;
mConfigurationController = configurationController;
+ mKeyguardViewController = keyguardViewController;
+ mFalsingManager = falsingManager;
}
public KeyguardSecurityContainerController create(
@@ -510,7 +560,7 @@
mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
- mConfigurationController);
+ mConfigurationController, mKeyguardViewController, mFalsingManager);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index cdbbfe6..b2bf2e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -78,8 +78,8 @@
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager,
- FalsingCollector falsingCollector, boolean isNewLayoutEnabled) {
+ TelephonyManager telephonyManager, FalsingCollector falsingCollector,
+ boolean isNewLayoutEnabled) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
falsingCollector);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index 8fff342..620db48 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -85,8 +85,8 @@
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager,
- FalsingCollector falsingCollector, boolean isNewLayoutEnabled) {
+ TelephonyManager telephonyManager, FalsingCollector falsingCollector,
+ boolean isNewLayoutEnabled) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
falsingCollector);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index 43ecf67..2036150 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -16,57 +16,63 @@
package com.android.systemui.biometrics;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.FrameLayout;
-import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.statusbar.phone.StatusBar;
-
/**
* Base class for views containing UDFPS animations. Note that this is a FrameLayout so that we
- * can support multiple child views drawing on the same region around the sensor location.
+ * can support multiple child views drawing in the same region around the sensor location.
+ *
+ * - hides animation view when pausing auth
+ * - sends illumination events to fingerprint drawable
+ * - sends sensor rect updates to fingerprint drawable
+ * - optionally can override dozeTimeTick to adjust views for burn-in mitigation
*/
-public abstract class UdfpsAnimationView extends FrameLayout implements DozeReceiver,
- StatusBar.ExpansionChangedListener {
+abstract class UdfpsAnimationView extends FrameLayout {
- private static final String TAG = "UdfpsAnimationView";
-
- @Nullable protected abstract UdfpsAnimation getUdfpsAnimation();
-
- @NonNull private UdfpsView mParent;
- @NonNull private RectF mSensorRect;
private int mAlpha;
+ private boolean mPauseAuth;
public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
- mSensorRect = new RectF();
- setWillNotDraw(false);
}
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
+ /**
+ * Fingerprint drawable
+ */
+ abstract UdfpsDrawable getDrawable();
- if (getUdfpsAnimation() != null) {
- final int alpha = mParent.shouldPauseAuth() ? mAlpha : 255;
- getUdfpsAnimation().setAlpha(alpha);
- getUdfpsAnimation().draw(canvas);
- }
+ void onSensorRectUpdated(RectF bounds) {
+ getDrawable().onSensorRectUpdated(bounds);
}
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
+ void onIlluminationStarting() {
+ getDrawable().setIlluminationShowing(true);
+ getDrawable().invalidateSelf();
+ }
- if (getUdfpsAnimation() != null) {
- getUdfpsAnimation().onDestroy();
+ void onIlluminationStopped() {
+ getDrawable().setIlluminationShowing(false);
+ getDrawable().invalidateSelf();
+ }
+
+ /**
+ * @return true if changed
+ */
+ boolean setPauseAuth(boolean pauseAuth) {
+ if (pauseAuth != mPauseAuth) {
+ mPauseAuth = pauseAuth;
+ updateAlpha();
+ return true;
}
+ return false;
+ }
+
+ private void updateAlpha() {
+ getDrawable().setAlpha(mPauseAuth ? mAlpha : 255);
}
private int expansionToAlpha(float expansion) {
@@ -81,76 +87,15 @@
return (int) ((1 - percent) * 255);
}
- void onIlluminationStarting() {
- if (getUdfpsAnimation() == null) {
- return;
- }
-
- getUdfpsAnimation().setIlluminationShowing(true);
- postInvalidate();
- }
-
- void onIlluminationStopped() {
- if (getUdfpsAnimation() == null) {
- return;
- }
-
- getUdfpsAnimation().setIlluminationShowing(false);
- postInvalidate();
- }
-
- void setParent(@NonNull UdfpsView parent) {
- mParent = parent;
- }
-
- void onSensorRectUpdated(@NonNull RectF sensorRect) {
- mSensorRect = sensorRect;
- if (getUdfpsAnimation() != null) {
- getUdfpsAnimation().onSensorRectUpdated(mSensorRect);
- }
- }
-
- void updateColor() {
- if (getUdfpsAnimation() != null) {
- getUdfpsAnimation().updateColor();
- }
- postInvalidate();
- }
-
- @Override
- public void dozeTimeTick() {
- if (getUdfpsAnimation() instanceof DozeReceiver) {
- ((DozeReceiver) getUdfpsAnimation()).dozeTimeTick();
- }
- }
-
- @Override
public void onExpansionChanged(float expansion, boolean expanded) {
mAlpha = expansionToAlpha(expansion);
- postInvalidate();
- }
-
- public int getPaddingX() {
- if (getUdfpsAnimation() == null) {
- return 0;
- }
- return getUdfpsAnimation().getPaddingX();
- }
-
- public int getPaddingY() {
- if (getUdfpsAnimation() == null) {
- return 0;
- }
- return getUdfpsAnimation().getPaddingY();
+ updateAlpha();
}
/**
- * @return the amount of translation needed if the view currently requires the user to touch
- * somewhere other than the exact center of the sensor. For example, this can happen
- * during guided enrollment.
+ * @return true if handled
*/
- @NonNull
- PointF getTouchTranslation() {
- return new PointF(0, 0);
+ boolean dozeTimeTick() {
+ return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
new file mode 100644
index 0000000..b6d80ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+
+import android.annotation.NonNull;
+import android.graphics.PointF;
+import android.graphics.RectF;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.util.ViewController;
+
+/**
+ * Handles:
+ * 1. registering for listeners when its view is attached and unregistering on view detached
+ * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide
+ * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth)
+ * 3. sending events to its view including:
+ * - illumination events
+ * - sensor position changes
+ * - doze time event
+ */
+abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
+ extends ViewController<T> {
+ @NonNull final StatusBarStateController mStatusBarStateController;
+ @NonNull final StatusBar mStatusBar;
+
+ private boolean mNotificationShadeExpanded;
+ private int mStatusBarState;
+
+ protected UdfpsAnimationViewController(
+ T view,
+ StatusBarStateController statusBarStateController,
+ StatusBar statusBar) {
+ super(view);
+ mStatusBarStateController = statusBarStateController;
+ mStatusBar = statusBar;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mStatusBarStateController.addCallback(mStateListener);
+ mStateListener.onStateChanged(mStatusBarStateController.getState());
+ mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mStatusBarStateController.removeCallback(mStateListener);
+ mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener);
+ }
+
+ /**
+ * Returns true if the fingerprint manager is running but we want to temporarily pause
+ * authentication.
+ */
+ boolean shouldPauseAuth() {
+ return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD)
+ || mStatusBarState == SHADE_LOCKED
+ || mStatusBarState == FULLSCREEN_USER_SWITCHER;
+ }
+
+ /**
+ * Send pause auth update to our view.
+ */
+ void updatePauseAuth() {
+ if (mView.setPauseAuth(shouldPauseAuth())) {
+ mView.postInvalidate();
+ }
+ }
+
+ /**
+ * Send sensor position change to our view. This rect contains paddingX and paddingY.
+ */
+ void onSensorRectUpdated(RectF sensorRect) {
+ mView.onSensorRectUpdated(sensorRect);
+ }
+
+ /**
+ * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
+ */
+ void dozeTimeTick() {
+ if (mView.dozeTimeTick()) {
+ mView.postInvalidate();
+ }
+ }
+
+ /**
+ * @return the amount of translation needed if the view currently requires the user to touch
+ * somewhere other than the exact center of the sensor. For example, this can happen
+ * during guided enrollment.
+ */
+ PointF getTouchTranslation() {
+ return new PointF(0, 0);
+ }
+
+ /**
+ * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
+ * window to draw within.
+ * @return
+ */
+ int getPaddingX() {
+ return 0;
+ }
+
+ /**
+ * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
+ * window to draw within.
+ */
+ int getPaddingY() {
+ return 0;
+ }
+
+ /**
+ * Udfps has started illuminating and the fingerprint manager is working on authenticating.
+ */
+ void onIlluminationStarting() {
+ mView.onIlluminationStarting();
+ mView.postInvalidate();
+ }
+
+ /**
+ * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
+ * authenticate.
+ */
+ void onIlluminationStopped() {
+ mView.onIlluminationStopped();
+ mView.postInvalidate();
+ }
+
+ private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
+ new StatusBar.ExpansionChangedListener() {
+ @Override
+ public void onExpansionChanged(float expansion, boolean expanded) {
+ mNotificationShadeExpanded = expanded;
+ mView.onExpansionChanged(expansion, expanded);
+ updatePauseAuth();
+ }
+ };
+
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mStatusBarState = newState;
+ updatePauseAuth();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
deleted file mode 100644
index 543df33..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.PointF;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-
-import com.android.systemui.R;
-
-/**
- * Class that coordinates non-HBM animations during enrollment.
- */
-public class UdfpsAnimationViewEnroll extends UdfpsAnimationView
- implements UdfpsEnrollHelper.Listener {
-
- private static final String TAG = "UdfpsAnimationViewEnroll";
-
- @NonNull private UdfpsAnimationEnroll mUdfpsAnimation;
- @NonNull private UdfpsProgressBar mProgressBar;
- @Nullable private UdfpsEnrollHelper mEnrollHelper;
-
- @NonNull
- @Override
- protected UdfpsAnimation getUdfpsAnimation() {
- return mUdfpsAnimation;
- }
-
- public UdfpsAnimationViewEnroll(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- mUdfpsAnimation = new UdfpsAnimationEnroll(context);
- }
-
- public void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
- mEnrollHelper = helper;
- mUdfpsAnimation.setEnrollHelper(helper);
- }
-
- @Override
- protected void onFinishInflate() {
- mProgressBar = findViewById(R.id.progress_bar);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if (mEnrollHelper == null) {
- Log.e(TAG, "Enroll helper is null");
- return;
- }
-
- if (mEnrollHelper.shouldShowProgressBar()) {
- mProgressBar.setVisibility(View.VISIBLE);
-
- // Only need enrollment updates if the progress bar is showing :)
- mEnrollHelper.setListener(this);
- }
- }
-
- @Override
- public void onEnrollmentProgress(int remaining, int totalSteps) {
- final int interpolatedProgress = mProgressBar.getMax()
- * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1);
-
- mProgressBar.setProgress(interpolatedProgress, true);
- }
-
- @NonNull
- @Override
- PointF getTouchTranslation() {
- if (!mEnrollHelper.isCenterEnrollmentComplete()) {
- return new PointF(0, 0);
- } else {
- return mEnrollHelper.getNextGuidedEnrollmentPoint();
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
deleted file mode 100644
index 3d2f5a0..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewFpmOther.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import androidx.annotation.Nullable;
-
-/**
- * Class that coordinates non-HBM animations during other usage of FingerprintManager (not
- * including Keyguard).
- */
-public class UdfpsAnimationViewFpmOther extends UdfpsAnimationView {
-
- private final UdfpsAnimationFpmOther mAnimation;
-
- public UdfpsAnimationViewFpmOther(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- mAnimation = new UdfpsAnimationFpmOther(context);
- }
-
- @Nullable
- @Override
- protected UdfpsAnimation getUdfpsAnimation() {
- return mAnimation;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
deleted file mode 100644
index 7d0b3e5..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewKeyguard.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-
-/**
- * Class that coordinates non-HBM animations during keyguard authentication.
- */
-public class UdfpsAnimationViewKeyguard extends UdfpsAnimationView {
- @Nullable private UdfpsAnimationKeyguard mAnimation;
-
- public UdfpsAnimationViewKeyguard(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- void setStatusBarStateController(@NonNull StatusBarStateController statusBarStateController) {
- if (mAnimation == null) {
- mAnimation = new UdfpsAnimationKeyguard(getContext(), statusBarStateController);
- mAnimation.setAnimationView(this);
- }
- }
-
- @Nullable
- @Override
- protected UdfpsAnimation getUdfpsAnimation() {
- return mAnimation;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
index 515b442..70be907 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
@@ -24,19 +24,22 @@
/**
* Class that coordinates non-HBM animations during BiometricPrompt.
*
+ * Currently doesn't draw anything.
+ *
* Note that {@link AuthBiometricUdfpsView} also shows UDFPS animations. At some point we should
- * de-dupe this if necessary. This will probably happen once the top-level TODO in UdfpsController
- * is completed (inflate operation-specific views, instead of inflating generic udfps_view and
- * adding operation-specific animations to it).
+ * de-dupe this if necessary.
*/
-public class UdfpsAnimationViewBp extends UdfpsAnimationView {
- public UdfpsAnimationViewBp(Context context, @Nullable AttributeSet attrs) {
+public class UdfpsBpView extends UdfpsAnimationView {
+ private UdfpsFpDrawable mFingerprintDrawable;
+
+ public UdfpsBpView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
+ // Drawable isn't ever added to the view, so we don't currently show anything
+ mFingerprintDrawable = new UdfpsFpDrawable(mContext);
}
- @Nullable
@Override
- protected UdfpsAnimation getUdfpsAnimation() {
- return null;
+ UdfpsDrawable getDrawable() {
+ return mFingerprintDrawable;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
new file mode 100644
index 0000000..b712c65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations for biometric prompt.
+ */
+class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> {
+ protected UdfpsBpViewController(
+ UdfpsBpView view,
+ StatusBarStateController statusBarStateController,
+ StatusBar statusBar) {
+ super(view, statusBarStateController, statusBar);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 4b6a8f6..94aeb73 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -31,9 +31,9 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
-import android.os.SystemClock;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -195,17 +195,6 @@
}
}
- @VisibleForTesting final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
- (expansion, expanded) -> mView.onExpansionChanged(expansion, expanded);
-
- @VisibleForTesting final StatusBarStateController.StateListener mStatusBarStateListener =
- new StatusBarStateController.StateListener() {
- @Override
- public void onStateChanged(int newState) {
- mView.onStateChanged(newState);
- }
- };
-
private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
final float vx = tracker.getXVelocity(pointerId);
final float vy = tracker.getYVelocity(pointerId);
@@ -360,10 +349,9 @@
@Override
public void dozeTimeTick() {
- if (mView == null) {
- return;
+ if (mView != null) {
+ mView.dozeTimeTick();
}
- mView.dozeTimeTick();
}
/**
@@ -387,7 +375,8 @@
}
}
- private WindowManager.LayoutParams computeLayoutParams(@Nullable UdfpsAnimationView animation) {
+ private WindowManager.LayoutParams computeLayoutParams(
+ @Nullable UdfpsAnimationViewController animation) {
final int paddingX = animation != null ? animation.getPaddingX() : 0;
final int paddingY = animation != null ? animation.getPaddingY() : 0;
@@ -438,20 +427,13 @@
mFgExecutor.execute(() -> {
if (mView == null) {
try {
- Log.v(TAG, "showUdfpsOverlay | adding window");
- // TODO: Eventually we should refactor the code to inflate an
- // operation-specific view here, instead of inflating a generic udfps_view
- // and adding operation-specific animations to it.
+ Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);
mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
mView.setSensorProperties(mSensorProps);
mView.setHbmCallback(this);
-
- final UdfpsAnimationView animation = getUdfpsAnimationViewForReason(reason);
- mView.setAnimationView(animation);
-
- mStatusBar.addExpansionChangedListener(mStatusBarExpansionListener);
- mStatusBarStateController.addCallback(mStatusBarStateListener);
- mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState());
+ UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
+ animation.init();
+ mView.setAnimationViewController(animation);
mWindowManager.addView(mView, computeLayoutParams(animation));
mView.setOnTouchListener(mOnTouchListener);
@@ -464,40 +446,46 @@
});
}
- @NonNull
- private UdfpsAnimationView getUdfpsAnimationViewForReason(int reason) {
- Log.d(TAG, "getUdfpsAnimationForReason: " + reason);
-
- final LayoutInflater inflater = LayoutInflater.from(mContext);
-
+ private UdfpsAnimationViewController inflateUdfpsAnimation(int reason) {
switch (reason) {
case IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR:
- case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: {
- final UdfpsAnimationViewEnroll view = (UdfpsAnimationViewEnroll)
- inflater.inflate(R.layout.udfps_animation_view_enroll, null, false);
- view.setEnrollHelper(mServerRequest.mEnrollHelper);
- return view;
- }
-
- case IUdfpsOverlayController.REASON_AUTH_BP: {
- final UdfpsAnimationViewBp view = (UdfpsAnimationViewBp)
- inflater.inflate(R.layout.udfps_animation_view_bp, null, false);
- return view;
- }
-
- case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: {
- final UdfpsAnimationViewKeyguard view = (UdfpsAnimationViewKeyguard)
- inflater.inflate(R.layout.udfps_animation_view_keyguard, null, false);
- view.setStatusBarStateController(mStatusBarStateController);
- return view;
- }
-
- case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: {
- final UdfpsAnimationViewFpmOther view = (UdfpsAnimationViewFpmOther)
- inflater.inflate(R.layout.udfps_animation_view_fpm_other, null, false);
- return view;
- }
-
+ case IUdfpsOverlayController.REASON_ENROLL_ENROLLING:
+ UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate(
+ R.layout.udfps_enroll_view, null);
+ mView.addView(enrollView);
+ return new UdfpsEnrollViewController(
+ enrollView,
+ mServerRequest.mEnrollHelper,
+ mStatusBarStateController,
+ mStatusBar
+ );
+ case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD:
+ UdfpsKeyguardView keyguardView = (UdfpsKeyguardView)
+ mInflater.inflate(R.layout.udfps_keyguard_view, null);
+ mView.addView(keyguardView);
+ return new UdfpsKeyguardViewController(
+ keyguardView,
+ mStatusBarStateController,
+ mStatusBar
+ );
+ case IUdfpsOverlayController.REASON_AUTH_BP:
+ // note: empty controller, currently shows no visual affordance
+ UdfpsBpView bpView = (UdfpsBpView) mInflater.inflate(R.layout.udfps_bp_view, null);
+ mView.addView(bpView);
+ return new UdfpsBpViewController(
+ bpView,
+ mStatusBarStateController,
+ mStatusBar
+ );
+ case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER:
+ UdfpsFpmOtherView authOtherView = (UdfpsFpmOtherView)
+ mInflater.inflate(R.layout.udfps_fpm_other_view, null);
+ mView.addView(authOtherView);
+ return new UdfpsFpmOtherViewController(
+ authOtherView,
+ mStatusBarStateController,
+ mStatusBar
+ );
default:
Log.d(TAG, "Animation for reason " + reason + " not supported yet");
return null;
@@ -510,11 +498,9 @@
Log.v(TAG, "hideUdfpsOverlay | removing window");
// Reset the controller back to its starting state.
onFingerUp();
-
- mStatusBar.removeExpansionChangedListener(mStatusBarExpansionListener);
- mStatusBarStateController.removeCallback(mStatusBarStateListener);
-
mWindowManager.removeView(mView);
+ mView.setOnTouchListener(null);
+ mView.setAnimationViewController(null);
mView = null;
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
index a51b6fd1..13d31cb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
@@ -17,10 +17,10 @@
package com.android.systemui.biometrics;
import android.content.Context;
+import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
-import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -28,24 +28,24 @@
import com.android.systemui.R;
/**
- * Abstract base class for animations that should be drawn when the finger is not touching the
+ * Abstract base class for drawable displayed when the finger is not touching the
* sensor area.
*/
-public abstract class UdfpsAnimation extends Drawable {
- protected abstract void updateColor();
- protected abstract void onDestroy();
-
+public abstract class UdfpsDrawable extends Drawable {
@NonNull protected final Context mContext;
@NonNull protected final Drawable mFingerprintDrawable;
- @Nullable private View mView;
private boolean mIlluminationShowing;
- public UdfpsAnimation(@NonNull Context context) {
+ int mAlpha = 255; // 0 - 255
+ public UdfpsDrawable(@NonNull Context context) {
mContext = context;
mFingerprintDrawable = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
mFingerprintDrawable.mutate();
}
+ /**
+ * @param sensorRect the rect coordinates for the sensor area
+ */
public void onSensorRectUpdated(@NonNull RectF sensorRect) {
final int margin = (int) sensorRect.height() / 8;
@@ -56,17 +56,17 @@
updateFingerprintIconBounds(bounds);
}
+ /**
+ * Bounds for the fingerprint icon
+ */
protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
mFingerprintDrawable.setBounds(bounds);
}
@Override
public void setAlpha(int alpha) {
- mFingerprintDrawable.setAlpha(alpha);
- }
-
- public void setAnimationView(UdfpsAnimationView view) {
- mView = view;
+ mAlpha = alpha;
+ mFingerprintDrawable.setAlpha(mAlpha);
}
boolean isIlluminationShowing() {
@@ -77,23 +77,12 @@
mIlluminationShowing = showing;
}
- /**
- * @return The amount of padding that's needed on each side of the sensor, in pixels.
- */
- public int getPaddingX() {
- return 0;
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
- /**
- * @return The amount of padding that's needed on each side of the sensor, in pixels.
- */
- public int getPaddingY() {
+ @Override
+ public int getOpacity() {
return 0;
}
-
- protected void postInvalidateView() {
- if (mView != null) {
- mView.postInvalidate();
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
similarity index 81%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index 015a598..d80e085 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -20,7 +20,6 @@
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -33,23 +32,23 @@
import com.android.systemui.R;
/**
- * UDFPS animations that should be shown when enrolling.
+ * UDFPS fingerprint drawable that is shown when enrolling
*/
-public class UdfpsAnimationEnroll extends UdfpsAnimation {
+public class UdfpsEnrollDrawable extends UdfpsDrawable {
private static final String TAG = "UdfpsAnimationEnroll";
private static final float SHADOW_RADIUS = 5.f;
- private static final float PROGRESS_BAR_RADIUS = 140.f;
+ static final float PROGRESS_BAR_RADIUS = 140.f;
@NonNull private final Drawable mMovingTargetFpIcon;
@NonNull private final Paint mSensorPaint;
@NonNull private final Paint mBlueFill;
- @NonNull private final Paint mBlueStroke;;
+ @NonNull private final Paint mBlueStroke;
@Nullable private RectF mSensorRect;
@Nullable private UdfpsEnrollHelper mEnrollHelper;
- UdfpsAnimationEnroll(@NonNull Context context) {
+ UdfpsEnrollDrawable(@NonNull Context context) {
super(context);
mSensorPaint = new Paint(0 /* flags */);
@@ -72,6 +71,8 @@
mMovingTargetFpIcon = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
mMovingTargetFpIcon.setTint(Color.WHITE);
mMovingTargetFpIcon.mutate();
+
+ mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
}
void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
@@ -79,16 +80,6 @@
}
@Override
- protected void updateColor() {
- mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
- }
-
- @Override
- protected void onDestroy() {
-
- }
-
- @Override
public void onSensorRectUpdated(@NonNull RectF sensorRect) {
super.onSensorRectUpdated(sensorRect);
mSensorRect = sensorRect;
@@ -98,6 +89,7 @@
protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
super.updateFingerprintIconBounds(bounds);
mMovingTargetFpIcon.setBounds(bounds);
+ invalidateSelf();
}
@Override
@@ -117,7 +109,7 @@
// Draw moving target
if (mEnrollHelper.isCenterEnrollmentComplete()) {
- mFingerprintDrawable.setAlpha(64);
+ mFingerprintDrawable.setAlpha(mAlpha == 255 ? 64 : mAlpha);
canvas.save();
final PointF point = mEnrollHelper.getNextGuidedEnrollmentPoint();
@@ -130,33 +122,16 @@
mMovingTargetFpIcon.draw(canvas);
canvas.restore();
} else {
- mFingerprintDrawable.setAlpha(255);
+ mFingerprintDrawable.setAlpha(mAlpha);
}
}
@Override
- public int getPaddingX() {
- return (int) Math.ceil(PROGRESS_BAR_RADIUS);
- }
-
- @Override
- public int getPaddingY() {
- return (int) Math.ceil(PROGRESS_BAR_RADIUS);
- }
-
- @Override
public void setAlpha(int alpha) {
super.setAlpha(alpha);
mSensorPaint.setAlpha(alpha);
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
- }
-
- @Override
- public int getOpacity() {
- return 0;
+ mBlueFill.setAlpha(alpha);
+ mBlueStroke.setAlpha(alpha);
+ invalidateSelf();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 667b7a7..98a703f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -21,6 +21,9 @@
import android.content.Context;
import android.graphics.PointF;
import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.Build;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.TypedValue;
import java.util.ArrayList;
@@ -32,6 +35,10 @@
public class UdfpsEnrollHelper {
private static final String TAG = "UdfpsEnrollHelper";
+ private static final String SCALE_OVERRIDE =
+ "com.android.systemui.biometrics.UdfpsEnrollHelper.scale";
+ private static final float SCALE = 0.5f;
+
// Enroll with two center touches before going to guided enrollment
private static final int NUM_CENTER_TOUCHES = 2;
@@ -39,9 +46,10 @@
void onEnrollmentProgress(int remaining, int totalSteps);
}
+ @NonNull private final Context mContext;
// IUdfpsOverlayController reason
private final int mEnrollReason;
- private final List<PointF> mGuidedEnrollmentPoints;
+ @NonNull private final List<PointF> mGuidedEnrollmentPoints;
private int mTotalSteps = -1;
private int mRemainingSteps = -1;
@@ -53,6 +61,7 @@
@Nullable Listener mListener;
public UdfpsEnrollHelper(@NonNull Context context, int reason) {
+ mContext = context;
mEnrollReason = reason;
mGuidedEnrollmentPoints = new ArrayList<>();
@@ -100,13 +109,13 @@
}
- void setListener(@NonNull Listener listener) {
+ void setListener(Listener listener) {
mListener = listener;
// Only notify during setListener if enrollment is already in progress, so the progress
// bar can be updated. If enrollment has not started yet, the progress bar will be empty
// anyway.
- if (mTotalSteps != -1) {
+ if (mListener != null && mTotalSteps != -1) {
mListener.onEnrollmentProgress(mRemainingSteps, mTotalSteps);
}
}
@@ -121,9 +130,15 @@
@NonNull
PointF getNextGuidedEnrollmentPoint() {
+ float scale = SCALE;
+ if (Build.IS_ENG || Build.IS_USERDEBUG) {
+ scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
+ SCALE_OVERRIDE, SCALE,
+ UserHandle.USER_CURRENT);
+ }
final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES;
final PointF originalPoint = mGuidedEnrollmentPoints
.get(index % mGuidedEnrollmentPoints.size());
- return new PointF(originalPoint.x * 0.5f, originalPoint.y * 0.5f);
+ return new PointF(originalPoint.x * scale, originalPoint.y * scale);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
new file mode 100644
index 0000000..7985d95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * View corresponding with udfps_enroll_view.xml
+ */
+public class UdfpsEnrollView extends UdfpsAnimationView {
+ private final UdfpsEnrollDrawable mFingerprintDrawable;
+ private ImageView mFingerprintView;
+
+ public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mFingerprintDrawable = new UdfpsEnrollDrawable(mContext);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mFingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view);
+ mFingerprintView.setImageDrawable(mFingerprintDrawable);
+ }
+
+ @Override
+ public UdfpsDrawable getDrawable() {
+ return mFingerprintDrawable;
+ }
+
+ void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
+ mFingerprintDrawable.setEnrollHelper(enrollHelper);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
new file mode 100644
index 0000000..da8d712
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import android.annotation.NonNull;
+import android.graphics.PointF;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations during enrollment.
+ */
+public class UdfpsEnrollViewController extends UdfpsAnimationViewController<UdfpsEnrollView> {
+ @NonNull private final UdfpsProgressBar mProgressBar;
+ @NonNull private final UdfpsEnrollHelper mEnrollHelper;
+
+ protected UdfpsEnrollViewController(
+ UdfpsEnrollView view,
+ @NonNull UdfpsEnrollHelper enrollHelper,
+ StatusBarStateController statusBarStateController,
+ StatusBar statusBar) {
+ super(view, statusBarStateController, statusBar);
+ mEnrollHelper = enrollHelper;
+ mProgressBar = mView.findViewById(R.id.progress_bar);
+ mView.setEnrollHelper(mEnrollHelper);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ super.onViewAttached();
+ if (mEnrollHelper.shouldShowProgressBar()) {
+ mProgressBar.setVisibility(View.VISIBLE);
+
+ // Only need enrollment updates if the progress bar is showing :)
+ mEnrollHelper.setListener(mEnrollHelperListener);
+ }
+ }
+
+ @Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mEnrollHelper.setListener(null);
+ }
+
+ @NonNull
+ @Override
+ public PointF getTouchTranslation() {
+ if (!mEnrollHelper.isCenterEnrollmentComplete()) {
+ return new PointF(0, 0);
+ } else {
+ return mEnrollHelper.getNextGuidedEnrollmentPoint();
+ }
+ }
+
+ @Override
+ public int getPaddingX() {
+ return (int) Math.ceil(UdfpsEnrollDrawable.PROGRESS_BAR_RADIUS);
+ }
+
+ @Override
+ public int getPaddingY() {
+ return (int) Math.ceil(UdfpsEnrollDrawable.PROGRESS_BAR_RADIUS);
+ }
+
+ private final UdfpsEnrollHelper.Listener mEnrollHelperListener =
+ new UdfpsEnrollHelper.Listener() {
+ @Override
+ public void onEnrollmentProgress(int remaining, int totalSteps) {
+ final int interpolatedProgress = mProgressBar.getMax()
+ * Math.max(0, totalSteps + 1 - remaining) / (totalSteps + 1);
+
+ mProgressBar.setProgress(interpolatedProgress, true);
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
index ef7a340..09b6fab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationFpmOther.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
@@ -18,32 +18,19 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.ColorFilter;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
/**
- * UDFPS animations that should be shown when authenticating via FingerprintManager, excluding
- * keyguard.
+ * Draws udfps fingerprint if sensor isn't illuminating.
*/
-public class UdfpsAnimationFpmOther extends UdfpsAnimation {
+public class UdfpsFpDrawable extends UdfpsDrawable {
- UdfpsAnimationFpmOther(@NonNull Context context) {
+ UdfpsFpDrawable(@NonNull Context context) {
super(context);
}
@Override
- protected void updateColor() {
-
- }
-
- @Override
- protected void onDestroy() {
-
- }
-
- @Override
public void draw(@NonNull Canvas canvas) {
if (isIlluminationShowing()) {
return;
@@ -51,14 +38,4 @@
mFingerprintDrawable.draw(canvas);
}
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
- }
-
- @Override
- public int getOpacity() {
- return 0;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
new file mode 100644
index 0000000..85f1606
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * View corresponding with udfps_fpm_other_view.xml
+ */
+public class UdfpsFpmOtherView extends UdfpsAnimationView {
+ private final UdfpsFpDrawable mFingerprintDrawable;
+ private ImageView mFingerprintView;
+
+ public UdfpsFpmOtherView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mFingerprintDrawable = new UdfpsFpDrawable(context);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mFingerprintView = findViewById(R.id.udfps_fpm_other_fp_view);
+ mFingerprintView.setImageDrawable(mFingerprintDrawable);
+ }
+
+ @Override
+ UdfpsDrawable getDrawable() {
+ return mFingerprintDrawable;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
new file mode 100644
index 0000000..587501b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
+ * states.
+ *
+ * Currently only shows the fp drawable.
+ */
+class UdfpsFpmOtherViewController extends UdfpsAnimationViewController<UdfpsFpmOtherView> {
+ protected UdfpsFpmOtherViewController(
+ UdfpsFpmOtherView view,
+ StatusBarStateController statusBarStateController,
+ StatusBar statusBar) {
+ super(view, statusBarStateController, statusBar);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
index 5f268cf..b0c5da0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationKeyguard.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardDrawable.java
@@ -21,28 +21,25 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.ColorFilter;
import android.util.MathUtils;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.internal.graphics.ColorUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
/**
* UDFPS animations that should be shown when authenticating on keyguard.
*/
-public class UdfpsAnimationKeyguard extends UdfpsAnimation implements DozeReceiver,
- StatusBarStateController.StateListener {
+public class UdfpsKeyguardDrawable extends UdfpsDrawable implements DozeReceiver {
private static final String TAG = "UdfpsAnimationKeyguard";
+ private final int mLockScreenColor;
+ private final int mAmbientDisplayColor;
@NonNull private final Context mContext;
- @NonNull private final StatusBarStateController mStatusBarStateController;
private final int mMaxBurnInOffsetX;
private final int mMaxBurnInOffsetY;
@@ -51,18 +48,19 @@
private float mBurnInOffsetX;
private float mBurnInOffsetY;
- UdfpsAnimationKeyguard(@NonNull Context context,
- @NonNull StatusBarStateController statusBarStateController) {
+ UdfpsKeyguardDrawable(@NonNull Context context) {
super(context);
mContext = context;
- mStatusBarStateController = statusBarStateController;
+ // TODO: move burn-in to view
mMaxBurnInOffsetX = context.getResources()
.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
mMaxBurnInOffsetY = context.getResources()
.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
- statusBarStateController.addCallback(this);
+ mLockScreenColor = Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor);
+ mAmbientDisplayColor = Color.WHITE;
+ updateAodPositionAndColor();
}
private void updateAodPositionAndColor() {
@@ -74,8 +72,10 @@
getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
- mMaxBurnInOffsetY,
mInterpolatedDarkAmount);
- updateColor();
- postInvalidateView();
+
+ mFingerprintDrawable.setTint(ColorUtils.blendARGB(mLockScreenColor,
+ mAmbientDisplayColor, mInterpolatedDarkAmount));
+ invalidateSelf();
}
@Override
@@ -84,44 +84,15 @@
}
@Override
- public void onDozeAmountChanged(float linear, float eased) {
- mInterpolatedDarkAmount = eased;
- updateAodPositionAndColor();
- }
-
- @Override
public void draw(@NonNull Canvas canvas) {
if (isIlluminationShowing()) {
return;
}
-
- canvas.save();
- canvas.translate(mBurnInOffsetX, mBurnInOffsetY);
mFingerprintDrawable.draw(canvas);
- canvas.restore();
}
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
-
- }
-
- @Override
- public int getOpacity() {
- return 0;
- }
-
- @Override
- protected void updateColor() {
- final int lockScreenIconColor = Utils.getColorAttrDefaultColor(mContext,
- R.attr.wallpaperTextColor);
- final int ambientDisplayIconColor = Color.WHITE;
- mFingerprintDrawable.setTint(ColorUtils.blendARGB(lockScreenIconColor,
- ambientDisplayIconColor, mInterpolatedDarkAmount));
- }
-
- @Override
- protected void onDestroy() {
- mStatusBarStateController.removeCallback(this);
+ void onDozeAmountChanged(float linear, float eased) {
+ mInterpolatedDarkAmount = eased;
+ updateAodPositionAndColor();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
new file mode 100644
index 0000000..6a93560
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * View corresponding with udfps_keyguard_view.xml
+ */
+public class UdfpsKeyguardView extends UdfpsAnimationView {
+ private final UdfpsKeyguardDrawable mFingerprintDrawable;
+ private ImageView mFingerprintView;
+
+ public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mFingerprintDrawable = new UdfpsKeyguardDrawable(mContext);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mFingerprintView = findViewById(R.id.udfps_keyguard_animation_fp_view);
+ mFingerprintView.setImageDrawable(mFingerprintDrawable);
+ }
+
+ @Override
+ public UdfpsDrawable getDrawable() {
+ return mFingerprintDrawable;
+ }
+
+ @Override
+ public boolean dozeTimeTick() {
+ // TODO: burnin
+ mFingerprintDrawable.dozeTimeTick();
+ return true;
+ }
+
+ void onDozeAmountChanged(float linear, float eased) {
+ mFingerprintDrawable.onDozeAmountChanged(linear, eased);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
new file mode 100644
index 0000000..14bb3fee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Class that coordinates non-HBM animations during keyguard authentication.
+ */
+public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
+ private boolean mForceShow;
+
+ protected UdfpsKeyguardViewController(
+ UdfpsKeyguardView view,
+ StatusBarStateController statusBarStateController,
+ StatusBar statusBar) {
+ super(view, statusBarStateController, statusBar);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ super.onViewAttached();
+ mStatusBarStateController.addCallback(mStateListener);
+ final float dozeAmount = mStatusBarStateController.getDozeAmount();
+ mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mStatusBarStateController.removeCallback(mStateListener);
+ }
+
+ /**
+ * Overrides non-force show logic in shouldPauseAuth to still auth.
+ */
+ private void forceShow(boolean forceShow) {
+ if (mForceShow == forceShow) {
+ return;
+ }
+
+ mForceShow = forceShow;
+ updatePauseAuth();
+ // TODO: animate show/hide background protection
+ }
+
+ /**
+ * Returns true if the fingerprint manager is running but we want to temporarily pause
+ * authentication. On the keyguard, we may want to show udfps when the shade
+ * is expanded, so this can be overridden with the forceShow method.
+ */
+ public boolean shouldPauseAuth() {
+ if (mForceShow) {
+ return false;
+ }
+ return super.shouldPauseAuth();
+ }
+
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ mView.onDozeAmountChanged(linear, eased);
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index a52bddc..42d0d84 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -16,10 +16,6 @@
package com.android.systemui.biometrics;
-import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER;
-import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -39,15 +35,12 @@
import com.android.systemui.R;
import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.StatusBar;
/**
* A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other
* animations.
*/
-public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator,
- StatusBarStateController.StateListener, StatusBar.ExpansionChangedListener {
+public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator {
private static final String TAG = "UdfpsView";
private static final int DEBUG_TEXT_SIZE_PX = 32;
@@ -56,7 +49,7 @@
@NonNull private final Paint mDebugTextPaint;
@NonNull private UdfpsSurfaceView mHbmSurfaceView;
- @Nullable private UdfpsAnimationView mAnimationView;
+ @Nullable private UdfpsAnimationViewController mAnimationViewController;
// Used to obtain the sensor location.
@NonNull private FingerprintSensorPropertiesInternal mSensorProps;
@@ -64,8 +57,6 @@
private final float mSensorTouchAreaCoefficient;
@Nullable private String mDebugMessage;
private boolean mIlluminationRequested;
- private int mStatusBarState;
- private boolean mNotificationShadeExpanded;
public UdfpsView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -108,15 +99,6 @@
mSensorProps = properties;
}
- void setAnimationView(@NonNull UdfpsAnimationView animation) {
- mAnimationView = animation;
- animation.setParent(this);
-
- // TODO: Consider using a ViewStub placeholder to maintain positioning and inflating it
- // after the animation type has been decided.
- addView(animation, 0);
- }
-
@Override
public void setHbmCallback(@Nullable HbmCallback callback) {
mHbmSurfaceView.setHbmCallback(callback);
@@ -124,45 +106,38 @@
@Override
public void dozeTimeTick() {
- if (mAnimationView == null) {
- return;
- }
- mAnimationView.dozeTimeTick();
- }
-
- @Override
- public void onStateChanged(int newState) {
- mStatusBarState = newState;
- }
-
- @Override
- public void onExpansionChanged(float expansion, boolean expanded) {
- mNotificationShadeExpanded = expanded;
-
- if (mAnimationView != null) {
- mAnimationView.onExpansionChanged(expansion, expanded);
+ if (mAnimationViewController != null) {
+ mAnimationViewController.dozeTimeTick();
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mSensorRect.set(0 + mAnimationView.getPaddingX(),
- 0 + mAnimationView.getPaddingY(),
- 2 * mSensorProps.sensorRadius + mAnimationView.getPaddingX(),
- 2 * mSensorProps.sensorRadius + mAnimationView.getPaddingY());
+ int paddingX = mAnimationViewController == null ? 0
+ : mAnimationViewController.getPaddingX();
+ int paddingY = mAnimationViewController == null ? 0
+ : mAnimationViewController.getPaddingY();
+ mSensorRect.set(
+ paddingX,
+ paddingY,
+ 2 * mSensorProps.sensorRadius + paddingX,
+ 2 * mSensorProps.sensorRadius + paddingY);
mHbmSurfaceView.onSensorRectUpdated(new RectF(mSensorRect));
- mAnimationView.onSensorRectUpdated(new RectF(mSensorRect));
+ if (mAnimationViewController != null) {
+ mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect));
+ }
+ }
+
+ void setAnimationViewController(UdfpsAnimationViewController animationViewController) {
+ mAnimationViewController = animationViewController;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Log.v(TAG, "onAttachedToWindow");
-
- // Retrieve the colors each time, since it depends on day/night mode
- mAnimationView.updateColor();
}
@Override
@@ -188,7 +163,9 @@
boolean isWithinSensorArea(float x, float y) {
// The X and Y coordinates of the sensor's center.
- final PointF translation = mAnimationView.getTouchTranslation();
+ final PointF translation = mAnimationViewController == null
+ ? new PointF(0, 0)
+ : mAnimationViewController.getTouchTranslation();
final float cx = mSensorRect.centerX() + translation.x;
final float cy = mSensorRect.centerY() + translation.y;
// Radii along the X and Y axes.
@@ -199,18 +176,7 @@
&& x < (cx + rx * mSensorTouchAreaCoefficient)
&& y > (cy - ry * mSensorTouchAreaCoefficient)
&& y < (cy + ry * mSensorTouchAreaCoefficient)
- && !shouldPauseAuth();
- }
-
- /**
- * States where UDFPS should temporarily not be authenticating. Instead of completely stopping
- * authentication which would cause the UDFPS icons to abruptly disappear, do it here by not
- * sending onFingerDown and smoothly animating away.
- */
- boolean shouldPauseAuth() {
- return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD)
- || mStatusBarState == SHADE_LOCKED
- || mStatusBarState == FULLSCREEN_USER_SWITCHER;
+ && !mAnimationViewController.shouldPauseAuth();
}
boolean isIlluminationRequested() {
@@ -223,7 +189,9 @@
@Override
public void startIllumination(@Nullable Runnable onIlluminatedRunnable) {
mIlluminationRequested = true;
- mAnimationView.onIlluminationStarting();
+ if (mAnimationViewController != null) {
+ mAnimationViewController.onIlluminationStarting();
+ }
mHbmSurfaceView.setVisibility(View.VISIBLE);
mHbmSurfaceView.startIllumination(onIlluminatedRunnable);
}
@@ -231,7 +199,9 @@
@Override
public void stopIllumination() {
mIlluminationRequested = false;
- mAnimationView.onIlluminationStopped();
+ if (mAnimationViewController != null) {
+ mAnimationViewController.onIlluminationStopped();
+ }
mHbmSurfaceView.setVisibility(View.INVISIBLE);
mHbmSurfaceView.stopIllumination();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 6572ca9..efb7992 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -18,7 +18,6 @@
import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS;
import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS;
-import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS;
import android.net.Uri;
import android.os.Build;
@@ -29,11 +28,9 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.ThresholdSensor;
import java.io.FileDescriptor;
@@ -63,14 +60,13 @@
private static final int RECENT_INFO_LOG_SIZE = 40;
private static final int RECENT_SWIPE_LOG_SIZE = 20;
+ private static final double TAP_CONFIDENCE_THRESHOLD = 0.7;
private final FalsingDataProvider mDataProvider;
private final DockManager mDockManager;
private final SingleTapClassifier mSingleTapClassifier;
private final DoubleTapClassifier mDoubleTapClassifier;
private final HistoryTracker mHistoryTracker;
- private final DelayableExecutor mDelayableExecutor;
- private final long mDoubleTapTimeMs;
private final boolean mTestHarness;
private final MetricsLogger mMetricsLogger;
private int mIsFalseTouchCalls;
@@ -98,19 +94,7 @@
@Override
public void onGestureComplete(long completionTimeMs) {
if (mPriorResults != null) {
- // Single taps that may become double taps don't get added right away.
- if (mClassifyAsSingleTap) {
- Collection<FalsingClassifier.Result> singleTapResults = mPriorResults;
- mSingleTapHistoryCanceller = mDelayableExecutor.executeDelayed(
- () -> {
- mSingleTapHistoryCanceller = null;
- mHistoryTracker.addResults(singleTapResults, completionTimeMs);
- },
- mDoubleTapTimeMs);
- mClassifyAsSingleTap = false; // Don't treat things as single taps by default.
- } else {
- mHistoryTracker.addResults(mPriorResults, completionTimeMs);
- }
+ mHistoryTracker.addResults(mPriorResults, completionTimeMs);
mPriorResults = null;
} else {
// Gestures that were not classified get treated as a false.
@@ -123,17 +107,13 @@
};
private Collection<FalsingClassifier.Result> mPriorResults;
- private boolean mClassifyAsSingleTap;
- private Runnable mSingleTapHistoryCanceller;
@Inject
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
DockManager dockManager, MetricsLogger metricsLogger,
@Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier,
- HistoryTracker historyTracker, @Main DelayableExecutor delayableExecutor,
- @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs,
- @TestHarness boolean testHarness) {
+ HistoryTracker historyTracker, @TestHarness boolean testHarness) {
mDataProvider = falsingDataProvider;
mDockManager = dockManager;
mMetricsLogger = metricsLogger;
@@ -141,8 +121,6 @@
mSingleTapClassifier = singleTapClassifier;
mDoubleTapClassifier = doubleTapClassifier;
mHistoryTracker = historyTracker;
- mDelayableExecutor = delayableExecutor;
- mDoubleTapTimeMs = doubleTapTimeMs;
mTestHarness = testHarness;
mDataProvider.addSessionListener(mSessionListener);
@@ -158,7 +136,6 @@
public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
boolean result;
- mClassifyAsSingleTap = false;
mDataProvider.setInteractionType(interactionType);
if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) {
@@ -166,7 +143,7 @@
mClassifiers.stream().map(falsingClassifier -> {
FalsingClassifier.Result classifierResult =
falsingClassifier.classifyGesture(
- mHistoryTracker.falsePenalty(),
+ mHistoryTracker.falseBelief(),
mHistoryTracker.falseConfidence());
if (classifierResult.isFalse()) {
logInfo(String.format(
@@ -217,9 +194,7 @@
}
@Override
- public boolean isFalseTap(boolean robustCheck) {
- mClassifyAsSingleTap = true;
-
+ public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
FalsingClassifier.Result singleTapResult =
mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents());
mPriorResults = Collections.singleton(singleTapResult);
@@ -233,14 +208,24 @@
return true;
}
- // TODO(b/172655679): More heuristics to come. For now, allow touches through if face-authed
if (robustCheck) {
- boolean result = !mDataProvider.isJustUnlockedWithFace();
- mPriorResults = Collections.singleton(
- result ? FalsingClassifier.Result.falsed(0.1, "no face detected")
- : FalsingClassifier.Result.passed(1));
-
- return result;
+ if (mDataProvider.isJustUnlockedWithFace()) {
+ // Immediately pass if a face is detected.
+ mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
+ return false;
+ } else if (!isFalseDoubleTap()) {
+ // We must check double tapping before other heuristics. This is because
+ // the double tap will fail if there's only been one tap. We don't want that
+ // failure to be recorded in mPriorResults.
+ return false;
+ } else if (mHistoryTracker.falseBelief() > TAP_CONFIDENCE_THRESHOLD) {
+ mPriorResults = Collections.singleton(
+ FalsingClassifier.Result.falsed(0, "bad history"));
+ return true;
+ } else {
+ mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(0.1));
+ return false;
+ }
}
return false;
@@ -248,7 +233,6 @@
@Override
public boolean isFalseDoubleTap() {
- mClassifyAsSingleTap = false;
FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture();
mPriorResults = Collections.singleton(result);
if (result.isFalse()) {
@@ -258,12 +242,6 @@
if (reason != null) {
logInfo(reason);
}
- } else {
- // A valid double tap prevents an invalid single tap from going into history.
- if (mSingleTapHistoryCanceller != null) {
- mSingleTapHistoryCanceller.run();
- mSingleTapHistoryCanceller = null;
- }
}
return result.isFalse();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
index bbb9371..ffcdb93 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
@@ -62,7 +62,7 @@
VERTICAL_ANGLE_RANGE);
}
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
float angle = getAngle();
if (angle == Float.MAX_VALUE) { // Unknown angle
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 4cb5aa2..0f121c1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -147,7 +147,7 @@
}
@Override
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
return !getPassedFlingThreshold()
? Result.falsed(0.5, getReason()) : Result.passed(0.5);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
index f7fe14a..baa54a6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
@@ -46,14 +46,14 @@
}
@Override
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
List<MotionEvent> secondTapEvents = getRecentMotionEvents();
List<MotionEvent> firstTapEvents = getPriorMotionEvents();
StringBuilder reason = new StringBuilder();
if (firstTapEvents == null) {
- return Result.falsed(1, "Only one gesture recorded");
+ return Result.falsed(0, "Only one gesture recorded");
}
return !isDoubleTap(firstTapEvents, secondTapEvents, reason)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
index f40045b..1af5f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
@@ -124,7 +124,7 @@
* See also {@link #classifyGesture(double, double)}.
*/
Result classifyGesture() {
- return calculateFalsingResult(0, 0);
+ return calculateFalsingResult(0.5, 0);
}
/**
@@ -135,16 +135,16 @@
*
* See also {@link #classifyGesture()}.
*/
- Result classifyGesture(double historyPenalty, double historyConfidence) {
- return calculateFalsingResult(historyPenalty, historyConfidence);
+ Result classifyGesture(double historyBelief, double historyConfidence) {
+ return calculateFalsingResult(historyBelief, historyConfidence);
}
/**
* Calculate a result based on available data.
*
- * When passed a historyConfidence of 0, the history penalty should be wholly ignored.
+ * When passed a historyConfidence of 0, the history belief should be wholly ignored.
*/
- abstract Result calculateFalsingResult(double historyPenalty, double historyConfidence);
+ abstract Result calculateFalsingResult(double historyBelief, double historyConfidence);
/** */
public static void logDebug(String msg) {
@@ -164,7 +164,7 @@
/**
* A Falsing result that encapsulates the boolean result along with confidence and a reason.
*/
- static class Result {
+ public static class Result {
private final boolean mFalsed;
private final double mConfidence;
private final String mReason;
@@ -193,14 +193,14 @@
/**
* Construct a "falsed" result indicating that a gesture should be treated as accidental.
*/
- static Result falsed(double confidence, String reason) {
+ public static Result falsed(double confidence, String reason) {
return new Result(true, confidence, reason);
}
/**
* Construct a "passed" result indicating that a gesture should be allowed.
*/
- static Result passed(double confidence) {
+ public static Result passed(double confidence) {
return new Result(false, confidence, null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
index b0bbab3..bb03720 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -120,5 +120,8 @@
/** */
void cleanup();
+
+ /** */
+ void updateFalseConfidence(FalsingClassifier.Result result);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index 12a0604..939b45a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -153,4 +153,8 @@
@Override
public void cleanup() {
}
+
+ @Override
+ public void updateFalseConfidence(FalsingClassifier.Result result) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index e08b43b..e090006 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -29,6 +29,9 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.sensors.ThresholdSensor;
+import com.android.systemui.util.time.SystemClock;
+
+import java.util.Collections;
import javax.inject.Inject;
@@ -42,8 +45,10 @@
private final FalsingDataProvider mFalsingDataProvider;
private final FalsingManager mFalsingManager;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final HistoryTracker mHistoryTracker;
private final ProximitySensor mProximitySensor;
private final StatusBarStateController mStatusBarStateController;
+ private final SystemClock mSystemClock;
private int mState;
private boolean mShowingAod;
@@ -80,13 +85,16 @@
@Inject
FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- ProximitySensor proximitySensor, StatusBarStateController statusBarStateController) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, HistoryTracker historyTracker,
+ ProximitySensor proximitySensor, StatusBarStateController statusBarStateController,
+ SystemClock systemClock) {
mFalsingDataProvider = falsingDataProvider;
mFalsingManager = falsingManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mHistoryTracker = historyTracker;
mProximitySensor = proximitySensor;
mStatusBarStateController = statusBarStateController;
+ mSystemClock = systemClock;
mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
@@ -282,6 +290,11 @@
mStatusBarStateController.removeCallback(mStatusBarStateListener);
}
+ @Override
+ public void updateFalseConfidence(FalsingClassifier.Result result) {
+ mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis());
+ }
+
private void updateInteractionType(@Classifier.InteractionType int type) {
logDebug("InteractionType: " + type);
mFalsingDataProvider.setInteractionType(type);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index d4d8d06..aac27cb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -76,7 +76,7 @@
}
@Override
- public boolean isFalseTap(boolean robustCheck) {
+ public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
return robustCheck ? mIsFalseRobustTap : mIsFalseTap;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index cbec057..e9bb48c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -131,8 +131,8 @@
}
@Override
- public boolean isFalseTap(boolean robustCheck) {
- return mInternalFalsingManager.isFalseTap(robustCheck);
+ public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
+ return mInternalFalsingManager.isFalseTap(robustCheck, falsePenalty);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
index 8bd94a1..be48ec4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java
@@ -36,12 +36,17 @@
*/
@SysUISingleton
public class HistoryTracker {
- private static final double HISTORY_DECAY = 0.8f;
+ private static final long HISTORY_MAX_AGE_MS = 10000;
+ // A score is decayed discretely every DECAY_INTERVAL_MS.
private static final long DECAY_INTERVAL_MS = 100;
- // We expire items once their decay factor is below 0.001.
- private static final double MINIMUM_SCORE = 0.001;
- private static final long TOTAL_DECAY_TIME_MS =
- DECAY_INTERVAL_MS * (long) (Math.log(MINIMUM_SCORE) / Math.log(HISTORY_DECAY));
+ // We expire items once their decay factor is below 0.1.
+ private static final double MINIMUM_SCORE = 0.1;
+ // This magic number is the factor a score is reduced by every DECAY_INTERVAL_MS.
+ // Once a score is HISTORY_MAX_AGE_MS ms old, it will be reduced by being multiplied by
+ // MINIMUM_SCORE. The math below ensures that.
+ private static final double HISTORY_DECAY =
+ Math.pow(10, Math.log10(MINIMUM_SCORE) / HISTORY_MAX_AGE_MS * DECAY_INTERVAL_MS);
+
private final SystemClock mSystemClock;
DelayQueue<CombinedResult> mResults = new DelayQueue<>();
@@ -54,29 +59,36 @@
/**
* Returns how much the HistoryClassifier thinks the past events indicate pocket dialing.
*
- * A result of 0 means that all prior gestures succeeded or there is no data to
- * calculate a score with. Use {@link #falseConfidence()} to differentiate between the
- * two cases.
+ * A result close to 0.5 means that prior data is inconclusive (inconsistent, lacking
+ * confidence, or simply lacking in quantity).
*
- * A result of 1 means that all prior gestures were very obviously false. The current gesture
- * might be valid, but it should have a high-bar to be classified as such.
+ * A result close to 0 means that prior gestures indicate a success.
+ *
+ * A result close to 1 means that prior gestures were very obviously false.
+ *
+ * The current gesture might be different than what is reported by this method, but there should
+ * be a high-bar to be classified differently.
*
* See also {@link #falseConfidence()}.
*/
- double falsePenalty() {
+ double falseBelief() {
//noinspection StatementWithEmptyBody
while (mResults.poll() != null) {
// Empty out the expired results.
}
if (mResults.isEmpty()) {
- return 0;
+ return 0.5;
}
long nowMs = mSystemClock.uptimeMillis();
+ // Get our Bayes on.
return mResults.stream()
.map(result -> result.getDecayedScore(nowMs))
- .reduce(0.0, Double::sum) / mResults.size();
+ .reduce(0.5,
+ (prior, measurement) ->
+ (prior * measurement)
+ / (prior * measurement + (1 - prior) * (1 - measurement)));
}
/**
@@ -91,7 +103,7 @@
* A result of 1 means that there are ample, fresh data to act upon that is all consistent
* with each other.
*
- * See als {@link #falsePenalty()}.
+ * See als {@link #falseBelief()}.
*/
double falseConfidence() {
//noinspection StatementWithEmptyBody
@@ -126,6 +138,15 @@
finalScore /= results.size();
+ // Never add a 0 or 1, else Bayes breaks down (a 0 and a 1 together results in NaN). In
+ // other words, you shouldn't need Bayes if you have 100% confidence one way or another.
+ // Instead, make the number ever so slightly smaller so that our math never breaks.
+ if (finalScore == 1) {
+ finalScore = 0.99999;
+ } else if (finalScore == 0) {
+ finalScore = 0.00001;
+ }
+
//noinspection StatementWithEmptyBody
while (mResults.poll() != null) {
// Empty out the expired results.
@@ -147,15 +168,17 @@
private final double mScore;
CombinedResult(long uptimeMillis, double score) {
- mExpiryMs = uptimeMillis + TOTAL_DECAY_TIME_MS;
+ mExpiryMs = uptimeMillis + HISTORY_MAX_AGE_MS;
mScore = score;
}
double getDecayedScore(long nowMs) {
long remainingTimeMs = mExpiryMs - nowMs;
- long decayedTimeMs = TOTAL_DECAY_TIME_MS - remainingTimeMs;
+ long decayedTimeMs = HISTORY_MAX_AGE_MS - remainingTimeMs;
double timeIntervals = (double) decayedTimeMs / DECAY_INTERVAL_MS;
- return mScore * Math.pow(HISTORY_DECAY, timeIntervals);
+
+ // Score should decay towards 0.5.
+ return (mScore - 0.5) * Math.pow(HISTORY_DECAY, timeIntervals) + 0.5;
}
double getScore() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
index cd399fe..77d2d42 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -56,7 +56,7 @@
}
@Override
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
int interactionType = getInteractionType();
int allowedPointerCount =
(interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 9ee8598..6e97857 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -112,7 +112,7 @@
}
@Override
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
if (getInteractionType() == QUICK_SETTINGS) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
index f2622ec..4dd20cc 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
@@ -39,12 +39,15 @@
}
@Override
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
return isTap(getRecentMotionEvents());
}
/** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */
public Result isTap(List<MotionEvent> motionEvents) {
+ if (motionEvents.isEmpty()) {
+ return Result.falsed(0, "no motion events");
+ }
float downX = motionEvents.get(0).getX();
float downY = motionEvents.get(0).getY();
@@ -59,7 +62,7 @@
} else if (Math.abs(event.getY() - downY) >= mTouchSlop) {
reason = "dY too big for a tap: "
+ Math.abs(event.getY() - downY)
- + "vs "
+ + " vs "
+ mTouchSlop;
return Result.falsed(0.5, reason);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index d470d62..4e032ea 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -38,7 +38,7 @@
}
@Override
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
boolean vertical = isVertical();
boolean up = isUp();
boolean right = isRight();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index 2bfb218..2058257 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -84,7 +84,7 @@
}
@Override
- Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
+ Result calculateFalsingResult(double historyBelief, double historyConfidence) {
List<MotionEvent> motionEvents = getRecentMotionEvents();
// Rotate horizontal gestures to be horizontal between their first and last point.
// Rotate vertical gestures to be vertical between their first and last point.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 4491cc1..0bfd065 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -212,6 +212,14 @@
createNavigationBar(display, null /* savedState */, null /* result */);
}
+ @Override
+ public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ final NavigationBarView navigationBarView = getNavigationBarView(displayId);
+ if (navigationBarView != null) {
+ navigationBarView.setNavigationBarLumaSamplingEnabled(enable);
+ }
+ }
+
/**
* Recreates the navigation bar for the given display.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 35d5ca9..148c665 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -1397,4 +1397,12 @@
private final Consumer<Rect> mPipListener = bounds -> post(() -> {
mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds);
});
+
+ void setNavigationBarLumaSamplingEnabled(boolean enable) {
+ if (enable) {
+ mRegionSamplingHelper.start(mSamplingBounds);
+ } else {
+ mRegionSamplingHelper.stop();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index fe76668..b8823e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,6 +14,8 @@
package com.android.systemui.qs;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
import android.util.Log;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
@@ -35,6 +37,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -77,6 +80,9 @@
// This animates fading of SecurityFooter and media divider
private TouchAnimator mAllPagesDelayedAnimator;
private TouchAnimator mBrightnessAnimator;
+ private HeightExpansionAnimator mQQSTileHeightAnimator;
+ private HeightExpansionAnimator mOtherTilesExpandAnimator;
+
private boolean mNeedsAnimatorUpdate = false;
private boolean mOnKeyguard;
@@ -161,7 +167,7 @@
@Override
public void onViewAttachedToWindow(View v) {
mTunerService.addTunable(this, ALLOW_FANCY_ANIMATION,
- MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
+ MOVE_FULL_ROWS);
}
@Override
@@ -179,9 +185,6 @@
}
} else if (MOVE_FULL_ROWS.equals(key)) {
mFullRows = TunerService.parseIntegerSwitch(newValue, true);
- } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
- mNumQuickTiles = QuickQSPanel.parseNumTiles(newValue);
- clearAnimationState();
}
updateAnimators();
}
@@ -209,6 +212,10 @@
clearAnimationState();
mAllViews.clear();
mQuickQsViews.clear();
+ mQQSTileHeightAnimator = null;
+ mOtherTilesExpandAnimator = null;
+
+ mNumQuickTiles = mQuickQsPanel.getNumQuickTiles();
QSTileLayout tileLayout = mQsPanelController.getTileLayout();
mAllViews.add((View) tileLayout);
@@ -218,6 +225,9 @@
+ mQs.getHeader().getPaddingBottom();
firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
+ boolean qsSideLabelsEnabled = mFeatureFlags.isQSLabelsEnabled();
+ int qqsTileHeight = 0;
+
for (QSTile tile : tiles) {
QSTileView tileView = mQsPanelController.getTileView(tile);
if (tileView == null) {
@@ -237,22 +247,47 @@
getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
getRelativePosition(loc2, tileIcon, view);
final int xDiff = loc2[0] - loc1[0];
- final int yDiff = loc2[1] - loc1[1];
-
+ int yDiff = loc2[1] - loc1[1];
if (count < tileLayout.getNumVisibleTiles()) {
+ getRelativePosition(loc1, quickTileView, view);
+ getRelativePosition(loc2, tileView, view);
+ int yOffset = qsSideLabelsEnabled ? loc2[1] - loc1[1] : 0;
// Move the quick tile right from its location to the new one.
- translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
- translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
-
- // Counteract the parent translation on the tile. So we have a static base to
- // animate the label position off from.
- //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+ View v = qsSideLabelsEnabled ? quickTileView.getIcon() : quickTileView;
+ translationXBuilder.addFloat(v, "translationX", 0, xDiff);
+ translationYBuilder.addFloat(v, "translationY", 0, yDiff - yOffset);
+ mAllViews.add(v);
// Move the real tile from the quick tile position to its final
// location.
- translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
- translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
+ v = qsSideLabelsEnabled ? tileIcon : tileView;
+ translationXBuilder.addFloat(v, "translationX", -xDiff, 0);
+ translationYBuilder.addFloat(v, "translationY", -yDiff + yOffset, 0);
+
+ if (qsSideLabelsEnabled) {
+ translationYBuilder.addFloat(quickTileView, "translationY", 0, yOffset);
+ translationYBuilder.addFloat(tileView, "translationY", -yOffset, 0);
+
+ if (mQQSTileHeightAnimator == null) {
+ mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
+ quickTileView.getHeight(), tileView.getHeight());
+ qqsTileHeight = quickTileView.getHeight();
+ }
+
+ mQQSTileHeightAnimator.addView(quickTileView);
+ View qqsLabelContainer = quickTileView.getLabelContainer();
+ View qsLabelContainer = tileView.getLabelContainer();
+
+ getRelativePosition(loc1, qqsLabelContainer, view);
+ getRelativePosition(loc2, qsLabelContainer, view);
+ yDiff = loc2[1] - loc1[1] - yOffset;
+
+ translationYBuilder.addFloat(qqsLabelContainer, "translationY", 0, yDiff);
+ translationYBuilder.addFloat(qsLabelContainer, "translationY", -yDiff, 0);
+ mAllViews.add(qqsLabelContainer);
+ mAllViews.add(qsLabelContainer);
+ }
} else { // These tiles disappear when expanding
firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0);
@@ -265,7 +300,7 @@
translationX);
}
- if (mFeatureFlags.isQSLabelsEnabled()) {
+ if (qsSideLabelsEnabled) {
mQuickQsViews.add(tileView);
} else {
mQuickQsViews.add(tileView.getIconWithBackground());
@@ -278,9 +313,29 @@
mAllViews.add(tileIcon);
} else {
- firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
- firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
+ if (!qsSideLabelsEnabled) {
+ firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
+ firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
+ } else {
+ // Pretend there's a corresponding QQS tile (for the position) that we are
+ // expanding from.
+ SideLabelTileLayout qqsLayout =
+ (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
+ getRelativePosition(loc1, qqsLayout, view);
+ getRelativePosition(loc2, tileView, view);
+ int diff = loc2[1] - (loc1[1] + qqsLayout.getPhantomTopPosition(count));
+ translationYBuilder.addFloat(tileView, "translationY", -diff, 0);
+ if (mOtherTilesExpandAnimator == null) {
+ mOtherTilesExpandAnimator =
+ new HeightExpansionAnimator(
+ this, qqsTileHeight, tileView.getHeight());
+ }
+ mOtherTilesExpandAnimator.addView(tileView);
+ tileView.setClipChildren(true);
+ tileView.setClipToPadding(true);
+ }
}
+
mAllViews.add(tileView);
count++;
}
@@ -303,7 +358,7 @@
.build();
// Fade in the tiles/labels as we reach the final position.
Builder builder = new Builder()
- .setStartDelay(EXPANDED_TILE_DELAY)
+ .setStartDelay(qsSideLabelsEnabled ? 0 : EXPANDED_TILE_DELAY)
.addFloat(tileLayout, "alpha", 0, 1);
mFirstPageDelayedAnimator = builder.build();
@@ -331,6 +386,12 @@
translationYBuilder.setInterpolator(interpolatorBuilder.getYInterpolator());
mTranslationXAnimator = translationXBuilder.build();
mTranslationYAnimator = translationYBuilder.build();
+ if (mQQSTileHeightAnimator != null) {
+ mQQSTileHeightAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+ }
+ if (mOtherTilesExpandAnimator != null) {
+ mOtherTilesExpandAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+ }
}
mNonfirstPageAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsPanel, "alpha", 1, 0)
@@ -404,6 +465,12 @@
if (mBrightnessAnimator != null) {
mBrightnessAnimator.setPosition(position);
}
+ if (mQQSTileHeightAnimator != null) {
+ mQQSTileHeightAnimator.setPosition(position);
+ }
+ if (mOtherTilesExpandAnimator != null) {
+ mOtherTilesExpandAnimator.setPosition(position);
+ }
} else {
mNonfirstPageAnimator.setPosition(position);
mNonfirstPageDelayedAnimator.setPosition(position);
@@ -446,6 +513,16 @@
v.setAlpha(1);
v.setTranslationX(0);
v.setTranslationY(0);
+ if (v instanceof SideLabelTileLayout) {
+ ((SideLabelTileLayout) v).setClipChildren(false);
+ ((SideLabelTileLayout) v).setClipToPadding(false);
+ }
+ }
+ if (mQQSTileHeightAnimator != null) {
+ mQQSTileHeightAnimator.resetViewsHeights();
+ }
+ if (mOtherTilesExpandAnimator != null) {
+ mOtherTilesExpandAnimator.resetViewsHeights();
}
final int N2 = mQuickQsViews.size();
for (int i = 0; i < N2; i++) {
@@ -483,4 +560,61 @@
updateAnimators();
setCurrentPosition();
};
+
+ static class HeightExpansionAnimator {
+ private final List<View> mViews = new ArrayList<>();
+ private final ValueAnimator mAnimator;
+ private final TouchAnimator.Listener mListener;
+
+ private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ float mLastT = -1;
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ float t = valueAnimator.getAnimatedFraction();
+ if (t == 0f) {
+ mListener.onAnimationAtStart();
+ } else if (t == 1f) {
+ mListener.onAnimationAtEnd();
+ } else if (mLastT <= 0 || mLastT == 1) {
+ mListener.onAnimationStarted();
+ }
+ mLastT = t;
+ final int viewCount = mViews.size();
+ int height = (Integer) valueAnimator.getAnimatedValue();
+ for (int i = 0; i < viewCount; i++) {
+ View v = mViews.get(i);
+ v.setBottom(v.getTop() + height);
+ }
+ }
+ };
+
+ HeightExpansionAnimator(TouchAnimator.Listener listener, int startHeight, int endHeight) {
+ mListener = listener;
+ mAnimator = ValueAnimator.ofInt(startHeight, endHeight);
+ mAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ mAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ mAnimator.addUpdateListener(mUpdateListener);
+ }
+
+ void addView(View v) {
+ mViews.add(v);
+ }
+
+ void setInterpolator(TimeInterpolator interpolator) {
+ mAnimator.setInterpolator(interpolator);
+ }
+
+ void setPosition(float position) {
+ mAnimator.setCurrentFraction(position);
+ }
+
+ void resetViewsHeights() {
+ final int viewsCount = mViews.size();
+ for (int i = 0; i < viewsCount; i++) {
+ View v = mViews.get(i);
+ v.setBottom(v.getTop() + v.getMeasuredHeight());
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index ed308ae..7c9f0b0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -430,6 +430,7 @@
mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
mQSPanelController.setRevealExpansion(expansion);
mQSPanelController.getTileLayout().setExpansion(expansion);
+ mQuickQSPanelController.getTileLayout().setExpansion(expansion);
mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
if (fullyCollapsed) {
mQSPanelScrollView.setScrollY(0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index ff9b912..c794a21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -315,7 +315,7 @@
int tileBg = getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size);
mFooterMarginStartHorizontal = getResources().getDimensionPixelSize(
R.dimen.qs_footer_horizontal_margin);
- mVisualTilePadding = (int) ((tileSize - tileBg) / 2.0f);
+ mVisualTilePadding = mSideLabels ? 0 : (int) ((tileSize - tileBg) / 2.0f);
updatePadding();
updatePageIndicator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f51d7ef..8f99a9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -348,6 +348,7 @@
}
static class QQSSideLabelTileLayout extends SideLabelTileLayout {
+
QQSSideLabelTileLayout(Context context) {
super(context, null);
setClipChildren(false);
@@ -361,6 +362,7 @@
@Override
public boolean updateResources() {
+ mCellHeightResId = R.dimen.qs_quick_tile_size;
boolean b = super.updateResources();
mMaxAllowedRows = 2;
return b;
@@ -379,5 +381,38 @@
updateMaxRows(10000, mRecords.size());
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+
+ @Override
+ public void setListening(boolean listening, UiEventLogger uiEventLogger) {
+ boolean startedListening = !mListening && listening;
+ super.setListening(listening, uiEventLogger);
+ if (startedListening) {
+ // getNumVisibleTiles() <= mRecords.size()
+ for (int i = 0; i < getNumVisibleTiles(); i++) {
+ QSTile tile = mRecords.get(i).tile;
+ uiEventLogger.logWithInstanceId(QSEvent.QQS_TILE_VISIBLE, 0,
+ tile.getMetricsSpec(), tile.getInstanceId());
+ }
+ }
+ }
+
+ @Override
+ public void setExpansion(float expansion) {
+ if (expansion > 0f && expansion < 1f) {
+ return;
+ }
+ boolean selected = expansion == 0f;
+ // Expansion == 0f is when QQS is fully showing (as opposed to 1f, which is QS). At this
+ // point we want them to be selected so the tiles will marquee (but not at other points
+ // of expansion.
+ // We set it as not important while we change this, so setting each tile as selected
+ // will not cause them to announce themselves until the user has actually selected the
+ // item.
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setSelected(selected);
+ }
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 671f8f7..fee56b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -99,7 +99,7 @@
break;
}
}
- super.setTiles(tiles, !mQSLabelFlag);
+ super.setTiles(tiles, /* collapsedView */ true);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index 52f111e7..0ebadfd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -33,4 +33,15 @@
override fun isFull(): Boolean {
return mRecords.size >= maxTiles()
}
+
+ /**
+ * Return the position from the top of the layout of the tile with this index.
+ *
+ * This will return a position even for indices that go beyond [maxTiles], continuing the rows
+ * beyond that.
+ */
+ fun getPhantomTopPosition(index: Int): Int {
+ val row = index / mColumns
+ return getRowTop(row)
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index c1ce4a5..9e0aa5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -25,6 +25,7 @@
protected int mColumns;
protected int mCellWidth;
+ protected int mCellHeightResId = R.dimen.qs_tile_height;
protected int mCellHeight;
protected int mMaxCellHeight;
protected int mCellMarginHorizontal;
@@ -118,7 +119,7 @@
final Resources res = mContext.getResources();
mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
updateColumns();
- mMaxCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
+ mMaxCellHeight = mContext.getResources().getDimensionPixelSize(mCellHeightResId);
mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
@@ -235,7 +236,7 @@
layoutTileRecords(mRecords.size());
}
- private int getRowTop(int row) {
+ protected int getRowTop(int row) {
return row * (mCellHeight + mCellMarginVertical) + mCellMarginTop;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
index f8c0dd4..7977b49 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
@@ -14,7 +14,7 @@
class CustomizeTileViewHorizontal(
context: Context,
icon: QSIconView
-) : QSTileViewHorizontal(context, icon),
+) : QSTileViewHorizontal(context, icon, collapsed = false),
TileAdapter.CustomizeView {
private var showAppLabel = false
@@ -27,6 +27,7 @@
override fun handleStateChanged(state: QSTile.State) {
super.handleStateChanged(state)
+ mShowRippleEffect = false
mSecondLine.visibility = if (showAppLabel) View.VISIBLE else View.GONE
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 56d06eb..1699a34 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -51,6 +51,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -95,6 +96,7 @@
QSHost host,
Looper backgroundLooper,
Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -102,8 +104,8 @@
String action,
Context userContext
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mWindowManager = WindowManagerGlobal.getWindowManagerService();
mComponent = ComponentName.unflattenFromString(action);
mTile = new Tile();
@@ -450,6 +452,7 @@
final Lazy<QSHost> mQSHostLazy;
final Looper mBackgroundLooper;
final Handler mMainHandler;
+ private final FalsingManager mFalsingManager;
final MetricsLogger mMetricsLogger;
final StatusBarStateController mStatusBarStateController;
final ActivityStarter mActivityStarter;
@@ -463,6 +466,7 @@
Lazy<QSHost> hostLazy,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -471,6 +475,7 @@
mQSHostLazy = hostLazy;
mBackgroundLooper = backgroundLooper;
mMainHandler = mainHandler;
+ mFalsingManager = falsingManager;
mMetricsLogger = metricsLogger;
mStatusBarStateController = statusBarStateController;
mActivityStarter = activityStarter;
@@ -496,6 +501,7 @@
mQSHostLazy.get(),
mBackgroundLooper,
mMainHandler,
+ mFalsingManager,
mMetricsLogger,
mStatusBarStateController,
mActivityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 9e5fe73..29b9e64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -248,10 +248,10 @@
public QSTileView createTileView(QSTile tile, boolean collapsedView) {
Context context = new ContextThemeWrapper(mQsHostLazy.get().getContext(), R.style.qs_theme);
QSIconView icon = tile.createTileView(context);
- if (collapsedView) {
+ if (mSideLabels) {
+ return new QSTileViewHorizontal(context, icon, collapsedView);
+ } else if (collapsedView) {
return new QSTileBaseView(context, icon, collapsedView);
- } else if (mSideLabels) {
- return new QSTileViewHorizontal(context, icon);
} else {
return new com.android.systemui.qs.tileimpl.QSTileView(context, icon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 33ca7d6..a45b1319 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -58,13 +58,13 @@
private static final int ICON_MASK_ID = com.android.internal.R.string.config_icon_mask;
protected final Handler mHandler = new H();
private final int[] mLocInScreen = new int[2];
- private final FrameLayout mIconFrame;
+ protected final FrameLayout mIconFrame;
protected QSIconView mIcon;
protected RippleDrawable mRipple;
protected Drawable mTileBackground;
private String mAccessibilityClass;
private boolean mTileState;
- private boolean mCollapsedView;
+ protected boolean mCollapsedView;
protected boolean mShowRippleEffect = true;
private float mStrokeWidthActive;
private float mStrokeWidthInactive;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 5a81676..f9d1def 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -58,6 +58,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.Prefs;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
@@ -103,6 +104,7 @@
private final StatusBarStateController mStatusBarStateController;
protected final ActivityStarter mActivityStarter;
private final UiEventLogger mUiEventLogger;
+ private final FalsingManager mFalsingManager;
private final QSLogger mQSLogger;
private volatile int mReadyState;
@@ -159,6 +161,7 @@
QSHost host,
Looper backgroundLooper,
Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -171,6 +174,7 @@
mUiHandler = mainHandler;
mHandler = new H(backgroundLooper);
+ mFalsingManager = falsingManager;
mQSLogger = qsLogger;
mMetricsLogger = metricsLogger;
mStatusBarStateController = statusBarStateController;
@@ -608,7 +612,9 @@
mContext, mEnforcedAdmin);
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
} else {
- handleClick();
+ if (!mFalsingManager.isFalseTap(true, 0.1)) {
+ handleClick();
+ }
}
} else if (msg.what == SECONDARY_CLICK) {
name = "handleSecondaryClick";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index b59326a..c7ed89b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -26,6 +26,8 @@
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.settingslib.Utils;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
@@ -116,7 +118,8 @@
}
}
- private boolean shouldLabelBeSingleLine() {
+ protected boolean shouldLabelBeSingleLine() {
+ if (mCollapsedView) return true;
if (mLabel.getLineCount() > mMaxLabelLines) {
return true;
} else if (!TextUtils.isEmpty(mSecondLine.getText())
@@ -138,14 +141,14 @@
} else {
labelColor = mColorLabelUnavailable;
}
- mLabel.setTextColor(labelColor);
+ changeLabelColor(labelColor);
mState = state.state;
mLabel.setText(state.label);
}
if (!Objects.equals(mSecondLine.getText(), state.secondaryLabel)) {
mSecondLine.setText(state.secondaryLabel);
- mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) ? View.GONE
- : View.VISIBLE);
+ mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) || mCollapsedView
+ ? View.GONE : View.VISIBLE);
}
boolean dualTarget = mDualTargetAllowed && state.dualTarget;
handleExpand(dualTarget);
@@ -160,6 +163,10 @@
mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
}
+ protected void changeLabelColor(ColorStateList color) {
+ mLabel.setTextColor(color);
+ }
+
protected void handleExpand(boolean dualTarget) {
mExpandIndicator.setVisibility(dualTarget ? View.VISIBLE : View.GONE);
mExpandSpace.setVisibility(dualTarget ? View.VISIBLE : View.GONE);
@@ -178,4 +185,10 @@
public TextView getAppLabel() {
return mSecondLine;
}
+
+ @Nullable
+ @Override
+ public View getLabelContainer() {
+ return mLabelContainer;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index 328c2c3..32285cf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -21,8 +21,7 @@
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.Drawable
-import android.graphics.drawable.ShapeDrawable
-import android.graphics.drawable.shapes.RoundRectShape
+import android.graphics.drawable.RippleDrawable
import android.service.quicksettings.Tile.STATE_ACTIVE
import android.view.Gravity
import android.widget.LinearLayout
@@ -32,25 +31,31 @@
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState
-// Placeholder
-private const val CORNER_RADIUS = 40f
-private val RADII = (1..8).map { CORNER_RADIUS }.toFloatArray()
-
open class QSTileViewHorizontal(
context: Context,
- icon: QSIconView
-) : QSTileView(context, icon, false) {
+ icon: QSIconView,
+ collapsed: Boolean
+) : QSTileView(context, icon, collapsed) {
- protected var backgroundDrawable: ShapeDrawable? = null
+ protected var colorBackgroundDrawable: Drawable? = null
private var paintColor = Color.WHITE
private var paintAnimator: ValueAnimator? = null
+ private var labelAnimator: ValueAnimator? = null
init {
orientation = HORIZONTAL
+ gravity = Gravity.CENTER_VERTICAL or Gravity.START
mDualTargetAllowed = false
+ val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
+ setPadding(padding, paddingTop, padding, paddingBottom)
+
mBg.setImageDrawable(null)
+ mIconFrame.removeAllViews()
+ removeView(mIconFrame)
+ val iconSize = context.resources.getDimensionPixelSize(R.dimen.qs_icon_size)
+ addView(mIcon, 0, LayoutParams(iconSize, iconSize))
+
mColorLabelActive = ColorStateList.valueOf(getColorForState(getContext(), STATE_ACTIVE))
- mMaxLabelLines = 3
}
override fun createLabel() {
@@ -61,65 +66,112 @@
removeRule(RelativeLayout.ALIGN_PARENT_TOP)
}
}
+ mLabelContainer.setPadding(0, 0, 0, 0)
+ (mLabelContainer.layoutParams as MarginLayoutParams).apply {
+ marginStart = context.resources.getDimensionPixelSize(R.dimen.qs_label_container_margin)
+ }
mLabel.gravity = Gravity.START
mLabel.textDirection = TEXT_DIRECTION_LOCALE
mSecondLine.gravity = Gravity.START
mSecondLine.textDirection = TEXT_DIRECTION_LOCALE
- val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
- mLabelContainer.setPaddingRelative(0, padding, padding, padding)
+
(mLabelContainer.layoutParams as LayoutParams).gravity =
Gravity.CENTER_VERTICAL or Gravity.START
+ if (mCollapsedView) {
+ mSecondLine.visibility = GONE
+ }
+ }
+
+ override fun shouldLabelBeSingleLine(): Boolean {
+ return true
}
override fun updateRippleSize() {
}
override fun newTileBackground(): Drawable? {
- backgroundDrawable = ShapeDrawable(RoundRectShape(RADII, null, null))
- return backgroundDrawable
+ val ripple = mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
+ colorBackgroundDrawable = ripple.findDrawableByLayerId(R.id.background)
+ return ripple
}
override fun setClickable(clickable: Boolean) {
super.setClickable(clickable)
- background = mTileBackground
+ background = if (clickable && mShowRippleEffect) {
+ mTileBackground
+ } else {
+ colorBackgroundDrawable
+ }
}
override fun handleStateChanged(state: QSTile.State) {
super.handleStateChanged(state)
- mSecondLine.setTextColor(mLabel.textColors)
mLabelContainer.background = null
val allowAnimations = animationsEnabled() && paintColor != Color.WHITE
val newColor = getCircleColor(state.state)
if (allowAnimations) {
- animateToNewState(newColor)
+ animateBackground(newColor)
} else {
if (newColor != paintColor) {
- clearAnimator()
- backgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))
+ clearBackgroundAnimator()
+ colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))?.also {
+ paintColor = newColor
+ }
paintColor = newColor
}
}
}
- private fun animateToNewState(newColor: Int) {
- if (newColor != paintColor) {
- clearAnimator()
- paintAnimator = ValueAnimator.ofArgb(paintColor, newColor)
+ private fun animateBackground(newBackgroundColor: Int) {
+ if (newBackgroundColor != paintColor) {
+ clearBackgroundAnimator()
+ paintAnimator = ValueAnimator.ofArgb(paintColor, newBackgroundColor)
.setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
addUpdateListener { animation: ValueAnimator ->
val c = animation.animatedValue as Int
- backgroundDrawable?.setTintList(ColorStateList.valueOf(c))
- paintColor = c
+ colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(c))?.also {
+ paintColor = c
+ }
}
start()
}
}
}
- private fun clearAnimator() {
+ override fun changeLabelColor(color: ColorStateList) {
+ val allowAnimations = animationsEnabled()
+ val currentColor = mLabel.textColors.defaultColor
+ if (currentColor != color.defaultColor) {
+ clearLabelAnimator()
+ if (allowAnimations) {
+ labelAnimator = ValueAnimator.ofArgb(currentColor, color.defaultColor)
+ .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
+ addUpdateListener {
+ setLabelsColor(ColorStateList.valueOf(it.animatedValue as Int))
+ }
+ start()
+ }
+ } else {
+ setLabelsColor(color)
+ }
+ }
+ }
+
+ private fun setLabelsColor(color: ColorStateList) {
+ mLabel.setTextColor(color)
+ if (!mCollapsedView) {
+ mSecondLine.setTextColor(color)
+ }
+ }
+
+ private fun clearBackgroundAnimator() {
paintAnimator?.cancel()?.also { paintAnimator = null }
}
+ private fun clearLabelAnimator() {
+ labelAnimator?.cancel()?.also { labelAnimator = null }
+ }
+
override fun handleExpand(dualTarget: Boolean) {}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index b848590..07abb90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -38,6 +38,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.GlobalSetting;
@@ -63,6 +64,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -70,8 +72,8 @@
BroadcastDispatcher broadcastDispatcher,
Lazy<ConnectivityManager> lazyConnectivityManager
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mBroadcastDispatcher = broadcastDispatcher;
mLazyConnectivityManager = lazyConnectivityManager;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
index dede627..2945c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
@@ -15,6 +15,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
@@ -30,6 +31,7 @@
host: QSHost,
@Background backgroundLooper: Looper,
@Main mainHandler: Handler,
+ falsingManager: FalsingManager,
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
@@ -41,6 +43,7 @@
host,
backgroundLooper,
mainHandler,
+ falsingManager,
metricsLogger,
statusBarStateController,
activityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index bf3e4be..49d3ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -29,6 +29,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -59,6 +60,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -66,8 +68,8 @@
BatteryController batteryController,
SecureSettings secureSettings
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mBatteryController = batteryController;
mBatteryController.observe(getLifecycle(), this);
int currentUser = host.getUserContext().getUserId();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 1424244..56df4d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -42,6 +42,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -70,14 +71,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
BluetoothController bluetoothController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = bluetoothController;
mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter();
mController.observe(getLifecycle(), mCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index 70287cd..0d73a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -21,7 +21,6 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
@@ -35,6 +34,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
@@ -50,13 +50,15 @@
@Background Looper backgroundLooper,
@Main Handler mainHandler,
MetricsLogger metricsLogger,
+ FalsingManager falsingManager,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
IndividualSensorPrivacyController sensorPrivacyController,
KeyguardStateController keyguardStateController) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger, sensorPrivacyController, keyguardStateController);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger, sensorPrivacyController,
+ keyguardStateController);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index f03ce2c..fa99eed 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -40,6 +40,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -81,6 +82,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -90,8 +92,8 @@
NetworkController networkController,
HotspotController hotspotController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = castController;
mDetailAdapter = new CastDetailAdapter();
mKeyguard = keyguardStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 6a574d1..8cc6ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -45,6 +45,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile.SignalState;
@@ -76,14 +77,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
NetworkController networkController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = networkController;
mDataController = mController.getMobileDataController();
mDetailAdapter = new CellularDetailAdapter();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index a6d9604..ca7cf83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -32,6 +32,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -60,6 +61,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -67,8 +69,8 @@
UserTracker userTracker,
SecureSettings secureSettings
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mSetting = new SecureSetting(secureSettings, mHandler,
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 85f1245..61376f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -29,6 +29,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -49,14 +50,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
DataSaverController dataSaverController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mDataSaverController = dataSaverController;
mDataSaverController.observe(getLifecycle(), this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index 257d6a7..a74a50e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -33,6 +33,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
@@ -47,6 +48,7 @@
host: QSHost,
@Background backgroundLooper: Looper,
@Main mainHandler: Handler,
+ falsingManager: FalsingManager,
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
@@ -58,6 +60,7 @@
host,
backgroundLooper,
mainHandler,
+ falsingManager,
metricsLogger,
statusBarStateController,
activityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 7ec2691..4b96cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -54,6 +54,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -87,6 +88,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -94,8 +96,8 @@
ZenModeController zenModeController,
@Main SharedPreferences sharedPreferences
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = zenModeController;
mSharedPreferences = sharedPreferences;
mDetailAdapter = new DndDetailAdapter();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index cd45082..31a98db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -30,6 +30,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -51,14 +52,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
FlashlightController flashlightController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mFlashlightController = flashlightController;
mFlashlightController.observe(getLifecycle(), this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index a45d94a..4e0f634 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -32,6 +32,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -57,6 +58,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -64,8 +66,8 @@
HotspotController hotspotController,
DataSaverController dataSaverController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mHotspotController = hotspotController;
mDataSaverController = dataSaverController;
mHotspotController.observe(this, mCallbacks);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index e1a1fd2..14a3fc0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -40,9 +40,9 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.plugins.qs.QSTile.Icon;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.AlphaControlledSignalTileView;
@@ -80,14 +80,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
NetworkController networkController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = networkController;
mDataController = mController.getMobileDataController();
mController.observe(getLifecycle(), mSignalCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index d502d06..830a1fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -30,6 +30,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -55,6 +56,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -62,8 +64,8 @@
LocationController locationController,
KeyguardStateController keyguardStateController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = locationController;
mKeyguard = keyguardStateController;
mController.observe(this, mCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index e9b712d..b8d8792 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -21,7 +21,6 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManager.Sensors.Sensor;
import android.os.Handler;
import android.os.Looper;
@@ -35,6 +34,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
@@ -50,13 +50,15 @@
@Background Looper backgroundLooper,
@Main Handler mainHandler,
MetricsLogger metricsLogger,
+ FalsingManager falsingManager,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
IndividualSensorPrivacyController sensorPrivacyController,
KeyguardStateController keyguardStateController) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger, sensorPrivacyController, keyguardStateController);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger, sensorPrivacyController,
+ keyguardStateController);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 63e27796..6ac2f9ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -36,6 +36,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -60,14 +61,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
BroadcastDispatcher broadcastDispatcher
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mBroadcastDispatcher = broadcastDispatcher;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index d8548de..5369086 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -40,6 +40,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -78,6 +79,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -86,8 +88,8 @@
ColorDisplayManager colorDisplayManager,
NightDisplayListenerModule.Builder nightDisplayListenerBuilder
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mLocationController = locationController;
mManager = colorDisplayManager;
mNightDisplayListenerBuilder = nightDisplayListenerBuilder;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index aec7b9a..479be65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -30,6 +30,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -57,13 +58,14 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mReduceBrightColorsController = reduceBrightColorsController;
mReduceBrightColorsController.observe(getLifecycle(), this);
mIsAvailable = isAvailable;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index c46cc4f..173cc05 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -31,6 +31,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -52,14 +53,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
RotationLockController rotationLockController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = rotationLockController;
mController.observe(this, mCallback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 0f0a9a2..6845dc5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -29,6 +29,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -55,6 +56,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -62,8 +64,8 @@
RecordingController controller,
KeyguardDismissUtil keyguardDismissUtil
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = controller;
mController.observe(this, mCallback);
mKeyguardDismissUtil = keyguardDismissUtil;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 0c582bd..a492330 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -29,6 +29,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -59,14 +60,15 @@
protected SensorPrivacyToggleTile(QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
IndividualSensorPrivacyController sensorPrivacyController,
KeyguardStateController keyguardStateController) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mSensorPrivacyController = sensorPrivacyController;
mKeyguard = keyguardStateController;
mSensorPrivacyController.observe(getLifecycle(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index 78975a47..0ef5bc8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -32,6 +32,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -66,6 +67,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -74,8 +76,8 @@
BatteryController batteryController,
LocationController locationController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mBatteryController = batteryController;
mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
mLocationController = locationController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index a6cddd3..2590f37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -28,6 +28,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
@@ -51,6 +52,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -58,8 +60,8 @@
UserSwitcherController userSwitcherController,
UserInfoController userInfoController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mUserSwitcherController = userSwitcherController;
mUserInfoController = userInfoController;
mUserInfoController.observe(getLifecycle(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 341e67c..dab68ed 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -37,6 +37,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
@@ -77,6 +78,7 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
@@ -84,8 +86,8 @@
NetworkController networkController,
AccessPointController accessPointController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mController = networkController;
mWifiController = accessPointController;
mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 5235b6d..c88a002 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -29,6 +29,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -50,14 +51,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
ManagedProfileController managedProfileController
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
mProfileController = managedProfileController;
mProfileController.observe(getLifecycle(), this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c4fa6df..0599039 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -141,6 +141,7 @@
private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 57 << MSG_SHIFT;
//TODO(b/169175022) Update name and when feature name is locked.
private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE = 58 << MSG_SHIFT;
+ private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -369,6 +370,11 @@
* Handles a window manager shell logging command.
*/
default void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {}
+
+ /**
+ * @see IStatusBar#setNavigationBarLumaSamplingEnabled(int, boolean)
+ */
+ default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
}
public CommandQueue(Context context) {
@@ -1019,6 +1025,14 @@
}
@Override
+ public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ synchronized (mLock) {
+ mHandler.obtainMessage(MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED, displayId,
+ enable ? 1 : 0).sendToTarget();
+ }
+ }
+
+ @Override
public void passThroughShellCommand(String[] args, ParcelFileDescriptor pfd) {
final FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
final PrintWriter pw = new PrintWriter(fos);
@@ -1400,6 +1414,12 @@
}
args.recycle();
break;
+ case MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED:
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).setNavigationBarLumaSamplingEnabled(msg.arg1,
+ msg.arg2 != 0);
+ }
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 89b97ae..6b144c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -28,6 +28,7 @@
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.util.Property;
+import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.animation.Interpolator;
@@ -35,6 +36,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
@@ -168,6 +170,7 @@
private Rect mIsolatedIconLocation;
private int[] mAbsolutePosition = new int[2];
private View mIsolatedIconForAnimation;
+ private int mThemedTextColorPrimary;
public NotificationIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -179,6 +182,10 @@
mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);
mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
mStaticDotDiameter = 2 * mStaticDotRadius;
+ final Context themedContext = new ContextThemeWrapper(getContext(),
+ com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+ mThemedTextColorPrimary = Utils.getColorAttr(themedContext,
+ com.android.internal.R.attr.textColorPrimary).getDefaultColor();
}
@Override
@@ -806,7 +813,8 @@
}
}
icon.setVisibleState(visibleState, animationsAllowed);
- icon.setIconColor(iconColor, needsCannedAnimation && animationsAllowed);
+ icon.setIconColor(mThemedTextColorPrimary,
+ needsCannedAnimation && animationsAllowed);
if (animate) {
animateTo(icon, animationProperties);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 626162d..ca6e53d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -575,8 +575,8 @@
FeatureFlags featureFlags) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
- latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager,
- ambientState);
+ statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
+ statusBarTouchableRegionManager, ambientState);
mView = view;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
@@ -1348,7 +1348,6 @@
super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}
-
private boolean onQsIntercept(MotionEvent event) {
int pointerIndex = event.findPointerIndex(mTrackingPointer);
if (pointerIndex < 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
index 50c8e2e..66df936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java
@@ -64,7 +64,7 @@
mTrackTouch = event.getY() <= maxTouchableHeight;
break;
case MotionEvent.ACTION_MOVE:
- if (mTrackTouch && mFalsingManager.isFalseTap(false)) {
+ if (mTrackTouch && mFalsingManager.isFalseTap(false, 0)) {
makeInactive();
mTrackTouch = false;
}
@@ -78,10 +78,10 @@
// 1) See if we have confidence that we can activate after a single tap.
// 2) Else, see if it looks like a tap at all and check for a double-tap.
- if (!mFalsingManager.isFalseTap(true)) {
+ if (!mFalsingManager.isFalseTap(true, 0)) {
makeInactive();
return mDoubleTapListener.onDoubleTap();
- } else if (!mFalsingManager.isFalseTap(false)) {
+ } else if (!mFalsingManager.isFalseTap(false, 0)) {
if (mSlideBackListener != null && mSlideBackListener.onSlideBack()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index b6ed3e5..3ac6937 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -167,6 +167,7 @@
private boolean mIgnoreXTouchSlop;
private boolean mExpandLatencyTracking;
private final PanelView mView;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
protected final Resources mResources;
protected final KeyguardStateController mKeyguardStateController;
protected final SysuiStatusBarStateController mStatusBarStateController;
@@ -235,12 +236,14 @@
FalsingManager falsingManager, DozeLog dozeLog,
KeyguardStateController keyguardStateController,
SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
LatencyTracker latencyTracker,
FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
AmbientState ambientState) {
mAmbientState = ambientState;
mView = view;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
@@ -1391,8 +1394,13 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- addMovement(event);
- endMotionEvent(event, x, y, false /* forceCancel */);
+ if (mStatusBarKeyguardViewManager.isBouncerShowing()
+ && mFalsingManager.isFalseTap(true, 0.5)) {
+ endMotionEvent(event, x, y, true /* forceCancel */);
+ } else {
+ addMovement(event);
+ endMotionEvent(event, x, y, false /* forceCancel */);
+ }
InteractionJankMonitor monitor = InteractionJankMonitor.getInstance();
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5083e33..01ada0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -76,7 +76,7 @@
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
* via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
* which is in turn, reported to this class by the current
- * {@link com.android.keyguard.KeyguardViewBase}.
+ * {@link com.android.keyguard.KeyguardViewController}.
*/
@SysUISingleton
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index ba58ed2..5cd3e57 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -52,6 +52,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
@@ -408,14 +409,15 @@
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
GarbageMonitor monitor
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
gm = monitor;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index a123269..1b6c612 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -480,8 +480,8 @@
@WMSingleton
@Provides
static StartingWindowController provideStartingWindowController(Context context,
- @ShellSplashscreenThread ShellExecutor executor) {
- return new StartingWindowController(context, executor);
+ @ShellAnimationThread ShellExecutor executor, TransactionPool pool) {
+ return new StartingWindowController(context, executor, pool);
}
//
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index c2ade81..0cf343c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -36,6 +36,8 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.classifier.FalsingCollectorFake;
import org.junit.Before;
import org.junit.Test;
@@ -69,6 +71,7 @@
private KeyguardMessageAreaController mKeyguardMessageAreaController;
@Mock
private LatencyTracker mLatencyTracker;
+ private final FalsingCollector mFalsingCollector = new FalsingCollectorFake();
private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController;
@@ -84,7 +87,7 @@
.thenReturn(mKeyguardMessageArea);
mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
- mKeyguardMessageAreaControllerFactory, mLatencyTracker) {
+ mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector) {
@Override
void resetState() {
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index c69ec1a..fc93ded 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -24,6 +24,8 @@
import com.android.internal.widget.LockPatternView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorFake
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -48,6 +50,7 @@
private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
@Mock
private lateinit var mLatencyTracker: LatencyTracker
+ private var mFalsingCollector: FalsingCollector = FalsingCollectorFake()
@Mock
private lateinit
var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
@@ -72,7 +75,7 @@
.thenReturn(mKeyguardMessageAreaController)
mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
- mLatencyTracker, mKeyguardMessageAreaControllerFactory)
+ mLatencyTracker, mFalsingCollector, mKeyguardMessageAreaControllerFactory)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 31cc7bb..33a0dcd0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -33,6 +33,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingCollectorFake;
+import com.android.systemui.classifier.SingleTapClassifier;
import org.junit.Before;
import org.junit.Test;
@@ -69,9 +70,12 @@
private LiftToActivateListener mLiftToactivateListener;
private FalsingCollector mFalsingCollector = new FalsingCollectorFake();
@Mock
+ private SingleTapClassifier mSingleTapClassifier;
+ @Mock
private View mDeleteButton;
@Mock
private View mOkButton;
+ private NumPadKey[] mButtons = new NumPadKey[]{};
private KeyguardPinBasedInputViewController mKeyguardPinViewController;
@@ -83,6 +87,7 @@
when(mPinBasedInputView.getPasswordTextViewId()).thenReturn(1);
when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry);
when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true);
+ when(mPinBasedInputView.getButtons()).thenReturn(mButtons);
when(mPinBasedInputView.findViewById(R.id.keyguard_message_area))
.thenReturn(mKeyguardMessageArea);
when(mPinBasedInputView.findViewById(R.id.delete_button))
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index b03dc94..49ba646 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -34,6 +34,8 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -83,6 +85,9 @@
private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
@Mock
private ConfigurationController mConfigurationController;
+ @Mock
+ private KeyguardViewController mKeyguardViewController;
+ private FalsingManager mFalsingManager = new FalsingManagerFake();
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@@ -96,7 +101,8 @@
mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, mKeyguardSecurityViewFlipperController,
- mConfigurationController).create(mSecurityCallback);
+ mConfigurationController, mKeyguardViewController, mFalsingManager)
+ .create(mSecurityCallback);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 0768618..d6f4958 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -246,20 +246,4 @@
// THEN the illumination is hidden
verify(mUdfpsView).stopIllumination();
}
-
- @Test
- public void registersAndUnregistersViewForCallbacks() throws RemoteException {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
- IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
- mFgExecutor.runAllReady();
- verify(mStatusBarStateController).addCallback(mUdfpsController.mStatusBarStateListener);
- verify(mStatusBar).addExpansionChangedListener(
- mUdfpsController.mStatusBarExpansionListener);
-
- mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
- mFgExecutor.runAllReady();
- verify(mStatusBarStateController).removeCallback(mUdfpsController.mStatusBarStateListener);
- verify(mStatusBar).removeExpansionChangedListener(
- mUdfpsController.mStatusBarExpansionListener);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
new file mode 100644
index 0000000..480b335
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.systemui.biometrics;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
+ // Dependencies
+ @Mock
+ private UdfpsKeyguardView mView;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private StatusBar mStatusBar;
+
+ private UdfpsKeyguardViewController mController;
+
+ // Capture listeners so that they can be used to send events
+ @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor;
+ private StatusBarStateController.StateListener mParentListener;
+ private StatusBarStateController.StateListener mDozeListener;
+
+ @Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
+ private StatusBar.ExpansionChangedListener mExpansionListener;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new UdfpsKeyguardViewController(
+ mView,
+ mStatusBarStateController,
+ mStatusBar);
+ }
+
+ @Test
+ public void testRegistersExpansionChangedListenerOnAttached() {
+ mController.onViewAttached();
+ captureExpansionListener();
+ }
+
+ @Test
+ public void testRegistersStatusBarStateListenersOnAttached() {
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+ }
+
+ @Test
+ public void testViewControllerQueriesSBStateOnAttached() {
+ mController.onViewAttached();
+ verify(mStatusBarStateController).getState();
+ verify(mStatusBarStateController).getDozeAmount();
+
+ final float dozeAmount = .88f;
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+ when(mStatusBarStateController.getDozeAmount()).thenReturn(dozeAmount);
+ captureStatusBarStateListeners();
+
+ mController.onViewAttached();
+ verify(mView).setPauseAuth(true);
+ verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount);
+ }
+
+ @Test
+ public void testListenersUnregisteredOnDetached() {
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+ captureExpansionListener();
+ mController.onViewDetached();
+
+ verify(mStatusBarStateController).removeCallback(mParentListener);
+ verify(mStatusBarStateController).removeCallback(mDozeListener);
+ verify(mStatusBar).removeExpansionChangedListener(mExpansionListener);
+ }
+
+ @Test
+ public void testDozeEventsSentToView() {
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+
+ final float linear = .55f;
+ final float eased = .65f;
+ mDozeListener.onDozeAmountChanged(linear, eased);
+
+ verify(mView).onDozeAmountChanged(linear, eased);
+ }
+
+ private void captureStatusBarStateListeners() {
+ verify(mStatusBarStateController, times(2)).addCallback(mStateListenerCaptor.capture());
+ List<StatusBarStateController.StateListener> stateListeners =
+ mStateListenerCaptor.getAllValues();
+ mParentListener = stateListeners.get(0);
+ mDozeListener = stateListeners.get(1);
+ }
+
+ private void captureExpansionListener() {
+ verify(mStatusBar).addExpansionChangedListener(mExpansionListenerCaptor.capture());
+ mExpansionListener = mExpansionListenerCaptor.getValue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 5709ce30..b232850 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -21,10 +21,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.anyDouble;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -93,7 +90,7 @@
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager,
mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier,
- mHistoryTracker, mFakeExecutor, DOUBLE_TAP_TIMEOUT_MS, false);
+ mHistoryTracker, false);
ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor =
@@ -161,25 +158,27 @@
public void testIsFalseTap_BasicCheck() {
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult);
- assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue();
+ assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isTrue();
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
- assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse();
+ assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isFalse();
}
@Test
public void testIsFalseTap_RobustCheck_NoFaceAuth() {
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
+ when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalsedResult);
+ when(mHistoryTracker.falseBelief()).thenReturn(1.0);
mFalsingDataProvider.setJustUnlockedWithFace(false);
- assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue();
+ assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isTrue();
}
@Test
public void testIsFalseTap_RobustCheck_FaceAuth() {
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
- assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse();
+ assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isFalse();
}
@Test
@@ -203,43 +202,29 @@
@Test
public void testHistory_singleTap() {
// When trying to classify single taps, we don't immediately add results to history.
- mBrightLineFalsingManager.isFalseTap(false);
+ mBrightLineFalsingManager.isFalseTap(false, 0);
mGestureCompleteListener.onGestureComplete(1000);
-
- verify(mHistoryTracker, never()).addResults(any(), anyLong());
-
- mFakeExecutor.advanceClockToNext();
- mFakeExecutor.runAllReady();
-
verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
}
@Test
public void testHistory_multipleSingleTaps() {
// When trying to classify single taps, we don't immediately add results to history.
- mBrightLineFalsingManager.isFalseTap(false);
+ mBrightLineFalsingManager.isFalseTap(false, 0);
mGestureCompleteListener.onGestureComplete(1000);
- mBrightLineFalsingManager.isFalseTap(false);
+ mBrightLineFalsingManager.isFalseTap(false, 0);
mGestureCompleteListener.onGestureComplete(2000);
-
- verify(mHistoryTracker, never()).addResults(any(), anyLong());
-
- mFakeExecutor.advanceClockToNext();
- mFakeExecutor.runNextReady();
verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
- reset(mHistoryTracker);
- mFakeExecutor.advanceClockToNext();
- mFakeExecutor.runNextReady();
verify(mHistoryTracker).addResults(anyCollection(), eq(2000L));
}
@Test
public void testHistory_doubleTap() {
// When trying to classify single taps, we don't immediately add results to history.
- mBrightLineFalsingManager.isFalseTap(false);
+ mBrightLineFalsingManager.isFalseTap(false, 0);
mGestureCompleteListener.onGestureComplete(1000);
// Before checking for double tap, we may check for single-tap on the second gesture.
- mBrightLineFalsingManager.isFalseTap(false);
+ mBrightLineFalsingManager.isFalseTap(false, 0);
mBrightLineFalsingManager.isFalseDoubleTap();
mGestureCompleteListener.onGestureComplete(2000);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
index 23ef865..dc79b88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -36,6 +36,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.sensors.ThresholdSensor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -56,6 +57,8 @@
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
+ private HistoryTracker mHistoryTracker;
+ @Mock
private ProximitySensor mProximitySensor;
@Mock
private SysuiStatusBarStateController mStatusBarStateController;
@@ -67,7 +70,8 @@
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager,
- mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController);
+ mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor,
+ mStatusBarStateController, new FakeSystemClock());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
index 01cce35..bb7545f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java
@@ -48,14 +48,14 @@
@Test
public void testNoDataNoPenalty() {
- assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0);
+ assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5);
assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0);
}
@Test
public void testOneResultFullConfidence() {
addResult(true, 1);
- assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1);
+ assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
}
@@ -64,8 +64,8 @@
addResult(true, 1);
addResult(false, 1);
- assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.5);
- assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.5);
+ assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(0.5);
+ assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.5);
}
@Test
@@ -73,20 +73,20 @@
addResult(true, 1);
addResult(true, 0);
- assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.75);
- assertThat(mHistoryTracker.falseConfidence()).isEqualTo(.75);
+ assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
+ assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(.75);
}
@Test
public void testDecay() {
addResult(true, 1);
- assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1);
+ assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
- mSystemClock.advanceTime(1000);
+ mSystemClock.advanceTime(9999);
- assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.1);
+ assertThat(mHistoryTracker.falseBelief()).isWithin(0.005).of(0.55);
assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
}
@@ -96,25 +96,25 @@
mSystemClock.advanceTime(1000);
addResult(false, .5);
- assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.17);
- assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.625);
+ assertThat(mHistoryTracker.falseBelief()).isWithin(0.01).of(0.74);
+ assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.625);
}
@Test
public void testCompleteDecay() {
addResult(true, 1);
- assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1);
+ assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1);
assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
- mSystemClock.advanceTime(2999);
+ mSystemClock.advanceTime(9999);
- assertThat(mHistoryTracker.falsePenalty()).isGreaterThan(0);
+ assertThat(mHistoryTracker.falseBelief()).isGreaterThan(0);
assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1);
mSystemClock.advanceTime(1);
- assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0);
+ assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5);
assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 1f9862c..3d4425c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -35,6 +35,7 @@
import org.junit.After
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -49,7 +50,7 @@
@SmallTest
@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class SeekBarViewModelTest : SysuiTestCase() {
private lateinit var viewModel: SeekBarViewModel
@@ -124,6 +125,7 @@
}
@Test
+ @Ignore
fun updateDurationWithPlayback() {
// GIVEN that the duration is contained within the metadata
val duration = 12000L
@@ -146,6 +148,7 @@
}
@Test
+ @Ignore
fun updateDurationWithoutPlayback() {
// GIVEN that the duration is contained within the metadata
val duration = 12000L
@@ -204,6 +207,7 @@
}
@Test
+ @Ignore
fun updateDurationNoMetadata() {
// GIVEN that the metadata is null
whenever(mockController.getMetadata()).thenReturn(null)
@@ -235,6 +239,7 @@
}
@Test
+ @Ignore
fun updateSeekAvailable() {
// GIVEN that seek is included in actions
val state = PlaybackState.Builder().run {
@@ -249,6 +254,7 @@
}
@Test
+ @Ignore
fun updateSeekNotAvailable() {
// GIVEN that seek is not included in actions
val state = PlaybackState.Builder().run {
@@ -303,6 +309,7 @@
}
@Test
+ @Ignore
fun onSeekProgressWithSeekStarting() {
val pos = 42L
with(viewModel) {
@@ -314,6 +321,7 @@
}
@Test
+ @Ignore
fun onProgressChangedFromUser() {
// WHEN user starts dragging the seek bar
val pos = 42
@@ -614,6 +622,7 @@
}
@Test
+ @Ignore
fun clearSeekBar() {
// GIVEN that the duration is contained within the metadata
val metadata = MediaMetadata.Builder().run {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index cfef5be..2ca8082 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -49,6 +49,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSFactory;
@@ -360,6 +361,7 @@
host,
mLooper.getLooper(),
new Handler(mLooper.getLooper()),
+ new FalsingManagerFake(),
mock(MetricsLogger.class),
mock(StatusBarStateController.class),
mock(ActivityStarter.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 3aa40de..b1c3d1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -32,6 +32,7 @@
import android.view.IWindowManager
import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -103,6 +104,7 @@
{ tileHost },
testableLooper.looper,
Handler(testableLooper.looper),
+ FalsingManagerFake(),
metricsLogger,
statusBarStateController,
activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 61a0d6c..937ab1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -26,6 +26,8 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -55,7 +57,9 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSEvent;
@@ -90,6 +94,7 @@
private QSTileHost mHost;
@Mock
private MetricsLogger mMetricsLogger;
+ private final FalsingManagerFake mFalsingManager = new FalsingManagerFake();
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
@@ -112,7 +117,7 @@
Handler mainHandler = new Handler(mTestableLooper.getLooper());
- mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler,
+ mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler, mFalsingManager,
mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger);
mTile.setTileSpec(SPEC);
}
@@ -144,6 +149,19 @@
}
@Test
+ public void testClick_falsing() {
+ mFalsingManager.setFalseRobustTap(true);
+ mTile.click();
+ mTestableLooper.processAllMessages();
+ assertThat(mTile.mClicked).isFalse();
+
+ mFalsingManager.setFalseRobustTap(false);
+ mTile.click();
+ mTestableLooper.processAllMessages();
+ assertThat(mTile.mClicked).isTrue();
+ }
+
+ @Test
public void testSecondaryClick_Metrics() {
mTile.secondaryClick();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK)));
@@ -360,17 +378,20 @@
}
private static class TileImpl extends QSTileImpl<QSTile.BooleanState> {
+ boolean mClicked;
+
protected TileImpl(
QSHost host,
Looper backgroundLooper,
Handler mainHandler,
+ FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger
) {
- super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
- activityStarter, qsLogger);
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
getState().state = Tile.STATE_ACTIVE;
}
@@ -381,7 +402,7 @@
@Override
protected void handleClick() {
-
+ mClicked = true;
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
index a9d10e9..9674a60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
@@ -10,6 +10,7 @@
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
@@ -73,6 +74,7 @@
qsHost,
testableLooper.looper,
Handler(testableLooper.looper),
+ FalsingManagerFake(),
metricsLogger,
statusBarStateController,
activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
index bcfc835..f17bd56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
@@ -24,6 +24,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
@@ -79,6 +80,7 @@
qsHost,
testableLooper.looper,
Handler(testableLooper.looper),
+ FalsingManagerFake(),
metricsLogger,
statusBarStateController,
activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 1c29a81..7d39361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -37,6 +37,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSTileHost;
@@ -101,6 +102,7 @@
mHost,
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
mMetricsLogger,
mStatusBarStateController,
mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index 9363b248..9fe5687 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -28,6 +28,7 @@
import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.dagger.ControlsComponent
@@ -323,6 +324,7 @@
qsHost,
testableLooper.looper,
Handler(testableLooper.looper),
+ FalsingManagerFake(),
metricsLogger,
statusBarStateController,
activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
index b37ac4a..99d028c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NfcTileTest.java
@@ -33,6 +33,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSTileHost;
@@ -84,6 +85,7 @@
mHost,
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
mMetricsLogger,
mStatusBarStateController,
mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index 880c290..6032e51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -33,6 +33,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSTileHost;
@@ -82,6 +83,7 @@
mHost,
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
mMetricsLogger,
mStatusBarStateController,
mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 6b54791..2215433 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -33,6 +33,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSTileHost;
@@ -81,6 +82,7 @@
mHost,
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
mMetricsLogger,
mStatusBarStateController,
mActivityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 2917dfa..8ec03d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -476,4 +476,11 @@
waitForIdleSync();
verify(mCallbacks).requestWindowMagnificationConnection(true);
}
+
+ @Test
+ public void testSetEnableNavigationBarLumaSampling() {
+ mCommandQueue.setNavigationBarLumaSamplingEnabled(1, true);
+ waitForIdleSync();
+ verify(mCallbacks).setNavigationBarLumaSamplingEnabled(eq(1), eq(true));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index a844d09..a60baa5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -45,6 +45,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -86,6 +87,7 @@
mRemoteInputQuickSettingsDisabler);
mDependency.injectTestDependency(LightBarController.class,
mLightBarController);
+ mDependency.injectMockDependency(NotificationRemoteInputManager.class);
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null,
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 8ccfad6..b00689b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -98,7 +98,6 @@
":platform-compat-overrides",
":display-device-config",
":display-layout-config",
- ":cec-config",
":device-state-config",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
@@ -119,7 +118,6 @@
],
required: [
- "cec_config.xml",
"gps_debug.conf",
"protolog.conf.json.gz",
],
@@ -185,11 +183,6 @@
}
prebuilt_etc {
- name: "cec_config.xml",
- src: "java/com/android/server/hdmi/cec_config.xml",
-}
-
-prebuilt_etc {
name: "gps_debug.conf",
src: "java/com/android/server/location/gnss/gps_debug.conf",
}
@@ -223,6 +216,7 @@
"java/com/android/server/TestNetworkService.java",
"java/com/android/server/connectivity/AutodestructReference.java",
"java/com/android/server/connectivity/ConnectivityConstants.java",
+ "java/com/android/server/connectivity/ConnectivityResources.java",
"java/com/android/server/connectivity/DnsManager.java",
"java/com/android/server/connectivity/KeepaliveTracker.java",
"java/com/android/server/connectivity/LingerMonitor.java",
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index bb4bbd5..1e608f5 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -918,19 +918,7 @@
int opts = parseOptions(shell);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
- if (!mUpdatesStopped) {
- copy(mLastHealthInfo, mHealthInfo);
- }
- mHealthInfo.chargerAcOnline = false;
- mHealthInfo.chargerUsbOnline = false;
- mHealthInfo.chargerWirelessOnline = false;
- final long ident = Binder.clearCallingIdentity();
- try {
- mUpdatesStopped = true;
- processValuesFromShellLocked(pw, opts);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
} break;
case "set": {
int opts = parseOptions(shell);
@@ -990,7 +978,8 @@
final long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
- processValuesFromShellLocked(pw, opts);
+ processValuesLocked(
+ /* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1004,30 +993,12 @@
int opts = parseOptions(shell);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
- final long ident = Binder.clearCallingIdentity();
- try {
- if (mUpdatesStopped) {
- mUpdatesStopped = false;
- copy(mHealthInfo, mLastHealthInfo);
- processValuesFromShellLocked(pw, opts);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- if (mBatteryInputSuspended) {
- PowerProperties.battery_input_suspended(false);
- mBatteryInputSuspended = false;
- }
+ resetBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
} break;
case "suspend_input": {
- if (!Build.IS_DEBUGGABLE) {
- throw new SecurityException(
- "battery suspend_input is only supported on debuggable builds");
- }
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
- PowerProperties.battery_input_suspended(true);
- mBatteryInputSuspended = true;
+ suspendBatteryInput();
} break;
default:
return shell.handleDefaultCommands(cmd);
@@ -1035,9 +1006,59 @@
return 0;
}
- private void processValuesFromShellLocked(PrintWriter pw, int opts) {
- processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
- if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ private void setChargerAcOnline(boolean online, boolean forceUpdate) {
+ if (!mUpdatesStopped) {
+ copy(mLastHealthInfo, mHealthInfo);
+ }
+ mHealthInfo.chargerAcOnline = online;
+ mUpdatesStopped = true;
+ Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate));
+ }
+
+ private void setBatteryLevel(int level, boolean forceUpdate) {
+ if (!mUpdatesStopped) {
+ copy(mLastHealthInfo, mHealthInfo);
+ }
+ mHealthInfo.batteryLevel = level;
+ mUpdatesStopped = true;
+ Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate));
+ }
+
+ private void unplugBattery(boolean forceUpdate, PrintWriter pw) {
+ if (!mUpdatesStopped) {
+ copy(mLastHealthInfo, mHealthInfo);
+ }
+ mHealthInfo.chargerAcOnline = false;
+ mHealthInfo.chargerUsbOnline = false;
+ mHealthInfo.chargerWirelessOnline = false;
+ mUpdatesStopped = true;
+ Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw));
+ }
+
+ private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) {
+ if (mUpdatesStopped) {
+ mUpdatesStopped = false;
+ copy(mHealthInfo, mLastHealthInfo);
+ Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw));
+ }
+ if (mBatteryInputSuspended) {
+ PowerProperties.battery_input_suspended(false);
+ mBatteryInputSuspended = false;
+ }
+ }
+
+ private void suspendBatteryInput() {
+ if (!Build.IS_DEBUGGABLE) {
+ throw new SecurityException(
+ "battery suspend_input is only supported on debuggable builds");
+ }
+ PowerProperties.battery_input_suspended(true);
+ mBatteryInputSuspended = true;
+ }
+
+ private void processValuesLocked(boolean forceUpdate, @Nullable PrintWriter pw) {
+ processValuesLocked(forceUpdate);
+ if (pw != null && forceUpdate) {
pw.println(mSequence);
}
}
@@ -1363,6 +1384,41 @@
return mInvalidCharger;
}
}
+
+ @Override
+ public void setChargerAcOnline(boolean online, boolean forceUpdate) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+ BatteryService.this.setChargerAcOnline(online, forceUpdate);
+ }
+
+ @Override
+ public void setBatteryLevel(int level, boolean forceUpdate) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+ BatteryService.this.setBatteryLevel(level, forceUpdate);
+ }
+
+ @Override
+ public void unplugBattery(boolean forceUpdate) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+ BatteryService.this.unplugBattery(forceUpdate, /* printWriter= */ null);
+ }
+
+ @Override
+ public void resetBattery(boolean forceUpdate) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+ BatteryService.this.resetBattery(forceUpdate, /* printWriter= */ null);
+ }
+
+ @Override
+ public void suspendBatteryInput() {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, /* message= */ null);
+ BatteryService.this.suspendBatteryInput();
+ }
}
/**
@@ -1539,6 +1595,8 @@
if (Objects.equals(newService, oldService)) return;
Slog.i(TAG, "health: new instance registered " + mInstanceName);
+ // #init() may be called with null callback. Skip null callbacks.
+ if (mCallback == null) return;
mCallback.onRegistration(oldService, newService, mInstanceName);
} catch (NoSuchElementException | RemoteException ex) {
Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 78853c7..b4fcaee 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -85,6 +85,7 @@
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.DataStallReportParcelable;
import android.net.DnsResolverServiceManager;
import android.net.ICaptivePortal;
@@ -187,10 +188,8 @@
import android.util.SparseIntArray;
import com.android.connectivity.aidl.INetworkAgent;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
@@ -202,6 +201,7 @@
import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.net.module.util.PermissionUtils;
import com.android.server.connectivity.AutodestructReference;
+import com.android.server.connectivity.ConnectivityResources;
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
import com.android.server.connectivity.KeepaliveTracker;
@@ -317,6 +317,7 @@
private boolean mRestrictBackground;
private final Context mContext;
+ private final ConnectivityResources mResources;
// The Context is created for UserHandle.ALL.
private final Context mUserAllContext;
private final Dependencies mDeps;
@@ -344,8 +345,7 @@
private String mCurrentTcpBufferSizes;
private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
- new Class[] { AsyncChannel.class, ConnectivityService.class, NetworkAgent.class,
- NetworkAgentInfo.class });
+ new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class });
private enum ReapUnvalidatedNetworks {
// Tear down networks that have no chance (e.g. even if validated) of becoming
@@ -605,7 +605,6 @@
private Intent mInitialBroadcast;
private PowerManager.WakeLock mNetTransitionWakeLock;
- private int mNetTransitionWakeLockTimeout;
private final PowerManager.WakeLock mPendingIntentWakeLock;
// A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
@@ -1013,6 +1012,13 @@
}
/**
+ * Get the {@link ConnectivityResources} to use in ConnectivityService.
+ */
+ public ConnectivityResources getResources(@NonNull Context ctx) {
+ return new ConnectivityResources(ctx);
+ }
+
+ /**
* Create a HandlerThread to use in ConnectivityService.
*/
public HandlerThread makeHandlerThread() {
@@ -1094,13 +1100,15 @@
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
mContext = Objects.requireNonNull(context, "missing Context");
+ mResources = deps.getResources(mContext);
mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultRequest();
mDefaultRequest = new NetworkRequestInfo(
- defaultInternetRequest, null, new Binder(),
+ defaultInternetRequest, null,
+ new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest);
@@ -1154,8 +1162,6 @@
final PowerManager powerManager = (PowerManager) context.getSystemService(
Context.POWER_SERVICE);
mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_networkTransitionTimeout);
mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
@@ -1222,10 +1228,6 @@
}
}
- mWolSupportedInterfaces = new ArraySet(
- mContext.getResources().getStringArray(
- com.android.internal.R.array.config_wakeonlan_supported_interfaces));
-
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -1356,7 +1358,9 @@
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- networkRequest, null, new Binder(),
+ networkRequest, null,
+ new Binder(),
+ NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */));
} else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
@@ -1717,8 +1721,8 @@
result.put(
nai.network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName,
- callingAttributionTag));
+ nc, false /* includeLocationSensitiveInfo */,
+ mDeps.getCallingUid(), callingPackageName, callingAttributionTag));
}
}
@@ -1731,7 +1735,9 @@
result.put(
network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName,
+ nc,
+ false /* includeLocationSensitiveInfo */,
+ mDeps.getCallingUid(), callingPackageName,
callingAttributionTag));
}
}
@@ -1813,6 +1819,7 @@
enforceAccessPermission();
return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
+ false /* includeLocationSensitiveInfo */,
mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
@@ -1846,8 +1853,8 @@
@VisibleForTesting
@Nullable
NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName,
- @Nullable String callingAttributionTag) {
+ @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo,
+ int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) {
if (nc == null) {
return null;
}
@@ -1855,7 +1862,9 @@
final NetworkCapabilities newNc;
// Avoid doing location permission check if the transport info has no location sensitive
// data.
- if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
+ if (includeLocationSensitiveInfo
+ && nc.getTransportInfo() != null
+ && nc.getTransportInfo().hasLocationSensitiveFields()) {
hasLocationPermission =
hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
newNc = new NetworkCapabilities(nc, hasLocationPermission);
@@ -1872,6 +1881,16 @@
// Owner UIDs already checked above. No need to re-check.
return newNc;
}
+ // If the caller does not want location sensitive data & target SDK >= S, then mask info.
+ // Else include the owner UID iff the caller has location permission to provide backwards
+ // compatibility for older apps.
+ if (!includeLocationSensitiveInfo
+ && isTargetSdkAtleast(
+ Build.VERSION_CODES.S, callerUid, callerPkgName)) {
+ newNc.setOwnerUid(INVALID_UID);
+ return newNc;
+ }
+
if (hasLocationPermission == null) {
// Location permission not checked yet, check now for masking owner UID.
hasLocationPermission =
@@ -2890,22 +2909,6 @@
super(looper);
}
- private boolean maybeHandleAsyncChannelMessage(Message msg) {
- switch (msg.what) {
- default:
- return false;
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
- handleAsyncChannelHalfConnect(msg);
- break;
- }
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
- handleAsyncChannelDisconnected(msg);
- break;
- }
- }
- return true;
- }
-
private void maybeHandleNetworkAgentMessage(Message msg) {
final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj;
final NetworkAgentInfo nai = arg.first;
@@ -3197,8 +3200,7 @@
@Override
public void handleMessage(Message msg) {
- if (!maybeHandleAsyncChannelMessage(msg)
- && !maybeHandleNetworkMonitorMessage(msg)
+ if (!maybeHandleNetworkMonitorMessage(msg)
&& !maybeHandleNetworkAgentInfoMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
}
@@ -3462,21 +3464,6 @@
return false;
}
- private void handleAsyncChannelHalfConnect(Message msg) {
- ensureRunningOnConnectivityServiceThread();
- if (mNetworkProviderInfos.containsKey(msg.replyTo)) {
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- if (VDBG) log("NetworkFactory connected");
- // Finish setting up the full connection
- NetworkProviderInfo npi = mNetworkProviderInfos.get(msg.replyTo);
- sendAllRequestsToProvider(npi);
- } else {
- loge("Error connecting NetworkFactory");
- mNetworkProviderInfos.remove(msg.obj);
- }
- }
- }
-
private void handleNetworkAgentRegistered(Message msg) {
final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
if (!mNetworkAgentInfos.contains(nai)) {
@@ -3507,14 +3494,6 @@
}
}
- // This is a no-op if it's called with a message designating a provider that has
- // already been destroyed, because its reference will not be found in the relevant
- // maps.
- private void handleAsyncChannelDisconnected(Message msg) {
- NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo);
- if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name);
- }
-
// Destroys a network, remove references to it from the internal state managed by
// ConnectivityService, free its interfaces and clean up.
// Must be called on the Handler thread.
@@ -4623,7 +4602,9 @@
}
mWakelockLogs.log("ACQUIRE for " + forWhom);
Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
- mHandler.sendMessageDelayed(msg, mNetTransitionWakeLockTimeout);
+ final int lockTimeout = mResources.get().getInteger(
+ com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
+ mHandler.sendMessageDelayed(msg, lockTimeout);
}
// Called when we gain a new default network to release the network transition wakelock in a
@@ -5155,8 +5136,8 @@
private final IBinder.DeathRecipient mDeathRecipient;
public final int providerId;
- NetworkProviderInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
- int providerId, @NonNull IBinder.DeathRecipient deathRecipient) {
+ NetworkProviderInfo(String name, Messenger messenger, int providerId,
+ @NonNull IBinder.DeathRecipient deathRecipient) {
this.name = name;
this.messenger = messenger;
this.providerId = providerId;
@@ -5250,6 +5231,7 @@
private final IBinder mBinder;
final int mPid;
final int mUid;
+ final @NetworkCallback.Flag int mCallbackFlags;
@Nullable
final String mCallingAttributionTag;
// In order to preserve the mapping of NetworkRequest-to-callback when apps register
@@ -5297,17 +5279,26 @@
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ /**
+ * Location sensitive data not included in pending intent. Only included in
+ * {@link NetworkCallback}.
+ */
+ mCallbackFlags = NetworkCallback.FLAG_NONE;
mCallingAttributionTag = callingAttributionTag;
}
NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
- @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, m, binder, callingAttributionTag);
+ @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @Nullable String callingAttributionTag) {
+ this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag);
}
NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
- @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
+ @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @Nullable String callingAttributionTag) {
super();
ensureAllNetworkRequestsHaveType(r);
mRequests = initializeRequests(r);
@@ -5318,6 +5309,7 @@
mUid = mDeps.getCallingUid();
mPendingIntent = null;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
try {
@@ -5359,6 +5351,7 @@
mUid = nri.mUid;
mPendingIntent = nri.mPendingIntent;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
}
@@ -5408,7 +5401,8 @@
+ " callback request Id: "
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
- + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
+ + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
+ + "callback flags: " + mCallbackFlags;
}
}
@@ -5492,13 +5486,13 @@
}
}
- private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) {
- final UserHandle user = UserHandle.getUserHandleForUid(mDeps.getCallingUid());
+ private boolean isTargetSdkAtleast(int version, int callingUid,
+ @NonNull String callingPackageName) {
+ final UserHandle user = UserHandle.getUserHandleForUid(callingUid);
final PackageManager pm =
mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
try {
- final int callingVersion = pm.getApplicationInfo(
- callingPackageName, 0 /* flags */).targetSdkVersion;
+ final int callingVersion = pm.getTargetSdkVersion(callingPackageName);
if (callingVersion < version) return false;
} catch (PackageManager.NameNotFoundException e) { }
return true;
@@ -5507,10 +5501,11 @@
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
- int legacyType, @NonNull String callingPackageName,
+ int legacyType, int callbackFlags, @NonNull String callingPackageName,
@Nullable String callingAttributionTag) {
if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
- if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) {
+ if (isTargetSdkAtleast(Build.VERSION_CODES.M, mDeps.getCallingUid(),
+ callingPackageName)) {
throw new SecurityException("Insufficient permissions to specify legacy type");
}
}
@@ -5547,6 +5542,8 @@
// request if the app changes network state. http://b/29964605
enforceMeteredApnPolicy(networkCapabilities);
break;
+ case TRACK_BEST:
+ throw new UnsupportedOperationException("Not implemented yet");
default:
throw new IllegalArgumentException("Unsupported request type " + reqType);
}
@@ -5570,7 +5567,7 @@
final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
final NetworkRequestInfo nri = getNriToRegister(
- networkRequest, messenger, binder, callingAttributionTag);
+ networkRequest, messenger, binder, callbackFlags, callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
@@ -5605,6 +5602,7 @@
*/
private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr,
@Nullable final Messenger msgr, @Nullable final IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
final List<NetworkRequest> requests;
if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
@@ -5613,7 +5611,8 @@
} else {
requests = Collections.singletonList(nr);
}
- return new NetworkRequestInfo(requests, nr, msgr, binder, callingAttributionTag);
+ return new NetworkRequestInfo(
+ requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
}
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
@@ -5739,8 +5738,9 @@
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, IBinder binder, @NonNull String callingPackageName,
- @Nullable String callingAttributionTag) {
+ Messenger messenger, IBinder binder,
+ @NetworkCallback.Flag int callbackFlags,
+ @NonNull String callingPackageName, @NonNull String callingAttributionTag) {
final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
@@ -5761,7 +5761,8 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
+ new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags,
+ callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5830,8 +5831,7 @@
public int registerNetworkProvider(Messenger messenger, String name) {
enforceNetworkFactoryOrSettingsPermission();
NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger,
- null /* asyncChannel */, nextNetworkProviderId(),
- () -> unregisterNetworkProvider(messenger));
+ nextNetworkProviderId(), () -> unregisterNetworkProvider(messenger));
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi));
return npi.providerId;
}
@@ -6518,6 +6518,11 @@
}
private void updateWakeOnLan(@NonNull LinkProperties lp) {
+ if (mWolSupportedInterfaces == null) {
+ mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray(
+ com.android.connectivity.resources.R.array
+ .config_wakeonlan_supported_interfaces));
+ }
lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
}
@@ -7090,6 +7095,8 @@
if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
putParcelable(bundle, networkAgent.network);
}
+ final boolean includeLocationSensitiveInfo =
+ (nri.mCallbackFlags & NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) != 0;
switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: {
final NetworkCapabilities nc =
@@ -7098,7 +7105,8 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, nri.mUid, nrForCallback.getRequestorPackageName(),
+ nc, includeLocationSensitiveInfo, nri.mUid,
+ nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
@@ -7118,7 +7126,8 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, nri.mUid, nrForCallback.getRequestorPackageName(),
+ netCap, includeLocationSensitiveInfo, nri.mUid,
+ nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
break;
}
@@ -8075,8 +8084,8 @@
@Override
public String getCaptivePortalServerUrl() {
enforceNetworkStackOrSettingsPermission();
- String settingUrl = mContext.getResources().getString(
- R.string.config_networkCaptivePortalServerUrl);
+ String settingUrl = mResources.get().getString(
+ com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
if (!TextUtils.isEmpty(settingUrl)) {
return settingUrl;
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 81d4b9d..4c3c6ef 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -56,6 +56,7 @@
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Range;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -756,13 +757,9 @@
}
}
- // These values have been reserved in NetIdManager
- @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00;
-
- public static final int TUN_INTF_NETID_RANGE = 0x0400;
-
private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray();
- private int mNextTunnelNetIdIndex = 0;
+ final Range<Integer> mNetIdRange = ConnectivityManager.getIpSecNetIdRange();
+ private int mNextTunnelNetId = mNetIdRange.getLower();
/**
* Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces
@@ -775,11 +772,13 @@
*/
@VisibleForTesting
int reserveNetId() {
+ final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1;
synchronized (mTunnelNetIds) {
- for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) {
- int index = mNextTunnelNetIdIndex;
- int netId = index + TUN_INTF_NETID_START;
- if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0;
+ for (int i = 0; i < range; i++) {
+ final int netId = mNextTunnelNetId;
+ if (++mNextTunnelNetId > mNetIdRange.getUpper()) {
+ mNextTunnelNetId = mNetIdRange.getLower();
+ }
if (!mTunnelNetIds.get(netId)) {
mTunnelNetIds.put(netId, true);
return netId;
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
index 097fb3a..61925c8 100644
--- a/services/core/java/com/android/server/NetIdManager.java
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.annotation.NonNull;
+import android.net.ConnectivityManager;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
@@ -31,7 +32,7 @@
// Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
public static final int MIN_NET_ID = 100; // some reserved marks
// Top IDs reserved by IpSecService
- public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
+ public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1;
@GuardedBy("mNetIdInUse")
private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index f2782f6..18d47c6 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -51,6 +51,7 @@
import android.hardware.ISensorPrivacyListener;
import android.hardware.ISensorPrivacyManager;
import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManagerInternal;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -67,6 +68,7 @@
import android.service.SensorPrivacyUserProto;
import android.text.Html;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -80,6 +82,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.XmlUtils;
@@ -137,6 +140,8 @@
private final ActivityManager mActivityManager;
private final ActivityTaskManager mActivityTaskManager;
+ private SensorPrivacyManagerInternalImpl mSensorPrivacyManagerInternal;
+
public SensorPrivacyService(Context context) {
super(context);
mUserManagerInternal = getLocalService(UserManagerInternal.class);
@@ -148,6 +153,9 @@
@Override
public void onStart() {
publishBinderService(Context.SENSOR_PRIVACY_SERVICE, mSensorPrivacyServiceImpl);
+ mSensorPrivacyManagerInternal = new SensorPrivacyManagerInternalImpl();
+ publishLocalService(SensorPrivacyManagerInternal.class,
+ mSensorPrivacyManagerInternal);
}
class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements
@@ -1108,6 +1116,7 @@
}
public void handleSensorPrivacyChanged(int userId, int sensor, boolean enabled) {
+ mSensorPrivacyManagerInternal.dispatch(userId, sensor, enabled);
SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
mIndividualSensorListeners.get(userId);
if (listenersForUser == null) {
@@ -1168,4 +1177,87 @@
c.accept(userIds[i]);
}
}
+
+ private class SensorPrivacyManagerInternalImpl extends SensorPrivacyManagerInternal {
+
+ private ArrayMap<Integer, ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>>>
+ mListeners = new ArrayMap<>();
+ private ArrayMap<Integer, ArraySet<OnUserSensorPrivacyChangedListener>> mAllUserListeners =
+ new ArrayMap<>();
+
+ private final Object mLock = new Object();
+
+ private void dispatch(int userId, int sensor, boolean enabled) {
+ synchronized (mLock) {
+ ArraySet<OnUserSensorPrivacyChangedListener> allUserSensorListeners =
+ mAllUserListeners.get(sensor);
+ if (allUserSensorListeners != null) {
+ for (int i = 0; i < allUserSensorListeners.size(); i++) {
+ OnUserSensorPrivacyChangedListener listener =
+ allUserSensorListeners.valueAt(i);
+ BackgroundThread.getHandler().post(() ->
+ listener.onSensorPrivacyChanged(userId, enabled));
+ }
+ }
+
+ ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>> userSensorListeners =
+ mListeners.get(userId);
+ if (userSensorListeners != null) {
+ ArraySet<OnSensorPrivacyChangedListener> sensorListeners =
+ userSensorListeners.get(sensor);
+ if (sensorListeners != null) {
+ for (int i = 0; i < sensorListeners.size(); i++) {
+ OnSensorPrivacyChangedListener listener = sensorListeners.valueAt(i);
+ BackgroundThread.getHandler().post(() ->
+ listener.onSensorPrivacyChanged(enabled));
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isSensorPrivacyEnabled(int userId, int sensor) {
+ return SensorPrivacyService.this
+ .mSensorPrivacyServiceImpl.isIndividualSensorPrivacyEnabled(userId, sensor);
+ }
+
+ @Override
+ public void addSensorPrivacyListener(int userId, int sensor,
+ OnSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ ArrayMap<Integer, ArraySet<OnSensorPrivacyChangedListener>> userSensorListeners =
+ mListeners.get(userId);
+ if (userSensorListeners == null) {
+ userSensorListeners = new ArrayMap<>();
+ mListeners.put(userId, userSensorListeners);
+ }
+
+ ArraySet<OnSensorPrivacyChangedListener> sensorListeners =
+ userSensorListeners.get(sensor);
+ if (sensorListeners == null) {
+ sensorListeners = new ArraySet<>();
+ userSensorListeners.put(sensor, sensorListeners);
+ }
+
+ sensorListeners.add(listener);
+ }
+ }
+
+ @Override
+ public void addSensorPrivacyListenerForAllUsers(int sensor,
+ OnUserSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ ArraySet<OnUserSensorPrivacyChangedListener> sensorListeners =
+ mAllUserListeners.get(sensor);
+ if (sensorListeners == null) {
+ sensorListeners = new ArraySet<>();
+ mAllUserListeners.put(sensor, sensorListeners);
+ }
+
+ sensorListeners.add(listener);
+ }
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a9904ba..5adbdff 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -318,7 +318,8 @@
private int[] mDataEnabledReason;
- private Map<Integer, Long> mAllowedNetworkTypesList;
+ private int[] mAllowedNetworkTypeReason;
+ private long[] mAllowedNetworkTypeValue;
/**
* Per-phone map of precise data connection state. The key of the map is the pair of transport
@@ -383,7 +384,8 @@
private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) {
return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
|| events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
- || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED);
+ || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
}
private static final int MSG_USER_SWITCHED = 1;
@@ -527,6 +529,8 @@
mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones);
mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
+ mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
+ mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones);
// ds -> ss switch.
if (mNumPhones < oldNumPhones) {
@@ -571,6 +575,8 @@
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+ mAllowedNetworkTypeReason[i] = -1;
+ mAllowedNetworkTypeValue[i] = -1;
}
}
@@ -630,9 +636,11 @@
mBarringInfo = new ArrayList<>();
mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
mPhysicalChannelConfigs = new ArrayList<>();
- mAllowedNetworkTypesList = new HashMap<>();
+ mAllowedNetworkTypeReason = new int[numPhones];
+ mAllowedNetworkTypeValue = new long[numPhones];
mIsDataEnabled = new boolean[numPhones];
mDataEnabledReason = new int[numPhones];
+
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -665,6 +673,8 @@
mIsDataEnabled[i] = false;
mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
+ mAllowedNetworkTypeReason[i] = -1;
+ mAllowedNetworkTypeValue[i] = -1;
}
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -1172,14 +1182,6 @@
remove(r.binder);
}
}
- if (events.contains(
- TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) {
- try {
- r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
- }
}
}
}
@@ -2454,18 +2456,19 @@
*
* @param phoneId the phone id.
* @param subId the subId.
- * @param allowedNetworkTypesList Map associating all allowed network type reasons with reason's
- * allowed network type values.
+ * @param reason the allowed network type reason.
+ * @param allowedNetworkType the allowed network type value.
*/
- public void notifyAllowedNetworkTypesChanged(int phoneId, int subId,
- Map allowedNetworkTypesList) {
+ public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, int reason,
+ long allowedNetworkType) {
if (!checkNotifyPermission("notifyAllowedNetworkTypesChanged()")) {
return;
}
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- mAllowedNetworkTypesList = allowedNetworkTypesList;
+ mAllowedNetworkTypeReason[phoneId] = reason;
+ mAllowedNetworkTypeValue[phoneId] = allowedNetworkType;
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
@@ -2473,10 +2476,12 @@
&& idMatch(r.subId, subId, phoneId)) {
try {
if (VDBG) {
- log("notifyAllowedNetworkTypesChanged: AllowedNetworkTypesList= "
- + mAllowedNetworkTypesList.toString());
+ log("notifyAllowedNetworkTypesChanged: reason= " + reason
+ + ", allowed network type:"
+ + TelephonyManager.convertNetworkTypeBitmaskToString(
+ allowedNetworkType));
}
- r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList);
+ r.callback.onAllowedNetworkTypesChanged(reason, allowedNetworkType);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2531,6 +2536,8 @@
pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]);
pw.println("mIsDataEnabled=" + mIsDataEnabled);
pw.println("mDataEnabledReason=" + mDataEnabledReason);
+ pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]);
+ pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]);
pw.decreaseIndent();
}
pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index cd3892d..140f24f 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -666,6 +666,10 @@
@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
requireNonNull(listener, "listener was null");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "Must have permission NETWORK_FACTORY to unregister a policy listener");
+
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
PolicyListenerBinderDeath listenerBinderDeath =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8ea6194..06a1abb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -44,11 +44,11 @@
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
-import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.BLUETOOTH_UID;
@@ -273,6 +273,9 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
+import android.os.incremental.IIncrementalService;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalMetrics;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
@@ -7697,18 +7700,32 @@
*/
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
- boolean isPackageLoading = false;
+ boolean isIncremental = false;
+ float loadingProgress = 1;
+ long millisSinceOldestPendingRead = 0;
// Notify package manager service to possibly update package state
if (r != null && r.info != null && r.info.packageName != null) {
+ final String codePath = r.info.getCodePath();
mPackageManagerInt.notifyPackageCrashOrAnr(r.info.packageName);
IncrementalStatesInfo incrementalStatesInfo =
mPackageManagerInt.getIncrementalStatesInfo(r.info.packageName, r.uid,
r.userId);
- isPackageLoading = incrementalStatesInfo.isLoading();
- if (isPackageLoading) {
- // Report in the main log that the package is still loading
- Slog.e(TAG, "App crashed when package " + r.info.packageName + " is "
- + ((int) (incrementalStatesInfo.getProgress() * 100)) + "% loaded.");
+ if (incrementalStatesInfo != null) {
+ loadingProgress = incrementalStatesInfo.getProgress();
+ }
+ isIncremental = IncrementalManager.isIncrementalPath(codePath);
+ if (isIncremental) {
+ // Report in the main log about the incremental package
+ Slog.e(TAG, "App crashed on incremental package " + r.info.packageName
+ + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
+ final IBinder incrementalService = ServiceManager.getService(
+ Context.INCREMENTAL_SERVICE);
+ if (incrementalService != null) {
+ final IncrementalManager incrementalManager = new IncrementalManager(
+ IIncrementalService.Stub.asInterface(incrementalService));
+ IncrementalMetrics metrics = incrementalManager.getMetrics(codePath);
+ millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead();
+ }
}
}
@@ -7737,7 +7754,7 @@
processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER
: (r != null) ? r.getProcessClassEnum()
: ServerProtoEnums.ERROR_SOURCE_UNKNOWN,
- isPackageLoading
+ isIncremental, loadingProgress, millisSinceOldestPendingRead
);
final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index dbfa7f3..6b9fc07 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -32,6 +32,7 @@
import android.net.INetworkManagementEventObserver;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.os.BatteryManagerInternal;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.BatteryUsageStats;
@@ -184,6 +185,8 @@
}
};
+ private BatteryManagerInternal mBatteryManagerInternal;
+
private void populatePowerEntityMaps() {
PowerEntity[] entities = mPowerStatsInternal.getPowerEntityInfo();
if (entities == null) {
@@ -370,6 +373,7 @@
Slog.e(TAG, "Could not register PowerStatsInternal");
}
}
+ mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
Watchdog.getInstance().addMonitor(this);
@@ -2715,4 +2719,44 @@
});
}
}
+
+ /**
+ * Sets battery AC charger to enabled/disabled, and freezes the battery state.
+ */
+ @Override
+ public void setChargerAcOnline(boolean online, boolean forceUpdate) {
+ mBatteryManagerInternal.setChargerAcOnline(online, forceUpdate);
+ }
+
+ /**
+ * Sets battery level, and freezes the battery state.
+ */
+ @Override
+ public void setBatteryLevel(int level, boolean forceUpdate) {
+ mBatteryManagerInternal.setBatteryLevel(level, forceUpdate);
+ }
+
+ /**
+ * Unplugs battery, and freezes the battery state.
+ */
+ @Override
+ public void unplugBattery(boolean forceUpdate) {
+ mBatteryManagerInternal.unplugBattery(forceUpdate);
+ }
+
+ /**
+ * Unfreezes battery state, returning to current hardware values.
+ */
+ @Override
+ public void resetBattery(boolean forceUpdate) {
+ mBatteryManagerInternal.resetBattery(forceUpdate);
+ }
+
+ /**
+ * Suspend charging even if plugged in.
+ */
+ @Override
+ public void suspendBatteryInput() {
+ mBatteryManagerInternal.suspendBatteryInput();
+ }
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 81c4c86..e79f096 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1416,7 +1416,7 @@
}
}
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
- r.requiredPermissions != null && r.requiredPermissions.length > 0) {
+ r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
try {
@@ -1424,7 +1424,7 @@
checkPermission(requiredPermission,
info.activityInfo.applicationInfo.packageName,
UserHandle
- .getUserId(info.activityInfo.applicationInfo.uid));
+ .getUserId(info.activityInfo.applicationInfo.uid));
} catch (RemoteException e) {
perm = PackageManager.PERMISSION_DENIED;
}
@@ -1439,36 +1439,18 @@
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
- if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
- && mService.getAppOpsManager().noteOpNoThrow(appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
- null /* default featureId */,
- "Broadcast delivered to " + info.activityInfo.name)
- != AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
- + r.intent + " to "
- + component.flattenToShortString()
- + " requires appop " + AppOpsManager.permissionToOp(
- requiredPermission)
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
- break;
+ if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
+ if (!noteOpForManifestReceiver(appOp, r, info, component)) {
+ skip = true;
+ break;
+ }
}
}
}
- if (!skip && r.appOp != AppOpsManager.OP_NONE
- && mService.getAppOpsManager().noteOpNoThrow(r.appOp,
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
- null /* default featureId */, "Broadcast delivered to " + info.activityInfo.name)
- != AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
- + r.intent + " to "
- + component.flattenToShortString()
- + " requires appop " + AppOpsManager.opToName(r.appOp)
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
+ if (!skip && r.appOp != AppOpsManager.OP_NONE) {
+ if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {
+ skip = true;
+ }
}
boolean isSingleton = false;
try {
@@ -1717,6 +1699,40 @@
mPendingBroadcastRecvIndex = recIdx;
}
+ private boolean noteOpForManifestReceiver(int appOp, BroadcastRecord r, ResolveInfo info,
+ ComponentName component) {
+ if (info.activityInfo.attributionTags == null) {
+ return noteOpForManifestReceiverInner(appOp, r, info, component, null);
+ } else {
+ // Attribution tags provided, noteOp each tag
+ for (String tag : info.activityInfo.attributionTags) {
+ if (!noteOpForManifestReceiverInner(appOp, r, info, component, tag)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private boolean noteOpForManifestReceiverInner(int appOp, BroadcastRecord r, ResolveInfo info,
+ ComponentName component, String tag) {
+ if (mService.getAppOpsManager().noteOpNoThrow(appOp,
+ info.activityInfo.applicationInfo.uid,
+ info.activityInfo.packageName,
+ tag,
+ "Broadcast delivered to " + info.activityInfo.name)
+ != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(TAG, "Appop Denial: receiving "
+ + r.intent + " to "
+ + component.flattenToShortString()
+ + " requires appop " + AppOpsManager.opToName(appOp)
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ return false;
+ }
+ return true;
+ }
+
private void maybeAddAllowBackgroundActivityStartsToken(ProcessRecord proc, BroadcastRecord r) {
if (r == null || proc == null || !r.allowBackgroundActivityStarts) {
return;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index d03a47a..93f30cc 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -26,12 +26,18 @@
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.PackageManagerInternal;
+import android.os.IBinder;
import android.os.Message;
import android.os.Process;
+import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.incremental.IIncrementalService;
+import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalMetrics;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;
@@ -294,14 +300,31 @@
}
// Check if package is still being loaded
- boolean isPackageLoading = false;
+ boolean isIncremental = false;
+ float loadingProgress = 1;
+ long millisSinceOldestPendingRead = 0;
final PackageManagerInternal packageManagerInternal = mService.getPackageManagerInternal();
if (aInfo != null && aInfo.packageName != null) {
IncrementalStatesInfo incrementalStatesInfo =
packageManagerInternal.getIncrementalStatesInfo(
aInfo.packageName, mApp.uid, mApp.userId);
if (incrementalStatesInfo != null) {
- isPackageLoading = incrementalStatesInfo.isLoading();
+ loadingProgress = incrementalStatesInfo.getProgress();
+ }
+ final String codePath = aInfo.getCodePath();
+ isIncremental = IncrementalManager.isIncrementalPath(codePath);
+ if (isIncremental) {
+ // Report in the main log that the incremental package is still loading
+ Slog.e(TAG, "App crashed on incremental package " + aInfo.packageName
+ + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
+ final IBinder incrementalService = ServiceManager.getService(
+ Context.INCREMENTAL_SERVICE);
+ if (incrementalService != null) {
+ final IncrementalManager incrementalManager = new IncrementalManager(
+ IIncrementalService.Stub.asInterface(incrementalService));
+ IncrementalMetrics metrics = incrementalManager.getMetrics(codePath);
+ millisSinceOldestPendingRead = metrics.getMillisSinceOldestPendingRead();
+ }
}
}
@@ -322,10 +345,8 @@
info.append("Parent: ").append(parentShortComponentName).append("\n");
}
- if (isPackageLoading) {
- // Report in the main log that the package is still loading
- final float loadingProgress = packageManagerInternal.getIncrementalStatesInfo(
- aInfo.packageName, mApp.uid, mApp.userId).getProgress();
+ if (isIncremental) {
+ // Report in the main log about the incremental package
info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n");
}
@@ -412,7 +433,8 @@
? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
: FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND,
mApp.getProcessClassEnum(),
- (mApp.info != null) ? mApp.info.packageName : "", isPackageLoading);
+ (mApp.info != null) ? mApp.info.packageName : "",
+ isIncremental, loadingProgress, millisSinceOldestPendingRead);
final ProcessRecord parentPr = parentProcess != null
? (ProcessRecord) parentProcess.mOwner : null;
mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6614e06..1122f7f 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2098,26 +2098,28 @@
ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
beginTimeMillis, endTimeMillis, flags);
Objects.requireNonNull(callback, "callback cannot be null");
-
ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
- boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
- boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
- boolean isCallerPermissionController;
- try {
- isCallerPermissionController = pm.getPackageUid(
- mContext.getPackageManager().getPermissionControllerPackageName(), 0)
- == Binder.getCallingUid();
- } catch (PackageManager.NameNotFoundException doesNotHappen) {
- return;
- }
+ boolean isSelfRequest = (filter & FILTER_BY_UID) != 0 && uid == Binder.getCallingUid();
+ if (!isSelfRequest) {
+ boolean isCallerInstrumented = ami.isUidCurrentlyInstrumented(Binder.getCallingUid());
+ boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
+ boolean isCallerPermissionController;
+ try {
+ isCallerPermissionController = pm.getPackageUid(
+ mContext.getPackageManager().getPermissionControllerPackageName(), 0)
+ == Binder.getCallingUid();
+ } catch (PackageManager.NameNotFoundException doesNotHappen) {
+ return;
+ }
- if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) {
- mHandler.post(() -> callback.sendResult(new Bundle()));
- return;
- }
+ if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController) {
+ mHandler.post(() -> callback.sendResult(new Bundle()));
+ return;
+ }
- mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
- Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+ mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+ }
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 22d628b..eeed452 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -795,7 +795,7 @@
private static boolean isApiEnabled() {
return Binder.getCallingUid() == Process.myUid()
|| DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_PERMISSIONS_HUB_ENABLED, false);
+ PROPERTY_PERMISSIONS_HUB_ENABLED, true);
}
private static final class Persistence {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index e0d1375..6712c54 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -950,34 +950,36 @@
}
clipboard.mNotifiedUids.put(uid, true);
- // Retrieve the app label of the source of the clip data
- CharSequence sourceAppLabel = null;
- if (clipboard.mPrimaryClipPackage != null) {
- try {
- sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
- clipboard.mPrimaryClipPackage, 0, userId));
- } catch (PackageManager.NameNotFoundException e) {
- // leave label as null
+ Binder.withCleanCallingIdentity(() -> {
+ // Retrieve the app label of the source of the clip data
+ CharSequence sourceAppLabel = null;
+ if (clipboard.mPrimaryClipPackage != null) {
+ try {
+ sourceAppLabel = mPm.getApplicationLabel(mPm.getApplicationInfoAsUser(
+ clipboard.mPrimaryClipPackage, 0, userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ // leave label as null
+ }
}
- }
- try {
- CharSequence callingAppLabel = mPm.getApplicationLabel(
- mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
- String message;
- if (sourceAppLabel != null) {
- message = getContext().getString(
- R.string.pasted_from_app, callingAppLabel, sourceAppLabel);
- } else {
- message = getContext().getString(R.string.pasted_from_clipboard, callingAppLabel);
+ try {
+ CharSequence callingAppLabel = mPm.getApplicationLabel(
+ mPm.getApplicationInfoAsUser(callingPackage, 0, userId));
+ String message;
+ if (sourceAppLabel != null) {
+ message = getContext().getString(
+ R.string.pasted_from_app, callingAppLabel, sourceAppLabel);
+ } else {
+ message = getContext().getString(
+ R.string.pasted_from_clipboard, callingAppLabel);
+ }
+ Slog.i(TAG, message);
+ Toast.makeText(
+ getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT)
+ .show();
+ } catch (PackageManager.NameNotFoundException e) {
+ // do nothing
}
- Slog.i(TAG, message);
- Binder.withCleanCallingIdentity(() ->
- Toast.makeText(getContext(), UiThread.get().getLooper(), message,
- Toast.LENGTH_SHORT)
- .show());
- } catch (PackageManager.NameNotFoundException e) {
- // do nothing
- }
+ });
}
}
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 5cf478a..ae9b001 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -28,6 +28,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
@@ -55,7 +56,7 @@
* A change ID to be used only in the CTS test for this SystemApi
*/
@ChangeId
- @EnabledSince(targetSdkVersion = 1235) // Needs to be > test APK targetSdkVersion.
+ @EnabledSince(targetSdkVersion = 31) // Needs to be > test APK targetSdkVersion.
static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id.
/**
@@ -233,7 +234,7 @@
* @param app Info about the app in question
* @return {@code true} if the change should be enabled for the package.
*/
- boolean isEnabled(ApplicationInfo app) {
+ boolean isEnabled(ApplicationInfo app, AndroidBuildClassifier buildClassifier) {
if (app == null) {
return defaultValue();
}
@@ -244,7 +245,13 @@
return false;
}
if (getEnableSinceTargetSdk() != -1) {
- return app.targetSdkVersion >= getEnableSinceTargetSdk();
+ // If the change is gated by a platform version newer than the one currently installed
+ // on the device, disregard the app's target sdk version.
+ int compareSdk = Math.min(app.targetSdkVersion, buildClassifier.platformTargetSdk());
+ if (compareSdk != app.targetSdkVersion) {
+ compareSdk = app.targetSdkVersion;
+ }
+ return compareSdk >= getEnableSinceTargetSdk();
}
return true;
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 2c053b4..ef86f42 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -74,12 +74,14 @@
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
private final OverrideValidatorImpl mOverrideValidator;
+ private final AndroidBuildClassifier mAndroidBuildClassifier;
private Context mContext;
private File mOverridesFile;
@VisibleForTesting
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
+ mAndroidBuildClassifier = androidBuildClassifier;
mContext = context;
}
@@ -133,7 +135,7 @@
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
CompatChange c = mChanges.valueAt(i);
- if (!c.isEnabled(app)) {
+ if (!c.isEnabled(app, mAndroidBuildClassifier)) {
disabled.add(c.getId());
}
}
@@ -175,7 +177,7 @@
// we know nothing about this change: default behaviour is enabled.
return true;
}
- return c.isEnabled(app);
+ return c.isEnabled(app, mAndroidBuildClassifier);
}
}
@@ -475,7 +477,7 @@
synchronized (mChanges) {
for (int i = 0; i < mChanges.size(); ++i) {
CompatChange c = mChanges.valueAt(i);
- if (c.isEnabled(applicationInfo)) {
+ if (c.isEnabled(applicationInfo, mAndroidBuildClassifier)) {
enabled.add(c.getId());
} else {
disabled.add(c.getId());
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index fe5b4a9..aa66a1a 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -22,6 +22,7 @@
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
+import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -85,6 +86,9 @@
if (debuggableBuild) {
return new OverrideAllowedState(ALLOWED, -1, -1);
}
+ if (maxTargetSdk >= mAndroidBuildClassifier.platformTargetSdk()) {
+ return new OverrideAllowedState(PLATFORM_TOO_OLD, -1, maxTargetSdk);
+ }
PackageManager packageManager = mContext.getPackageManager();
if (packageManager == null) {
throw new IllegalStateException("No PackageManager!");
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index d17753f..2be39aa 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -66,18 +66,22 @@
private final Context mContext;
private final ChangeReporter mChangeReporter;
private final CompatConfig mCompatConfig;
+ private final AndroidBuildClassifier mBuildClassifier;
public PlatformCompat(Context context) {
mContext = context;
mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
- mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
+ mBuildClassifier = new AndroidBuildClassifier();
+ mCompatConfig = CompatConfig.create(mBuildClassifier, mContext);
}
@VisibleForTesting
- PlatformCompat(Context context, CompatConfig compatConfig) {
+ PlatformCompat(Context context, CompatConfig compatConfig,
+ AndroidBuildClassifier buildClassifier) {
mContext = context;
mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
mCompatConfig = compatConfig;
+ mBuildClassifier = buildClassifier;
registerPackageReceiver(context);
}
@@ -392,7 +396,8 @@
return false;
}
if (change.getEnableSinceTargetSdk() > 0) {
- return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q;
+ return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q
+ && change.getEnableSinceTargetSdk() <= mBuildClassifier.platformTargetSdk();
}
return true;
}
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityResources.java b/services/core/java/com/android/server/connectivity/ConnectivityResources.java
new file mode 100644
index 0000000..45cf21e
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ConnectivityResources.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.server.ConnectivityService;
+
+import java.util.List;
+
+/**
+ * Utility to obtain the {@link ConnectivityService} {@link Resources}, in the
+ * ServiceConnectivityResources APK.
+ */
+public class ConnectivityResources {
+ private static final String RESOURCES_APK_INTENT =
+ "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK";
+ private static final String RES_PKG_DIR = "/apex/com.android.tethering/";
+
+ @NonNull
+ private final Context mContext;
+
+ @Nullable
+ private Resources mResources = null;
+
+ public ConnectivityResources(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Get the {@link Resources} of the ServiceConnectivityResources APK.
+ */
+ public synchronized Resources get() {
+ if (mResources != null) {
+ return mResources;
+ }
+
+ final List<ResolveInfo> pkgs = mContext.getPackageManager()
+ .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY);
+ pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR));
+ if (pkgs.size() > 1) {
+ Log.wtf(ConnectivityResources.class.getSimpleName(),
+ "More than one package found: " + pkgs);
+ }
+ if (pkgs.isEmpty()) {
+ throw new IllegalStateException("No connectivity resource package found");
+ }
+
+ final Context pkgContext;
+ try {
+ pkgContext = mContext.createPackageContext(
+ pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException("Resolved package not found", e);
+ }
+
+ mResources = pkgContext.getResources();
+ return mResources;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 9411e33..488677a 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -31,14 +31,17 @@
import static com.android.net.module.util.CollectionUtils.toIntArray;
import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.UidRange;
+import android.net.Uri;
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -54,7 +57,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.CollectionUtils;
-import com.android.server.LocalServices;
import java.util.ArrayList;
import java.util.HashMap;
@@ -71,7 +73,7 @@
*
* @hide
*/
-public class PermissionMonitor implements PackageManagerInternal.PackageListObserver {
+public class PermissionMonitor {
private static final String TAG = "PermissionMonitor";
private static final boolean DBG = true;
protected static final Boolean SYSTEM = Boolean.TRUE;
@@ -83,6 +85,7 @@
private final SystemConfigManager mSystemConfigManager;
private final INetd mNetd;
private final Dependencies mDeps;
+ private final Context mContext;
@GuardedBy("this")
private final Set<UserHandle> mUsers = new HashSet<>();
@@ -102,6 +105,25 @@
@GuardedBy("this")
private final Set<Integer> mAllApps = new HashSet<>();
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri packageData = intent.getData();
+ final String packageName =
+ packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ onPackageAdded(packageName, uid);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ onPackageRemoved(packageName, uid);
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
+ }
+ }
+ };
+
/**
* Dependencies of PermissionMonitor, for injection in tests.
*/
@@ -127,6 +149,7 @@
mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
mNetd = netd;
mDeps = deps;
+ mContext = context;
}
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -134,12 +157,14 @@
public synchronized void startMonitoring() {
log("Monitoring");
- PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
- if (pmi != null) {
- pmi.getPackageList(this);
- } else {
- loge("failed to get the PackageManagerInternal service");
- }
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */).registerReceiver(
+ mIntentReceiver, intentFilter, null /* broadcastPermission */,
+ null /* scheduler */);
+
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
| MATCH_ANY_USER);
if (apps == null) {
@@ -347,9 +372,10 @@
*
* @hide
*/
- @Override
public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+ // using appId instead of uid actually
+ sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
@@ -384,9 +410,10 @@
*
* @hide
*/
- @Override
public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
+ // using appId instead of uid actually
+ sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
// If the newly-removed package falls within some VPN's uid range, update Netd with it.
// This needs to happen before the mApps update below, since removeBypassingUids() depends
@@ -432,19 +459,6 @@
}
}
- /**
- * Called when a package is changed.
- *
- * @param packageName The name of the changed package.
- * @param uid The uid of the changed package.
- *
- * @hide
- */
- @Override
- public synchronized void onPackageChanged(@NonNull final String packageName, final int uid) {
- sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
- }
-
private static int getNetdPermissionMask(String[] requestedPermissions,
int[] requestedPermissionsFlags) {
int permissions = 0;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 027b9af..0e71496 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -791,12 +791,13 @@
public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
enforceCrossUserPermission(userId,
"no permission to read sync settings for user " + userId);
+ final int callingUid = Binder.getCallingUid();
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- return syncManager.getSyncAdapterTypes(userId);
+ return syncManager.getSyncAdapterTypes(callingUid, userId);
} finally {
restoreCallingIdentity(identityToken);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index df87012..ac7e01e 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -89,6 +89,7 @@
import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
+import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.util.EventLog;
import android.util.Log;
@@ -1257,16 +1258,19 @@
syncExemptionFlag, callingUid, callingPid, callingPackage);
}
- public SyncAdapterType[] getSyncAdapterTypes(int userId) {
+ public SyncAdapterType[] getSyncAdapterTypes(int callingUid, int userId) {
final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
serviceInfos = mSyncAdapters.getAllServices(userId);
- SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
- int i = 0;
+ final List<SyncAdapterType> types = new ArrayList<>(serviceInfos.size());
for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
- types[i] = serviceInfo.type;
- ++i;
+ final String packageName = serviceInfo.type.getPackageName();
+ if (!TextUtils.isEmpty(packageName) && mPackageManagerInternal.filterAppAccess(
+ packageName, callingUid, userId)) {
+ continue;
+ }
+ types.add(serviceInfo.type);
}
- return types;
+ return types.toArray(new SyncAdapterType[] {});
}
public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 174d4b2..96a7416 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1128,7 +1128,7 @@
recordTopInsetLocked(display);
}
addDisplayPowerControllerLocked(display);
- mDisplayStates.append(displayId, Display.STATE_OFF);
+ mDisplayStates.append(displayId, Display.STATE_UNKNOWN);
mDisplayBrightnesses.append(displayId, display.getDisplayInfoLocked().brightnessDefault);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1204,16 +1204,15 @@
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
- final int state;
final int displayId = display.getDisplayIdLocked();
+ final int state = mDisplayStates.get(displayId);
- if (display.isEnabled()) {
- state = mDisplayStates.get(displayId);
- } else {
- state = Display.STATE_OFF;
+ // Only send a request for display state if the display state has already been
+ // initialized by DisplayPowercontroller.
+ if (state != Display.STATE_UNKNOWN) {
+ final float brightness = mDisplayBrightnesses.get(displayId);
+ return device.requestDisplayStateLocked(state, brightness);
}
- final float brightness = mDisplayBrightnesses.get(displayId);
- return device.requestDisplayStateLocked(state, brightness);
}
return null;
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 0117326..7b107b85 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -982,7 +982,8 @@
mWaitingForNegativeProximity = false;
mIgnoreProximityUntilChanged = false;
}
- if (mScreenOffBecauseOfProximity) {
+
+ if (!mLogicalDisplay.isEnabled() || mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF;
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index d88896c..aaec89a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -682,7 +682,10 @@
|| oldState == Display.STATE_ON_SUSPEND) {
setDisplayState(Display.STATE_ON);
currentState = Display.STATE_ON;
- } else {
+
+ // If UNKNOWN, we still want to set the initial display state,
+ // otherwise, return early.
+ } else if (oldState != Display.STATE_UNKNOWN) {
return; // old state and new state is off
}
}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 06adce8..2b7d207 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -31,6 +31,7 @@
import android.os.ShellCallback;
import android.system.ErrnoException;
import android.text.FontConfig;
+import android.text.TextUtils;
import android.util.AndroidException;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -66,6 +67,8 @@
@Override
public FontConfig getFontConfig() {
+ getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS,
+ "UPDATE_FONTS permission required.");
return getSystemFontConfig();
}
@@ -148,10 +151,24 @@
/* package */ static class OtfFontFileParser implements UpdatableFontDir.FontFileParser {
@Override
- public String getPostScriptName(File file) throws IOException {
+ public String getCanonicalFileName(File file) throws IOException {
ByteBuffer buffer = mmap(file);
try {
- return FontFileUtil.getPostScriptName(buffer, 0);
+ String psName = FontFileUtil.getPostScriptName(buffer, 0);
+ int isType1Font = FontFileUtil.isPostScriptType1Font(buffer, 0);
+ int isCollection = FontFileUtil.isCollectionFont(buffer);
+
+ if (TextUtils.isEmpty(psName) || isType1Font == -1 || isCollection == -1) {
+ return null;
+ }
+
+ String extension;
+ if (isCollection == 1) {
+ extension = isType1Font == 1 ? ".otc" : ".ttc";
+ } else {
+ extension = isType1Font == 1 ? ".otf" : ".ttf";
+ }
+ return psName + extension;
} finally {
NioUtils.freeDirectBuffer(buffer);
}
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index 86dbe86..4f95d27 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -56,14 +56,12 @@
private static final String TAG = "UpdatableFontDir";
private static final String RANDOM_DIR_PREFIX = "~~";
- // TODO: Support .otf
- private static final String ALLOWED_EXTENSION = ".ttf";
private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml";
/** Interface to mock font file access in tests. */
interface FontFileParser {
- String getPostScriptName(File file) throws IOException;
+ String getCanonicalFileName(File file) throws IOException;
long getRevision(File file) throws IOException;
}
@@ -321,20 +319,20 @@
FontManager.RESULT_ERROR_VERIFICATION_FAILURE,
"Failed to setup fs-verity.", e);
}
- String postScriptName;
+ String canonicalFileName;
try {
- postScriptName = mParser.getPostScriptName(tempNewFontFile);
+ canonicalFileName = mParser.getCanonicalFileName(tempNewFontFile);
} catch (IOException e) {
throw new SystemFontException(
FontManager.RESULT_ERROR_INVALID_FONT_FILE,
"Failed to read PostScript name from font file", e);
}
- if (postScriptName == null) {
+ if (canonicalFileName == null) {
throw new SystemFontException(
FontManager.RESULT_ERROR_INVALID_FONT_NAME,
"Failed to read PostScript name from font file");
}
- File newFontFile = new File(newDir, postScriptName + ALLOWED_EXTENSION);
+ File newFontFile = new File(newDir, canonicalFileName);
if (!mFsverityUtil.rename(tempNewFontFile, newFontFile)) {
throw new SystemFontException(
FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
@@ -380,20 +378,38 @@
return dir;
}
+ private FontFileInfo lookupFontFileInfo(File file) {
+ String name = file.getName();
+
+ if (!name.endsWith(".ttf") && !name.endsWith(".otf") && !name.endsWith(".ttc")
+ && !name.endsWith(".otc")) {
+ return null;
+ }
+ String key = name.substring(0, name.length() - 4);
+ return mFontFileInfoMap.get(key);
+ }
+
+ private void putFontFileInfo(FontFileInfo info) {
+ String name = info.getFile().getName();
+ // The file name in FontFileInfo is already validated. Thus, just strip last 4 chars.
+ String key = name.substring(0, name.length() - 4);
+ mFontFileInfoMap.put(key, info);
+ }
+
/**
* Add the given {@link FontFileInfo} to {@link #mFontFileInfoMap} if its font revision is
* higher than the currently used font file (either in {@link #mFontFileInfoMap} or {@link
* #mPreinstalledFontDirs}).
*/
private boolean addFileToMapIfNewer(FontFileInfo fontFileInfo, boolean deleteOldFile) {
- String name = fontFileInfo.getFile().getName();
- FontFileInfo existingInfo = mFontFileInfoMap.get(name);
+ FontFileInfo existingInfo = lookupFontFileInfo(fontFileInfo.getFile());
final boolean shouldAddToMap;
if (existingInfo == null) {
// We got a new updatable font. We need to check if it's newer than preinstalled fonts.
// Note that getPreinstalledFontRevision() returns -1 if there is no preinstalled font
// with 'name'.
- shouldAddToMap = getPreinstalledFontRevision(name) < fontFileInfo.getRevision();
+ long preInstalledRev = getPreinstalledFontRevision(fontFileInfo.getFile().getName());
+ shouldAddToMap = preInstalledRev < fontFileInfo.getRevision();
} else {
shouldAddToMap = existingInfo.getRevision() < fontFileInfo.getRevision();
}
@@ -401,7 +417,7 @@
if (deleteOldFile && existingInfo != null) {
FileUtils.deleteContentsAndDir(existingInfo.getRandomizedFontDir());
}
- mFontFileInfoMap.put(name, fontFileInfo);
+ putFontFileInfo(fontFileInfo);
} else {
if (deleteOldFile) {
FileUtils.deleteContentsAndDir(fontFileInfo.getRandomizedFontDir());
@@ -464,15 +480,18 @@
*/
private boolean validateFontFileName(File file) {
String fileName = file.getName();
- String postScriptName = getPostScriptName(file);
- return (postScriptName + ALLOWED_EXTENSION).equals(fileName);
+ String canonicalFileName = getCanonicalFileName(file);
+ if (canonicalFileName == null) {
+ return false;
+ }
+ return canonicalFileName.equals(fileName);
}
/** Returns the PostScript name of the given font file, or null. */
@Nullable
- private String getPostScriptName(File file) {
+ private String getCanonicalFileName(File file) {
try {
- return mParser.getPostScriptName(file);
+ return mParser.getCanonicalFileName(file);
} catch (IOException e) {
Slog.e(TAG, "Failed to read font file", e);
return null;
@@ -514,7 +533,7 @@
List<FontConfig.Font> fontList = fontFamily.getFontList();
for (int i = 0; i < fontList.size(); i++) {
FontConfig.Font font = fontList.get(i);
- FontFileInfo info = mFontFileInfoMap.get(font.getFile().getName());
+ FontFileInfo info = lookupFontFileInfo(font.getFile());
if (info == null) {
return null;
}
@@ -537,8 +556,9 @@
Map<String, File> getFontFileMap() {
Map<String, File> map = new ArrayMap<>();
- for (Map.Entry<String, FontFileInfo> entry : mFontFileInfoMap.entrySet()) {
- map.put(entry.getKey(), entry.getValue().getFile());
+ for (int i = 0; i < mFontFileInfoMap.size(); ++i) {
+ File file = mFontFileInfoMap.valueAt(i).getFile();
+ map.put(file.getName(), file);
}
return map;
}
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index c23e2e6..947ee24 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -97,11 +97,16 @@
@Override
public boolean start() {
- // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
- // The message is re-sent at the end of the action for devices that don't support 2.0.
- sendSetStreamPath();
- int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
- .getCecDeviceInfo(getTargetAddress()).getDevicePowerStatus();
+ // Wake-up on <Set Stream Path> was not mandatory before CEC 2.0.
+ // The message is re-sent at the end of the action for devices that don't support 2.0.
+ sendSetStreamPath();
+ int targetPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
+ HdmiDeviceInfo targetDevice = localDevice().mService.getHdmiCecNetwork().getCecDeviceInfo(
+ getTargetAddress());
+ if (targetDevice != null) {
+ targetPowerStatus = targetDevice.getDevicePowerStatus();
+ }
+
if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
queryDevicePowerStatus();
} else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 624af30..6fbb26c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -35,33 +35,19 @@
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.util.ArrayMap;
-import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ConcurrentUtils;
-import com.android.server.hdmi.cec.config.CecSettings;
-import com.android.server.hdmi.cec.config.Setting;
-import com.android.server.hdmi.cec.config.Value;
-import com.android.server.hdmi.cec.config.XmlParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
-import java.util.Set;
import java.util.concurrent.Executor;
-import javax.xml.datatype.DatatypeConfigurationException;
-
/**
* The {@link HdmiCecConfig} class is used for getting information about
* available HDMI CEC settings.
@@ -74,6 +60,10 @@
private static final String SHARED_PREFS_DIR = "shared_prefs";
private static final String SHARED_PREFS_NAME = "cec_config.xml";
+ private static final int STORAGE_SYSPROPS = 0;
+ private static final int STORAGE_GLOBAL_SETTINGS = 1;
+ private static final int STORAGE_SHARED_PREFS = 2;
+
@IntDef({
STORAGE_SYSPROPS,
STORAGE_GLOBAL_SETTINGS,
@@ -81,10 +71,6 @@
})
private @interface Storage {}
- private static final int STORAGE_SYSPROPS = 0;
- private static final int STORAGE_GLOBAL_SETTINGS = 1;
- private static final int STORAGE_SHARED_PREFS = 2;
-
private static final String VALUE_TYPE_STRING = "string";
private static final String VALUE_TYPE_INT = "int";
@@ -96,8 +82,6 @@
@NonNull private final Context mContext;
@NonNull private final StorageAdapter mStorageAdapter;
- @Nullable private final CecSettings mSystemConfig;
- @Nullable private final CecSettings mVendorOverride;
private final Object mLock = new Object();
@@ -107,6 +91,18 @@
private SettingsObserver mSettingsObserver;
+ private LinkedHashMap<String, Setting> mSettings = new LinkedHashMap<>();
+
+ /**
+ * Exception thrown when the CEC Configuration setup verification fails.
+ * This usually means a settings lacks default value or storage/storage key.
+ */
+ public static class VerificationException extends RuntimeException {
+ public VerificationException(String message) {
+ super(message);
+ }
+ }
+
/**
* Listener used to get notifications when value of a setting changes.
*/
@@ -202,91 +198,297 @@
}
}
+ private class Value {
+ private final String mStringValue;
+ private final Integer mIntValue;
+
+ Value(@NonNull String value) {
+ mStringValue = value;
+ mIntValue = null;
+ }
+
+ Value(@NonNull Integer value) {
+ mStringValue = null;
+ mIntValue = value;
+ }
+
+ String getStringValue() {
+ return mStringValue;
+ }
+
+ Integer getIntValue() {
+ return mIntValue;
+ }
+ }
+
+ private class Setting {
+ @NonNull private final Context mContext;
+ @NonNull private final @CecSettingName String mName;
+ private final boolean mUserConfigurable;
+
+ private Value mDefaultValue = null;
+ private List<Value> mAllowedValues = new ArrayList<>();
+
+ Setting(@NonNull Context context,
+ @NonNull @CecSettingName String name,
+ int userConfResId) {
+ mContext = context;
+ mName = name;
+ mUserConfigurable = mContext.getResources().getBoolean(userConfResId);
+ }
+
+ public @CecSettingName String getName() {
+ return mName;
+ }
+
+ public @ValueType String getValueType() {
+ return getDefaultValue().getStringValue() != null
+ ? VALUE_TYPE_STRING
+ : VALUE_TYPE_INT;
+ }
+
+ public Value getDefaultValue() {
+ if (mDefaultValue == null) {
+ throw new VerificationException("Invalid CEC setup for '"
+ + this.getName() + "' setting. "
+ + "Setting has no default value.");
+ }
+ return mDefaultValue;
+ }
+
+ public boolean getUserConfigurable() {
+ return mUserConfigurable;
+ }
+
+ private void registerValue(@NonNull Value value,
+ int allowedResId, int defaultResId) {
+ if (mContext.getResources().getBoolean(allowedResId)) {
+ mAllowedValues.add(value);
+ if (mContext.getResources().getBoolean(defaultResId)) {
+ if (mDefaultValue != null) {
+ throw new VerificationException("Invalid CEC setup for '"
+ + this.getName() + "' setting. "
+ + "Setting already has a default value.");
+ }
+ mDefaultValue = value;
+ }
+ }
+ }
+
+ public void registerValue(@NonNull String value, int allowedResId,
+ int defaultResId) {
+ registerValue(new Value(value), allowedResId, defaultResId);
+ }
+
+ public void registerValue(int value, int allowedResId,
+ int defaultResId) {
+ registerValue(new Value(value), allowedResId, defaultResId);
+ }
+
+
+ public List<Value> getAllowedValues() {
+ return mAllowedValues;
+ }
+ }
+
@VisibleForTesting
HdmiCecConfig(@NonNull Context context,
- @NonNull StorageAdapter storageAdapter,
- @Nullable CecSettings systemConfig,
- @Nullable CecSettings vendorOverride) {
+ @NonNull StorageAdapter storageAdapter) {
mContext = context;
mStorageAdapter = storageAdapter;
- mSystemConfig = systemConfig;
- mVendorOverride = vendorOverride;
- if (mSystemConfig == null) {
- Slog.i(TAG, "CEC system configuration XML missing.");
- }
- if (mVendorOverride == null) {
- Slog.i(TAG, "CEC OEM configuration override XML missing.");
- }
+
+ Setting hdmiCecEnabled = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ R.bool.config_cecHdmiCecEnabled_userConfigurable);
+ hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED,
+ R.bool.config_cecHdmiCecControlEnabled_allowed,
+ R.bool.config_cecHdmiCecControlEnabled_default);
+ hdmiCecEnabled.registerValue(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
+ R.bool.config_cecHdmiCecControlDisabled_allowed,
+ R.bool.config_cecHdmiCecControlDisabled_default);
+
+ Setting hdmiCecVersion = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ R.bool.config_cecHdmiCecVersion_userConfigurable);
+ hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_1_4_B,
+ R.bool.config_cecHdmiCecVersion14b_allowed,
+ R.bool.config_cecHdmiCecVersion14b_default);
+ hdmiCecVersion.registerValue(HdmiControlManager.HDMI_CEC_VERSION_2_0,
+ R.bool.config_cecHdmiCecVersion20_allowed,
+ R.bool.config_cecHdmiCecVersion20_default);
+
+ Setting powerControlMode = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ R.bool.config_cecSendStandbyOnSleep_userConfigurable);
+ powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_TV,
+ R.bool.config_cecPowerControlModeTv_allowed,
+ R.bool.config_cecPowerControlModeTv_default);
+ powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST,
+ R.bool.config_cecPowerControlModeBroadcast_allowed,
+ R.bool.config_cecPowerControlModeBroadcast_default);
+ powerControlMode.registerValue(HdmiControlManager.POWER_CONTROL_MODE_NONE,
+ R.bool.config_cecPowerControlModeNone_allowed,
+ R.bool.config_cecPowerControlModeNone_default);
+
+ Setting powerStateChangeOnActiveSourceLost = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable);
+ powerStateChangeOnActiveSourceLost.registerValue(
+ HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default);
+ powerStateChangeOnActiveSourceLost.registerValue(
+ HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed,
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
+
+ Setting systemAudioModeMuting = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ R.bool.config_cecSystemAudioModeMuting_userConfigurable);
+ systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED,
+ R.bool.config_cecSystemAudioModeMutingEnabled_allowed,
+ R.bool.config_cecSystemAudioModeMutingEnabled_default);
+ systemAudioModeMuting.registerValue(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED,
+ R.bool.config_cecSystemAudioModeMutingDisabled_allowed,
+ R.bool.config_cecSystemAudioModeMutingDisabled_default);
+
+ Setting volumeControlMode = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ R.bool.config_cecVolumeControlMode_userConfigurable);
+ volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_ENABLED,
+ R.bool.config_cecVolumeControlModeEnabled_allowed,
+ R.bool.config_cecVolumeControlModeEnabled_default);
+ volumeControlMode.registerValue(HdmiControlManager.VOLUME_CONTROL_DISABLED,
+ R.bool.config_cecVolumeControlModeDisabled_allowed,
+ R.bool.config_cecVolumeControlModeDisabled_default);
+
+ Setting tvWakeOnOneTouchPlay = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable);
+ tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED,
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed,
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default);
+ tvWakeOnOneTouchPlay.registerValue(HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED,
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed,
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default);
+
+ Setting tvSendStandbyOnSleep = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ R.bool.config_cecTvSendStandbyOnSleep_userConfigurable);
+ tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED,
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed,
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_default);
+ tvSendStandbyOnSleep.registerValue(HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED,
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed,
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
+
+ Setting rcProfileTv = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ R.bool.config_cecRcProfileTv_userConfigurable);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_NONE,
+ R.bool.config_cecRcProfileTvNone_allowed,
+ R.bool.config_cecRcProfileTvNone_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_ONE,
+ R.bool.config_cecRcProfileTvOne_allowed,
+ R.bool.config_cecRcProfileTvOne_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_TWO,
+ R.bool.config_cecRcProfileTvTwo_allowed,
+ R.bool.config_cecRcProfileTvTwo_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_THREE,
+ R.bool.config_cecRcProfileTvThree_allowed,
+ R.bool.config_cecRcProfileTvThree_default);
+ rcProfileTv.registerValue(HdmiControlManager.RC_PROFILE_TV_FOUR,
+ R.bool.config_cecRcProfileTvFour_allowed,
+ R.bool.config_cecRcProfileTvFour_default);
+
+ Setting rcProfileSourceRootMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ R.bool.config_cecRcProfileSourceRootMenu_userConfigurable);
+ rcProfileSourceRootMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceRootMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceRootMenuHandled_default);
+ rcProfileSourceRootMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_ROOT_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_default);
+
+ Setting rcProfileSourceSetupMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable);
+ rcProfileSourceSetupMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_default);
+ rcProfileSourceSetupMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_SETUP_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default);
+
+ Setting rcProfileSourceContentsMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable);
+ rcProfileSourceContentsMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_default);
+ rcProfileSourceContentsMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_CONTENTS_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default);
+
+ Setting rcProfileSourceTopMenu = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ R.bool.config_cecRcProfileSourceTopMenu_userConfigurable);
+ rcProfileSourceTopMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceTopMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceTopMenuHandled_default);
+ rcProfileSourceTopMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_TOP_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_default);
+
+ Setting rcProfileSourceMediaContextSensitiveMenu = registerSetting(
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable);
+ rcProfileSourceMediaContextSensitiveMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_HANDLED,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default);
+ rcProfileSourceMediaContextSensitiveMenu.registerValue(
+ HdmiControlManager.RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU_NOT_HANDLED,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed,
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default);
+
+ verifySettings();
}
HdmiCecConfig(@NonNull Context context) {
- this(context, new StorageAdapter(context),
- readSettingsFromFile(Environment.buildPath(Environment.getRootDirectory(),
- ETC_DIR, CONFIG_FILE)),
- readSettingsFromFile(Environment.buildPath(Environment.getVendorDirectory(),
- ETC_DIR, CONFIG_FILE)));
+ this(context, new StorageAdapter(context));
}
- @Nullable
- private static CecSettings readSettingsFromFile(@NonNull File file) {
- if (!file.exists()) {
- return null;
- }
- if (!file.isFile()) {
- Slog.e(TAG, "CEC configuration is not a file: " + file + ", skipping.");
- return null;
- }
- try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
- return XmlParser.read(in);
- } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
- Slog.e(TAG, "Encountered an error while reading/parsing CEC config file: " + file, e);
- }
- return null;
+ private Setting registerSetting(@NonNull @CecSettingName String name,
+ int userConfResId) {
+ Setting setting = new Setting(mContext, name, userConfResId);
+ mSettings.put(name, setting);
+ return setting;
}
- @NonNull
- @VisibleForTesting
- static HdmiCecConfig createFromStrings(@NonNull Context context,
- @NonNull StorageAdapter storageAdapter,
- @Nullable String productConfigXml,
- @Nullable String vendorOverrideXml) {
- CecSettings productConfig = null;
- CecSettings vendorOverride = null;
- try {
- if (productConfigXml != null) {
- productConfig = XmlParser.read(
- new ByteArrayInputStream(productConfigXml.getBytes()));
- }
- if (vendorOverrideXml != null) {
- vendorOverride = XmlParser.read(
- new ByteArrayInputStream(vendorOverrideXml.getBytes()));
- }
- } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
- Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
+ private void verifySettings() {
+ for (Setting setting: mSettings.values()) {
+ // This will throw an exception when a setting
+ // doesn't have a default value assigned.
+ setting.getDefaultValue();
+ getStorage(setting);
+ getStorageKey(setting);
}
- return new HdmiCecConfig(context, storageAdapter, productConfig, vendorOverride);
}
@Nullable
private Setting getSetting(@NonNull String name) {
- if (mSystemConfig == null) {
- return null;
- }
- if (mVendorOverride != null) {
- // First read from the vendor override.
- for (Setting setting : mVendorOverride.getSetting()) {
- if (setting.getName().equals(name)) {
- return setting;
- }
- }
- }
- // If not found, try the system config.
- for (Setting setting : mSystemConfig.getSetting()) {
- if (setting.getName().equals(name)) {
- return setting;
- }
- }
- return null;
+ return mSettings.containsKey(name) ? mSettings.get(name) : null;
}
@Storage
@@ -322,7 +524,7 @@
.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU:
return STORAGE_SHARED_PREFS;
default:
- throw new RuntimeException("Invalid CEC setting '" + setting.getName()
+ throw new VerificationException("Invalid CEC setting '" + setting.getName()
+ "' storage.");
}
}
@@ -359,7 +561,7 @@
.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU:
return setting.getName();
default:
- throw new RuntimeException("Invalid CEC setting '" + setting.getName()
+ throw new VerificationException("Invalid CEC setting '" + setting.getName()
+ "' storage key.");
}
}
@@ -396,10 +598,6 @@
}
}
- private int getIntValue(@NonNull Value value) {
- return Integer.decode(value.getIntValue());
- }
-
private void notifyGlobalSettingChanged(String setting) {
switch (setting) {
case Global.HDMI_CONTROL_ENABLED:
@@ -533,41 +731,20 @@
* Returns a list of all settings based on the XML metadata.
*/
public @CecSettingName List<String> getAllSettings() {
- if (mSystemConfig == null) {
- return new ArrayList<String>();
- }
- List<String> allSettings = new ArrayList<String>();
- for (Setting setting : mSystemConfig.getSetting()) {
- allSettings.add(setting.getName());
- }
- return allSettings;
+ return new ArrayList<>(mSettings.keySet());
}
/**
* Returns a list of user-modifiable settings based on the XML metadata.
*/
public @CecSettingName List<String> getUserSettings() {
- if (mSystemConfig == null) {
- return new ArrayList<String>();
- }
- Set<String> userSettings = new HashSet<String>();
- // First read from the system config.
- for (Setting setting : mSystemConfig.getSetting()) {
+ List<String> settings = new ArrayList<>();
+ for (Setting setting: mSettings.values()) {
if (setting.getUserConfigurable()) {
- userSettings.add(setting.getName());
+ settings.add(setting.getName());
}
}
- if (mVendorOverride != null) {
- // Next either add or remove based on the vendor override.
- for (Setting setting : mVendorOverride.getSetting()) {
- if (setting.getUserConfigurable()) {
- userSettings.add(setting.getName());
- } else {
- userSettings.remove(setting.getName());
- }
- }
- }
- return new ArrayList(userSettings);
+ return settings;
}
/**
@@ -607,7 +784,7 @@
+ "' is not a string-type setting.");
}
List<String> allowedValues = new ArrayList<String>();
- for (Value allowedValue : setting.getAllowedValues().getValue()) {
+ for (Value allowedValue : setting.getAllowedValues()) {
allowedValues.add(allowedValue.getStringValue());
}
return allowedValues;
@@ -626,8 +803,8 @@
+ "' is not a string-type setting.");
}
List<Integer> allowedValues = new ArrayList<Integer>();
- for (Value allowedValue : setting.getAllowedValues().getValue()) {
- allowedValues.add(getIntValue(allowedValue));
+ for (Value allowedValue : setting.getAllowedValues()) {
+ allowedValues.add(allowedValue.getIntValue());
}
return allowedValues;
}
@@ -659,7 +836,7 @@
throw new IllegalArgumentException("Setting '" + name
+ "' is not a string-type setting.");
}
- return getIntValue(getSetting(name).getDefaultValue());
+ return getSetting(name).getDefaultValue().getIntValue();
}
/**
@@ -691,7 +868,7 @@
+ "' is not a int-type setting.");
}
HdmiLogger.debug("Getting CEC setting value '" + name + "'.");
- String defaultValue = Integer.toString(getIntValue(setting.getDefaultValue()));
+ String defaultValue = Integer.toString(setting.getDefaultValue().getIntValue());
String value = retrieveValue(setting, defaultValue);
return Integer.parseInt(value);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index d8914b3..bdc4e66 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -500,7 +500,8 @@
HdmiDeviceInfo cecDeviceInfo = mService.getHdmiCecNetwork().getCecDeviceInfo(address);
// If no non-default display name is available for the device, request the devices OSD name.
- if (cecDeviceInfo.getDisplayName().equals(HdmiUtils.getDefaultDeviceName(address))) {
+ if (cecDeviceInfo != null && cecDeviceInfo.getDisplayName().equals(
+ HdmiUtils.getDefaultDeviceName(address))) {
mService.sendCecCommand(
HdmiCecMessageBuilder.buildGiveOsdNameCommand(mAddress, address));
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 7235a92..90d6433 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -30,6 +30,7 @@
import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
+import android.annotation.Nullable;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
@@ -1147,6 +1148,7 @@
&& getAvrDeviceInfo() != null;
}
+ @Nullable
@ServiceThreadOnly
HdmiDeviceInfo getAvrDeviceInfo() {
assertRunOnServiceThread();
@@ -1157,6 +1159,7 @@
return getSafeAvrDeviceInfo() != null;
}
+ @Nullable
HdmiDeviceInfo getSafeAvrDeviceInfo() {
return mService.getHdmiCecNetwork().getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index b748ae0..7ceaa95 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -185,6 +185,12 @@
mLocalDevices.clear();
}
+ /**
+ * Get the device info of a local device or a device in the CEC network by a device id.
+ * @param id id of the device to get
+ * @return the device with the given id, or {@code null}
+ */
+ @Nullable
public HdmiDeviceInfo getDeviceInfo(int id) {
return mDeviceInfos.get(id);
}
@@ -717,6 +723,7 @@
* @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
* Returns null if no logical address matched
*/
+ @Nullable
HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) {
for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 115cafed..e6e2f96 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -988,6 +988,7 @@
return mCecController.getVendorId();
}
+ @Nullable
@ServiceThreadOnly
HdmiDeviceInfo getDeviceInfo(int logicalAddress) {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 73ecbe0..9d2db94 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -16,6 +16,7 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
import android.hardware.hdmi.IHdmiControlCallback;
import android.util.Slog;
@@ -62,8 +63,7 @@
Slog.e(TAG, "Wrong arguments");
return null;
}
- return new OneTouchPlayAction(source, targetAddress,
- callback);
+ return new OneTouchPlayAction(source, targetAddress, callback);
}
private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress,
@@ -71,8 +71,8 @@
this(localDevice, targetAddress, callback,
localDevice.getDeviceInfo().getCecVersion()
>= HdmiControlManager.HDMI_CEC_VERSION_2_0
- && localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
- targetAddress).getCecVersion() >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ && getTargetCecVersion(localDevice, targetAddress)
+ >= HdmiControlManager.HDMI_CEC_VERSION_2_0);
}
@VisibleForTesting
@@ -88,9 +88,9 @@
// Because only source device can create this action, it's safe to cast.
mSource = source();
sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress));
- boolean targetOnBefore = localDevice().mService.getHdmiCecNetwork()
- .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus()
- == HdmiControlManager.POWER_STATUS_ON;
+
+ boolean targetOnBefore = getTargetDevicePowerStatus(mSource, mTargetAddress,
+ HdmiControlManager.POWER_STATUS_UNKNOWN) == HdmiControlManager.POWER_STATUS_ON;
broadcastActiveSource();
// If the device is not an audio system itself, request the connected audio system to
// turn on.
@@ -98,8 +98,8 @@
sendCommand(HdmiCecMessageBuilder.buildSystemAudioModeRequest(getSourceAddress(),
Constants.ADDR_AUDIO_SYSTEM, getSourcePath(), true));
}
- int targetPowerStatus = localDevice().mService.getHdmiCecNetwork()
- .getCecDeviceInfo(mTargetAddress).getDevicePowerStatus();
+ int targetPowerStatus = getTargetDevicePowerStatus(mSource, mTargetAddress,
+ HdmiControlManager.POWER_STATUS_UNKNOWN);
if (!mIsCec20 || targetPowerStatus == HdmiControlManager.POWER_STATUS_UNKNOWN) {
queryDevicePowerStatus();
} else if (targetPowerStatus == HdmiControlManager.POWER_STATUS_ON) {
@@ -179,4 +179,23 @@
return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
}
+ private static int getTargetCecVersion(HdmiCecLocalDevice localDevice,
+ int targetLogicalAddress) {
+ HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
+ targetLogicalAddress);
+ if (targetDevice != null) {
+ return targetDevice.getCecVersion();
+ }
+ return HdmiControlManager.HDMI_CEC_VERSION_1_4_B;
+ }
+
+ private static int getTargetDevicePowerStatus(HdmiCecLocalDevice localDevice,
+ int targetLogicalAddress, int defaultPowerStatus) {
+ HdmiDeviceInfo targetDevice = localDevice.mService.getHdmiCecNetwork().getCecDeviceInfo(
+ targetLogicalAddress);
+ if (targetDevice != null) {
+ return targetDevice.getDevicePowerStatus();
+ }
+ return defaultPowerStatus;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/cec_config.xml b/services/core/java/com/android/server/hdmi/cec_config.xml
deleted file mode 100644
index 191e725..0000000
--- a/services/core/java/com/android/server/hdmi/cec_config.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<cec-settings>
- <setting name="hdmi_cec_enabled"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="hdmi_cec_version"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0x05" />
- <value int-value="0x06" />
- </allowed-values>
- <default-value int-value="0x05" />
- </setting>
- <setting name="send_standby_on_sleep"
- value-type="string"
- user-configurable="true">
- <allowed-values>
- <value string-value="to_tv" />
- <value string-value="broadcast" />
- <value string-value="none" />
- </allowed-values>
- <default-value string-value="to_tv" />
- </setting>
- <setting name="power_state_change_on_active_source_lost"
- value-type="string"
- user-configurable="true">
- <allowed-values>
- <value string-value="none" />
- <value string-value="standby_now" />
- </allowed-values>
- <default-value string-value="none" />
- </setting>
- <setting name="system_audio_mode_muting"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="volume_control_enabled"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="tv_wake_on_one_touch_play"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="tv_send_standby_on_sleep"
- value-type="int"
- user-configurable="true">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="rc_profile_tv"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0x0" />
- <value int-value="0x2" />
- <value int-value="0x6" />
- <value int-value="0xA" />
- <value int-value="0xE" />
- </allowed-values>
- <default-value int-value="0x0" />
- </setting>
- <setting name="rc_profile_source_handles_root_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="rc_profile_source_handles_setup_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="1" />
- </setting>
- <setting name="rc_profile_source_handles_contents_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="0" />
- </setting>
- <setting name="rc_profile_source_handles_top_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="0" />
- </setting>
- <setting name="rc_profile_source_handles_media_context_sensitive_menu"
- value-type="int"
- user-configurable="false">
- <allowed-values>
- <value int-value="0" />
- <value int-value="1" />
- </allowed-values>
- <default-value int-value="0" />
- </setting>
-</cec-settings>
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7dc9a0b..cbe6e69 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -304,7 +304,7 @@
int displayId, InputApplicationHandle application);
private static native void nativeSetFocusedDisplay(long ptr, int displayId);
private static native boolean nativeTransferTouchFocus(long ptr,
- IBinder fromChannelToken, IBinder toChannelToken);
+ IBinder fromChannelToken, IBinder toChannelToken, boolean isDragDrop);
private static native void nativeSetPointerSpeed(long ptr, int speed);
private static native void nativeSetShowTouches(long ptr, boolean enabled);
private static native void nativeSetInteractive(long ptr, boolean interactive);
@@ -1727,12 +1727,14 @@
* @param fromChannel The channel of a window that currently has touch focus.
* @param toChannel The channel of the window that should receive touch focus in
* place of the first.
+ * @param isDragDrop True if transfer touch focus for drag and drop.
* @return True if the transfer was successful. False if the window with the
* specified channel did not actually have touch focus at the time of the request.
*/
public boolean transferTouchFocus(@NonNull InputChannel fromChannel,
- @NonNull InputChannel toChannel) {
- return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken());
+ @NonNull InputChannel toChannel, boolean isDragDrop) {
+ return nativeTransferTouchFocus(mPtr, fromChannel.getToken(), toChannel.getToken(),
+ isDragDrop);
}
/**
@@ -1752,7 +1754,8 @@
@NonNull IBinder toChannelToken) {
Objects.nonNull(fromChannelToken);
Objects.nonNull(toChannelToken);
- return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken);
+ return nativeTransferTouchFocus(mPtr, fromChannelToken, toChannelToken,
+ false /* isDragDrop */);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a89cb55..672ed3d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5838,7 +5838,22 @@
@BinderThread
@ShellCommandResult
private int handleShellCommandTraceInputMethod(@NonNull ShellCommand shellCommand) {
- int result = ImeTracing.getInstance().onShellCommand(shellCommand);
+ final String cmd = shellCommand.getNextArgRequired();
+ final PrintWriter pw = shellCommand.getOutPrintWriter();
+ switch (cmd) {
+ case "start":
+ ImeTracing.getInstance().getInstance().startTrace(pw);
+ break;
+ case "stop":
+ ImeTracing.getInstance().stopTrace(pw);
+ break;
+ default:
+ pw.println("Unknown command: " + cmd);
+ pw.println("Input method trace options:");
+ pw.println(" start: Start tracing");
+ pw.println(" stop: Stop tracing");
+ return ShellCommandResult.FAILURE;
+ }
boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
ArrayMap<IBinder, ClientState> clients;
synchronized (mMethodMap) {
@@ -5854,7 +5869,7 @@
}
}
}
- return result;
+ return ShellCommandResult.SUCCESS;
}
/**
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 5a90fa7..7f47805 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -370,6 +370,7 @@
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_GEOFENCE,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
null,
/* LocationRequest= */ null,
/* hasListener= */ false,
@@ -383,6 +384,7 @@
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_GEOFENCE,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
null,
/* LocationRequest= */ null,
/* hasListener= */ false,
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index b3119d7..8460d67 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -189,6 +189,7 @@
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
null,
null,
true,
@@ -202,6 +203,7 @@
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
null,
null,
true,
diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
index 1eb1618..936283d 100644
--- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
@@ -83,6 +83,7 @@
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
null,
null,
true,
@@ -96,6 +97,7 @@
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
null,
null,
true,
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index f275663..1eef0de 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -27,6 +27,7 @@
import android.location.GnssNavigationMessage;
import android.location.GnssStatus;
import android.location.Location;
+import android.os.Binder;
import android.os.SystemClock;
import android.util.Log;
@@ -921,6 +922,7 @@
@NativeEntryPoint
void reportGnssServiceDied() {
+ // Not necessary to clear (and restore) binder identity since it runs on another thread.
Log.e(TAG, "gnss hal died - restarting shortly...");
// move to another thread just in case there is some awkward gnss thread dependency with
@@ -940,96 +942,111 @@
@NativeEntryPoint
void reportLocation(boolean hasLatLong, Location location) {
- if (hasLatLong && !mHasFirstFix) {
- mHasFirstFix = true;
+ Binder.withCleanCallingIdentity(() -> {
+ if (hasLatLong && !mHasFirstFix) {
+ mHasFirstFix = true;
- // notify status listeners
- int ttff = (int) (SystemClock.elapsedRealtime() - mStartRealtimeMs);
- for (int i = 0; i < mStatusCallbacks.length; i++) {
- mStatusCallbacks[i].onReportFirstFix(ttff);
+ // notify status listeners
+ int ttff = (int) (SystemClock.elapsedRealtime() - mStartRealtimeMs);
+ for (int i = 0; i < mStatusCallbacks.length; i++) {
+ mStatusCallbacks[i].onReportFirstFix(ttff);
+ }
}
- }
- if (location.hasSpeed()) {
- boolean exceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
- if (!mItarSpeedLimitExceeded && exceeded) {
- Log.w(TAG, "speed nearing ITAR threshold - blocking further GNSS output");
- } else if (mItarSpeedLimitExceeded && !exceeded) {
- Log.w(TAG, "speed leaving ITAR threshold - allowing further GNSS output");
+ if (location.hasSpeed()) {
+ boolean exceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
+ if (!mItarSpeedLimitExceeded && exceeded) {
+ Log.w(TAG, "speed nearing ITAR threshold - blocking further GNSS output");
+ } else if (mItarSpeedLimitExceeded && !exceeded) {
+ Log.w(TAG, "speed leaving ITAR threshold - allowing further GNSS output");
+ }
+ mItarSpeedLimitExceeded = exceeded;
}
- mItarSpeedLimitExceeded = exceeded;
- }
- if (mItarSpeedLimitExceeded) {
- return;
- }
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
- for (int i = 0; i < mLocationCallbacks.length; i++) {
- mLocationCallbacks[i].onReportLocation(hasLatLong, location);
- }
+ for (int i = 0; i < mLocationCallbacks.length; i++) {
+ mLocationCallbacks[i].onReportLocation(hasLatLong, location);
+ }
+ });
}
@NativeEntryPoint
void reportStatus(@StatusCallbacks.GnssStatusValue int gnssStatus) {
- for (int i = 0; i < mStatusCallbacks.length; i++) {
- mStatusCallbacks[i].onReportStatus(gnssStatus);
- }
+ Binder.withCleanCallingIdentity(() -> {
+ for (int i = 0; i < mStatusCallbacks.length; i++) {
+ mStatusCallbacks[i].onReportStatus(gnssStatus);
+ }
+ });
}
@NativeEntryPoint
void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
float[] elevations, float[] azimuths, float[] carrierFrequencies,
float[] basebandCn0DbHzs) {
- GnssStatus gnssStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations,
- azimuths, carrierFrequencies, basebandCn0DbHzs);
- for (int i = 0; i < mSvStatusCallbacks.length; i++) {
- mSvStatusCallbacks[i].onReportSvStatus(gnssStatus);
- }
+ Binder.withCleanCallingIdentity(() -> {
+ GnssStatus gnssStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations,
+ azimuths, carrierFrequencies, basebandCn0DbHzs);
+ for (int i = 0; i < mSvStatusCallbacks.length; i++) {
+ mSvStatusCallbacks[i].onReportSvStatus(gnssStatus);
+ }
+ });
}
@NativeEntryPoint
void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
- mAGpsCallbacks.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
+ Binder.withCleanCallingIdentity(
+ () -> mAGpsCallbacks.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr));
}
@NativeEntryPoint
void reportNmea(long timestamp) {
- if (mItarSpeedLimitExceeded) {
- return;
- }
+ Binder.withCleanCallingIdentity(() -> {
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
- for (int i = 0; i < mNmeaCallbacks.length; i++) {
- mNmeaCallbacks[i].onReportNmea(timestamp);
- }
+ for (int i = 0; i < mNmeaCallbacks.length; i++) {
+ mNmeaCallbacks[i].onReportNmea(timestamp);
+ }
+ });
}
@NativeEntryPoint
void reportMeasurementData(GnssMeasurementsEvent event) {
- if (mItarSpeedLimitExceeded) {
- return;
- }
+ Binder.withCleanCallingIdentity(() -> {
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
- for (int i = 0; i < mMeasurementCallbacks.length; i++) {
- mMeasurementCallbacks[i].onReportMeasurements(event);
- }
+ for (int i = 0; i < mMeasurementCallbacks.length; i++) {
+ mMeasurementCallbacks[i].onReportMeasurements(event);
+ }
+ });
}
@NativeEntryPoint
void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
- for (int i = 0; i < mAntennaInfoCallbacks.length; i++) {
- mAntennaInfoCallbacks[i].onReportAntennaInfo(antennaInfos);
- }
+ Binder.withCleanCallingIdentity(() -> {
+ for (int i = 0; i < mAntennaInfoCallbacks.length; i++) {
+ mAntennaInfoCallbacks[i].onReportAntennaInfo(antennaInfos);
+ }
+ });
}
@NativeEntryPoint
void reportNavigationMessage(GnssNavigationMessage event) {
- if (mItarSpeedLimitExceeded) {
- return;
- }
+ Binder.withCleanCallingIdentity(() -> {
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
- for (int i = 0; i < mNavigationMessageCallbacks.length; i++) {
- mNavigationMessageCallbacks[i].onReportNavigationMessage(event);
- }
+ for (int i = 0; i < mNavigationMessageCallbacks.length; i++) {
+ mNavigationMessageCallbacks[i].onReportNavigationMessage(event);
+ }
+ });
}
@NativeEntryPoint
@@ -1061,15 +1078,17 @@
private void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
GnssCapabilities newCapabilities) {
- if (newCapabilities.equals(oldCapabilities)) {
- return;
- }
+ Binder.withCleanCallingIdentity(() -> {
+ if (newCapabilities.equals(oldCapabilities)) {
+ return;
+ }
- Log.i(TAG, "gnss capabilities changed to " + newCapabilities);
+ Log.i(TAG, "gnss capabilities changed to " + newCapabilities);
- for (int i = 0; i < mBaseCallbacks.length; i++) {
- mBaseCallbacks[i].onCapabilitiesChanged(oldCapabilities, newCapabilities);
- }
+ for (int i = 0; i < mBaseCallbacks.length; i++) {
+ mBaseCallbacks[i].onCapabilitiesChanged(oldCapabilities, newCapabilities);
+ }
+ });
}
@NativeEntryPoint
@@ -1089,88 +1108,103 @@
@NativeEntryPoint
void reportLocationBatch(Location[] locations) {
- for (int i = 0; i < mLocationCallbacks.length; i++) {
- mLocationCallbacks[i].onReportLocations(locations);
- }
+ Binder.withCleanCallingIdentity(() -> {
+ for (int i = 0; i < mLocationCallbacks.length; i++) {
+ mLocationCallbacks[i].onReportLocations(locations);
+ }
+ });
}
@NativeEntryPoint
void psdsDownloadRequest(int psdsType) {
- mPsdsCallbacks.onRequestPsdsDownload(psdsType);
+ Binder.withCleanCallingIdentity(() -> mPsdsCallbacks.onRequestPsdsDownload(psdsType));
}
@NativeEntryPoint
void reportGeofenceTransition(int geofenceId, Location location, int transition,
long transitionTimestamp) {
- mGeofenceCallbacks.onReportGeofenceTransition(geofenceId, location, transition,
- transitionTimestamp);
+ Binder.withCleanCallingIdentity(
+ () -> mGeofenceCallbacks.onReportGeofenceTransition(geofenceId, location,
+ transition, transitionTimestamp));
}
@NativeEntryPoint
void reportGeofenceStatus(int status, Location location) {
- mGeofenceCallbacks.onReportGeofenceStatus(status, location);
+ Binder.withCleanCallingIdentity(
+ () -> mGeofenceCallbacks.onReportGeofenceStatus(status, location));
}
@NativeEntryPoint
void reportGeofenceAddStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
- mGeofenceCallbacks.onReportGeofenceAddStatus(geofenceId, status);
+ Binder.withCleanCallingIdentity(
+ () -> mGeofenceCallbacks.onReportGeofenceAddStatus(geofenceId, status));
}
@NativeEntryPoint
void reportGeofenceRemoveStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
- mGeofenceCallbacks.onReportGeofenceRemoveStatus(geofenceId, status);
+ Binder.withCleanCallingIdentity(
+ () -> mGeofenceCallbacks.onReportGeofenceRemoveStatus(geofenceId, status));
}
@NativeEntryPoint
void reportGeofencePauseStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
- mGeofenceCallbacks.onReportGeofencePauseStatus(geofenceId, status);
+ Binder.withCleanCallingIdentity(
+ () -> mGeofenceCallbacks.onReportGeofencePauseStatus(geofenceId, status));
}
@NativeEntryPoint
void reportGeofenceResumeStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
- mGeofenceCallbacks.onReportGeofenceResumeStatus(geofenceId, status);
+ Binder.withCleanCallingIdentity(
+ () -> mGeofenceCallbacks.onReportGeofenceResumeStatus(geofenceId, status));
}
@NativeEntryPoint
void reportNiNotification(int notificationId, int niType, int notifyFlags,
int timeout, int defaultResponse, String requestorId, String text,
int requestorIdEncoding, int textEncoding) {
- mNotificationCallbacks.onReportNiNotification(notificationId, niType, notifyFlags, timeout,
- defaultResponse, requestorId, text, requestorIdEncoding, textEncoding);
+ Binder.withCleanCallingIdentity(
+ () -> mNotificationCallbacks.onReportNiNotification(notificationId, niType,
+ notifyFlags, timeout, defaultResponse, requestorId, text,
+ requestorIdEncoding, textEncoding));
}
@NativeEntryPoint
void requestSetID(int flags) {
- mAGpsCallbacks.onRequestSetID(flags);
+ Binder.withCleanCallingIdentity(() -> mAGpsCallbacks.onRequestSetID(flags));
}
@NativeEntryPoint
void requestLocation(boolean independentFromGnss, boolean isUserEmergency) {
- mLocationRequestCallbacks.onRequestLocation(independentFromGnss, isUserEmergency);
+ Binder.withCleanCallingIdentity(
+ () -> mLocationRequestCallbacks.onRequestLocation(independentFromGnss,
+ isUserEmergency));
}
@NativeEntryPoint
void requestUtcTime() {
- mTimeCallbacks.onRequestUtcTime();
+ Binder.withCleanCallingIdentity(() -> mTimeCallbacks.onRequestUtcTime());
}
@NativeEntryPoint
void requestRefLocation() {
- mLocationRequestCallbacks.onRequestRefLocation();
+ Binder.withCleanCallingIdentity(
+ () -> mLocationRequestCallbacks.onRequestRefLocation());
}
@NativeEntryPoint
void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
String otherProtocolStackName, byte requestor, String requestorId,
byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
- mNotificationCallbacks.onReportNfwNotification(proxyAppPackageName, protocolStack,
- otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
- isCachedLocation);
+ Binder.withCleanCallingIdentity(
+ () -> mNotificationCallbacks.onReportNfwNotification(proxyAppPackageName,
+ protocolStack, otherProtocolStackName, requestor, requestorId, responseType,
+ inEmergencyMode, isCachedLocation));
}
@NativeEntryPoint
boolean isInEmergencySession() {
- return mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec());
+ return Binder.withCleanCallingIdentity(
+ () -> mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec()));
}
/**
diff --git a/services/core/java/com/android/server/location/injector/LocationUsageLogger.java b/services/core/java/com/android/server/location/injector/LocationUsageLogger.java
index 244a8e0..af21bcb 100644
--- a/services/core/java/com/android/server/location/injector/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/location/injector/LocationUsageLogger.java
@@ -49,9 +49,9 @@
* Log a location API usage event.
*/
public void logLocationApiUsage(int usageType, int apiInUse,
- String packageName, String provider, LocationRequest locationRequest,
- boolean hasListener, boolean hasIntent,
- Geofence geofence, boolean foreground) {
+ String packageName, String attributionTag, String provider,
+ LocationRequest locationRequest, boolean hasListener,
+ boolean hasIntent, Geofence geofence, boolean foreground) {
try {
if (hitApiUsageLogCap()) {
return;
@@ -84,7 +84,8 @@
isGeofenceNull
? LocationStatsEnums.RADIUS_UNKNOWN
: bucketizeRadius(geofence.getRadius()),
- categorizeActivityImportance(foreground));
+ categorizeActivityImportance(foreground),
+ attributionTag);
} catch (Exception e) {
// Swallow exceptions to avoid crashing LMS.
Log.w(TAG, "Failed to log API usage to statsd.", e);
@@ -114,7 +115,8 @@
/* isListenerNull= */ true,
/* isIntentNull= */ true),
/* bucketizedRadius= */ 0,
- LocationStatsEnums.IMPORTANCE_UNKNOWN);
+ LocationStatsEnums.IMPORTANCE_UNKNOWN,
+ /* attribution_tag */ null);
} catch (Exception e) {
Log.w(TAG, "Failed to log API usage to statsd.", e);
}
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 2aa6f28..dc8b1d0 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1854,6 +1854,7 @@
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
mName,
registration.getRequest(),
key instanceof PendingIntent,
@@ -1882,6 +1883,7 @@
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
mName,
registration.getRequest(),
key instanceof PendingIntent,
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 1acbabd..ca8202f 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -105,6 +105,12 @@
private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>();
/**
+ * A mapping from the set of App IDs that query other App IDs via library name to the
+ * list of packages that they can see.
+ */
+ private final SparseSetArray<Integer> mQueryableViaUsesLibrary = new SparseSetArray<>();
+
+ /**
* Executor for running reasonably short background tasks such as building the initial
* visibility cache.
*/
@@ -239,6 +245,7 @@
Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
+ Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary);
mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute;
mForceQueryable.addAll(orig.mForceQueryable);
mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames;
@@ -508,6 +515,22 @@
return false;
}
+ private static boolean canQueryViaUsesLibrary(AndroidPackage querying,
+ AndroidPackage potentialTarget) {
+ if (potentialTarget.getLibraryNames().isEmpty()) {
+ return false;
+ }
+ final List<String> libNames = potentialTarget.getLibraryNames();
+ for (int i = 0, size = libNames.size(); i < size; i++) {
+ final String libName = libNames.get(i);
+ if (querying.getUsesLibraries().contains(libName)
+ || querying.getUsesOptionalLibraries().contains(libName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static boolean matchesProviders(
Set<String> queriesAuthorities, AndroidPackage potentialTarget) {
for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) {
@@ -707,6 +730,9 @@
|| canQueryAsInstaller(existingSetting, newPkg)) {
mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
}
+ if (canQueryViaUsesLibrary(existingPkg, newPkg)) {
+ mQueryableViaUsesLibrary.add(existingSetting.appId, newPkgSetting.appId);
+ }
}
// now we'll evaluate our new package's ability to see existing packages
if (!mForceQueryable.contains(existingSetting.appId)) {
@@ -718,6 +744,9 @@
|| canQueryAsInstaller(newPkgSetting, existingPkg)) {
mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
}
+ if (canQueryViaUsesLibrary(newPkg, existingPkg)) {
+ mQueryableViaUsesLibrary.add(newPkgSetting.appId, existingSetting.appId);
+ }
}
// if either package instruments the other, mark both as visible to one another
if (newPkgSetting.pkg != null && existingSetting.pkg != null
@@ -1035,6 +1064,10 @@
for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId);
}
+ mQueryableViaUsesLibrary.remove(setting.appId);
+ for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) {
+ mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i), setting.appId);
+ }
mForceQueryable.remove(setting.appId);
@@ -1315,6 +1348,18 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary");
+ if (mQueryableViaUsesLibrary.contains(callingAppId, targetAppId)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting, "queryable for library users");
+ }
+ return false;
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
return true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -1394,6 +1439,8 @@
filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
mImplicitlyQueryable, " ", expandPackages);
}
+ pw.println(" queryable via uses-library:");
+ dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages);
}
private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId,
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index b34611b..29322e2 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -180,6 +180,8 @@
mId = id;
mListener = listener;
mDataLoader = null;
+
+ callListener(IDataLoaderStatusListener.DATA_LOADER_BINDING);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 58e2aa2..bafe987 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1011,8 +1011,9 @@
"DataLoader installation of APEX modules is not allowed.");
}
- if (this.params.dataLoaderParams.getComponentName().getPackageName()
- == SYSTEM_DATA_LOADER_PACKAGE && mContext.checkCallingOrSelfPermission(
+ boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals(
+ this.params.dataLoaderParams.getComponentName().getPackageName());
+ if (systemDataLoader && mContext.checkCallingOrSelfPermission(
Manifest.permission.USE_SYSTEM_DATA_LOADERS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("You need the "
@@ -3060,7 +3061,7 @@
// Also stage .dm.fsv_sig. .dm may be required to install with fs-verity signature on
// supported on older devices.
maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile,
- VerityUtils.isFsVeritySupported() && DexMetadataHelper.isFsVerityRequired());
+ DexMetadataHelper.isFsVerityRequired());
}
private void storeBytesToInstallationFile(final String localPath, final String absolutePath,
@@ -3653,6 +3654,7 @@
@Override
public void onStatusChanged(int dataLoaderId, int status) {
switch (status) {
+ case IDataLoaderStatusListener.DATA_LOADER_BINDING:
case IDataLoaderStatusListener.DATA_LOADER_STOPPED:
case IDataLoaderStatusListener.DATA_LOADER_DESTROYED:
return;
@@ -3763,8 +3765,8 @@
healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
- final boolean systemDataLoader =
- params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE;
+ final boolean systemDataLoader = SYSTEM_DATA_LOADER_PACKAGE.equals(
+ params.getComponentName().getPackageName());
final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff87f1c..dfe72b2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -410,6 +410,7 @@
import com.android.server.utils.WatchedArrayMap;
import com.android.server.utils.WatchedLongSparseArray;
import com.android.server.utils.WatchedSparseBooleanArray;
+import com.android.server.utils.WatchedSparseIntArray;
import com.android.server.utils.Watcher;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -892,7 +893,7 @@
// that created the isolated process.
@Watched
@GuardedBy("mLock")
- final SparseIntArray mIsolatedOwners = new SparseIntArray();
+ final WatchedSparseIntArray mIsolatedOwners = new WatchedSparseIntArray();
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -1795,7 +1796,7 @@
public static final int SNAPPED = 2;
public final Settings settings;
- public final SparseIntArray isolatedOwners;
+ public final WatchedSparseIntArray isolatedOwners;
public final WatchedArrayMap<String, AndroidPackage> packages;
public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibs;
public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> staticLibs;
@@ -1814,7 +1815,7 @@
Snapshot(int type) {
if (type == Snapshot.SNAPPED) {
settings = mSettings.snapshot();
- isolatedOwners = mIsolatedOwners.clone();
+ isolatedOwners = mIsolatedOwners.snapshot();
packages = mPackages.snapshot();
sharedLibs = mSharedLibraries.snapshot();
staticLibs = mStaticLibsByDeclaringPackage.snapshot();
@@ -2016,7 +2017,7 @@
// Cached attributes. The names in this class are the same as the
// names in PackageManagerService; see that class for documentation.
private final Settings mSettings;
- private final SparseIntArray mIsolatedOwners;
+ private final WatchedSparseIntArray mIsolatedOwners;
private final WatchedArrayMap<String, AndroidPackage> mPackages;
private final WatchedArrayMap<ComponentName, ParsedInstrumentation>
mInstrumentation;
@@ -3551,7 +3552,7 @@
public String getInstantAppPackageName(int callingUid) {
// If the caller is an isolated app use the owner's uid for the lookup.
if (Process.isIsolated(callingUid)) {
- callingUid = mIsolatedOwners.get(callingUid);
+ callingUid = getIsolatedOwner(callingUid);
}
final int appId = UserHandle.getAppId(callingUid);
final Object obj = mSettings.getSettingLPr(appId);
@@ -3563,6 +3564,19 @@
return null;
}
+ /**
+ * Finds the owner for the provided isolated UID. Throws IllegalStateException if no such
+ * isolated UID is found.
+ */
+ private int getIsolatedOwner(int isolatedUid) {
+ final int ownerUid = mIsolatedOwners.get(isolatedUid, -1);
+ if (ownerUid == -1) {
+ throw new IllegalStateException(
+ "No owner UID found for isolated UID " + isolatedUid);
+ }
+ return ownerUid;
+ }
+
public String resolveExternalPackageNameLPr(AndroidPackage pkg) {
if (pkg.getStaticSharedLibName() != null) {
return pkg.getManifestPackageName();
@@ -3929,7 +3943,7 @@
public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
int callingUid) {
if (Process.isIsolated(callingUid)) {
- callingUid = mIsolatedOwners.get(callingUid);
+ callingUid = getIsolatedOwner(callingUid);
}
final PackageSetting ps = mSettings.getPackageLPr(packageName);
final boolean returnAllowed =
@@ -4083,7 +4097,7 @@
@Nullable ComponentName component, @ComponentType int componentType, int userId) {
// if we're in an isolated process, get the real calling UID
if (Process.isIsolated(callingUid)) {
- callingUid = mIsolatedOwners.get(callingUid);
+ callingUid = getIsolatedOwner(callingUid);
}
final String instantAppPkgName = getInstantAppPackageName(callingUid);
final boolean callerIsInstantApp = instantAppPkgName != null;
@@ -6164,6 +6178,7 @@
mAppsFilter.registerObserver(mWatcher);
mInstantAppRegistry.registerObserver(mWatcher);
mSettings.registerObserver(mWatcher);
+ mIsolatedOwners.registerObserver(mWatcher);
// If neither "build" attribute is true then this may be a mockito test, and verification
// can fail as a false positive.
Watchable.verifyWatchedAttributes(this, mWatcher, !(mIsEngBuild || mIsUserDebugBuild));
@@ -27803,13 +27818,23 @@
}
private static String getDefaultTimeouts() {
- return DeviceConfig.getString(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
- PROPERTY_INCFS_DEFAULT_TIMEOUTS, "");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE,
+ PROPERTY_INCFS_DEFAULT_TIMEOUTS, "");
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private static String getKnownDigestersList() {
- return DeviceConfig.getString(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
- PROPERTY_KNOWN_DIGESTERS_LIST, "");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getString(NAMESPACE_PACKAGE_MANAGER_SERVICE,
+ PROPERTY_KNOWN_DIGESTERS_LIST, "");
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 0c2b4c5..b4bcde7 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -80,14 +80,14 @@
* been preserved for migration purposes, but is otherwise ignored. Corresponds to
* {@link PackageManager#INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS}.
*/
- int APPROVAL_LEVEL_LEGACY_ALWAYS = 1;
+ int APPROVAL_LEVEL_LEGACY_ALWAYS = 2;
/**
* The app has been chosen by the user through
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
* indicating an explicit choice to use this app to open an unverified domain.
*/
- int APPROVAL_LEVEL_SELECTION = 2;
+ int APPROVAL_LEVEL_SELECTION = 3;
/**
* The app is approved through the digital asset link statement being hosted at the domain
@@ -95,7 +95,7 @@
* {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)} by
* the domain verification agent on device.
*/
- int APPROVAL_LEVEL_VERIFIED = 3;
+ int APPROVAL_LEVEL_VERIFIED = 4;
/**
* The app has been installed as an instant app, which grants it total authority on the domains
@@ -105,7 +105,7 @@
* The user is still able to disable instant app link handling through
* {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String, boolean)}.
*/
- int APPROVAL_LEVEL_INSTANT_APP = 4;
+ int APPROVAL_LEVEL_INSTANT_APP = 5;
/**
* Defines the possible values for {@link #approvalLevelForDomain(PackageSetting, Intent, int)}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 047e3b3..ffea6a7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -345,6 +345,9 @@
*/
private final Object mLock = new Object();
+ /** List of {@link ScreenOnListener}s which do not belong to the default display. */
+ private final SparseArray<ScreenOnListener> mScreenOnListeners = new SparseArray<>();
+
Context mContext;
IWindowManager mWindowManager;
WindowManagerFuncs mWindowManagerFuncs;
@@ -434,8 +437,25 @@
volatile boolean mBeganFromNonInteractive;
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
- volatile boolean mGoingToSleep;
- volatile boolean mRequestedOrGoingToSleep;
+
+ /**
+ * {@code true} if the device is entering a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mRequestedOrSleepingDefaultDisplay} which tracks the power state
+ * of the {@link #mDefaultDisplay default display} versus the power state of the entire device.
+ */
+ volatile boolean mDeviceGoingToSleep;
+
+ /**
+ * {@code true} if the {@link #mDefaultDisplay default display} is entering or was requested to
+ * enter a low-power state; {@code false otherwise}.
+ *
+ * <p>This differs from {@link #mDeviceGoingToSleep} which tracks the power state of the entire
+ * device versus the power state of the {@link #mDefaultDisplay default display}.
+ */
+ // TODO(b/178103325): Track sleep/requested sleep for every display.
+ volatile boolean mRequestedOrSleepingDefaultDisplay;
+
volatile boolean mRecentsVisible;
volatile boolean mNavBarVirtualKeyHapticFeedbackEnabled = true;
volatile boolean mPictureInPictureVisible;
@@ -917,13 +937,14 @@
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, 0);
+ sleepDefaultDisplayFromPowerButton(eventTime, 0);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
- goToSleepFromPowerButton(eventTime, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ sleepDefaultDisplayFromPowerButton(eventTime,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
- if (goToSleepFromPowerButton(eventTime,
+ if (sleepDefaultDisplayFromPowerButton(eventTime,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE)) {
launchHomeFromHotKey(DEFAULT_DISPLAY);
}
@@ -951,11 +972,12 @@
}
/**
- * Sends the device to sleep as a result of a power button press.
+ * Sends the default display to sleep as a result of a power button press.
*
- * @return True if the was device was sent to sleep, false if sleep was suppressed.
+ * @return {@code true} if the device was sent to sleep, {@code false} if the device did not
+ * sleep.
*/
- private boolean goToSleepFromPowerButton(long eventTime, int flags) {
+ private boolean sleepDefaultDisplayFromPowerButton(long eventTime, int flags) {
// Before we actually go to sleep, we check the last wakeup reason.
// If the device very recently woke up from a gesture (like user lifting their device)
// then ignore the sleep instruction. This is because users have developed
@@ -975,12 +997,12 @@
}
}
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags);
return true;
}
- private void goToSleep(long eventTime, int reason, int flags) {
- mRequestedOrGoingToSleep = true;
+ private void sleepDefaultDisplay(long eventTime, int reason, int flags) {
+ mRequestedOrSleepingDefaultDisplay = true;
mPowerManager.goToSleep(eventTime, reason, flags);
}
@@ -1017,7 +1039,8 @@
Settings.Global.THEATER_MODE_ON, 1);
if (mGoToSleepOnButtonPressTheaterMode && interactive) {
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+ 0);
}
}
break;
@@ -1126,7 +1149,7 @@
case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
Slog.i(TAG, "sleepRelease() calling goToSleep(GO_TO_SLEEP_REASON_SLEEP_BUTTON)");
- goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+ sleepDefaultDisplay(eventTime, PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
break;
}
}
@@ -3511,7 +3534,7 @@
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- goToSleep(event.getEventTime(),
+ sleepDefaultDisplay(event.getEventTime(),
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
isWakeKey = false;
}
@@ -3538,10 +3561,12 @@
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
+ final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
+ final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
if (down) {
- interceptPowerKeyDown(event, interactive);
+ interceptPowerKeyDown(event, interactiveAndOn);
} else {
- interceptPowerKeyUp(event, interactive, canceled);
+ interceptPowerKeyUp(event, interactiveAndOn, canceled);
}
break;
}
@@ -3746,7 +3771,7 @@
final MutableBoolean outLaunched = new MutableBoolean(false);
final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event,
interactive, outLaunched);
- if (outLaunched.value && mRequestedOrGoingToSleep) {
+ if (outLaunched.value && mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
return gesturedServiceIntercepted;
@@ -4088,8 +4113,8 @@
pmSleepReason)) + ")");
}
- mGoingToSleep = true;
- mRequestedOrGoingToSleep = true;
+ mDeviceGoingToSleep = true;
+ mRequestedOrSleepingDefaultDisplay = true;
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(pmSleepReason);
@@ -4108,8 +4133,8 @@
}
MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
- mGoingToSleep = false;
- mRequestedOrGoingToSleep = false;
+ mDeviceGoingToSleep = false;
+ mRequestedOrSleepingDefaultDisplay = false;
mDefaultDisplayPolicy.setAwake(false);
// We must get this work done here because the power manager will drop
@@ -4253,21 +4278,25 @@
// Called on the DisplayManager's DisplayPowerController thread.
@Override
public void screenTurnedOff(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Display" + displayId + " turned off...");
- if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
-
- updateScreenOffSleepToken(true);
- mDefaultDisplayPolicy.screenTurnedOff();
- synchronized (mLock) {
- if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onScreenTurnedOff();
+ if (displayId == DEFAULT_DISPLAY) {
+ updateScreenOffSleepToken(true);
+ mRequestedOrSleepingDefaultDisplay = false;
+ mDefaultDisplayPolicy.screenTurnedOff();
+ synchronized (mLock) {
+ if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.onScreenTurnedOff();
+ }
+ }
+ mDefaultDisplayRotation.updateOrientationListener();
+ reportScreenStateToVrManager(false);
+ if (mCameraGestureTriggeredDuringGoingToSleep) {
+ wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromPowerKey,
+ PowerManager.WAKE_REASON_CAMERA_LAUNCH,
+ "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
}
}
- mDefaultDisplayRotation.updateOrientationListener();
- reportScreenStateToVrManager(false);
}
private long getKeyguardDrawnTimeout() {
@@ -4280,27 +4309,28 @@
// Called on the DisplayManager's DisplayPowerController thread.
@Override
public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turning on...");
- if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
+ if (displayId == DEFAULT_DISPLAY) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn",
+ 0 /* cookie */);
+ updateScreenOffSleepToken(false);
+ mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
- Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
- updateScreenOffSleepToken(false);
- mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
-
- synchronized (mLock) {
- if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
- mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
- getKeyguardDrawnTimeout());
- mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
- } else {
- if (DEBUG_WAKEUP) Slog.d(TAG,
- "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
- mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+ synchronized (mLock) {
+ if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
+ mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+ mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
+ getKeyguardDrawnTimeout());
+ mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
+ } else {
+ if (DEBUG_WAKEUP) Slog.d(TAG,
+ "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
+ mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+ }
}
+ } else {
+ mScreenOnListeners.put(displayId, screenOnListener);
}
}
@@ -4321,11 +4351,12 @@
@Override
public void screenTurningOff(int displayId, ScreenOffListener screenOffListener) {
+ mWindowManagerFuncs.screenTurningOff(displayId, screenOffListener);
if (displayId != DEFAULT_DISPLAY) {
return;
}
- mWindowManagerFuncs.screenTurningOff(screenOffListener);
+ mRequestedOrSleepingDefaultDisplay = true;
synchronized (mLock) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onScreenTurningOff();
@@ -4380,6 +4411,14 @@
listener.onScreenOn();
}
+ for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) {
+ final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i);
+ if (screenOnListener != null) {
+ screenOnListener.onScreenOn();
+ }
+ }
+ mScreenOnListeners.clear();
+
if (enableScreen) {
try {
mWindowManager.enableScreenIfNeeded();
@@ -4410,7 +4449,7 @@
@Override
public boolean okToAnimate() {
- return mDefaultDisplayPolicy.isAwake() && !mGoingToSleep;
+ return mDefaultDisplayPolicy.isAwake() && !mDeviceGoingToSleep;
}
/** {@inheritDoc} */
@@ -4777,7 +4816,7 @@
mWindowManagerFuncs.lockDeviceNow();
break;
case LID_BEHAVIOR_SLEEP:
- goToSleep(SystemClock.uptimeMillis(),
+ sleepDefaultDisplay(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
diff --git a/services/core/java/com/android/server/policy/SplashScreenSurface.java b/services/core/java/com/android/server/policy/SplashScreenSurface.java
index b9202c3..72933a0 100644
--- a/services/core/java/com/android/server/policy/SplashScreenSurface.java
+++ b/services/core/java/com/android/server/policy/SplashScreenSurface.java
@@ -45,7 +45,7 @@
}
@Override
- public void remove() {
+ public void remove(boolean animate) {
if (DEBUG_SPLASH_SCREEN) Slog.v(TAG, "Removing splash screen window for " + mAppToken + ": "
+ this + " Callers=" + Debug.getCallers(4));
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index b5a9aca..0735977b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -238,8 +238,9 @@
/**
* Removes the starting window surface. Do not hold the window manager lock when calling
* this method!
+ * @param animate Whether need to play the default exit animation for starting window.
*/
- void remove();
+ void remove(boolean animate);
}
/**
@@ -303,9 +304,10 @@
/**
* Notifies the window manager that screen is being turned off.
*
+ * @param displayId the ID of the display which is turning off
* @param listener callback to call when display can be turned off
*/
- void screenTurningOff(ScreenOffListener listener);
+ void screenTurningOff(int displayId, ScreenOffListener listener);
/**
* Convert the lid state to a human readable format.
diff --git a/services/core/java/com/android/server/power/PreRebootLogger.java b/services/core/java/com/android/server/power/PreRebootLogger.java
index 2e4b054..c9e81ed 100644
--- a/services/core/java/com/android/server/power/PreRebootLogger.java
+++ b/services/core/java/com/android/server/power/PreRebootLogger.java
@@ -19,7 +19,6 @@
import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.content.Context;
-import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -147,7 +146,6 @@
return;
}
- final long token = Binder.clearCallingIdentity();
try {
final File dumpFile = new File(dumpDir, serviceName);
final ParcelFileDescriptor fd = ParcelFileDescriptor.open(dumpFile,
@@ -156,8 +154,6 @@
binder.dump(fd.getFileDescriptor(), ArrayUtils.emptyArray(String.class));
} catch (FileNotFoundException | RemoteException e) {
Slog.e(TAG, String.format("Failed to dump %s service before reboot", serviceName), e);
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 3a08ddc..fc62f5b 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -24,6 +24,7 @@
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.content.rollback.RollbackInfo;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.system.ErrnoException;
import android.system.Os;
@@ -227,6 +228,15 @@
packageSessionIds, extensionVersions);
}
+ private static boolean isLinkPossible(File oldFile, File newFile) {
+ try {
+ return Os.stat(oldFile.getAbsolutePath()).st_dev
+ == Os.stat(newFile.getAbsolutePath()).st_dev;
+ } catch (ErrnoException ignore) {
+ return false;
+ }
+ }
+
/**
* Creates a backup copy of an apk or apex for a package.
* For packages containing splits, this method should be called for each
@@ -239,16 +249,29 @@
targetDir.mkdirs();
File targetFile = new File(targetDir, sourceFile.getName());
- try {
- // Create a hard link to avoid copy
- // TODO(b/168562373)
- // Linking between non-encrypted and encrypted is not supported and we have
- // encrypted /data/rollback and non-encrypted /data/apex/active. For now this works
- // because we happen to store encrypted files under /data/apex/active which is no
- // longer the case when compressed apex rolls out. We have to handle this case in
- // order not to fall back to copy.
- Os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
- } catch (ErrnoException ignore) {
+ boolean fallbackToCopy = !isLinkPossible(sourceFile, targetFile);
+ if (!fallbackToCopy) {
+ try {
+ // Create a hard link to avoid copy
+ // TODO(b/168562373)
+ // Linking between non-encrypted and encrypted is not supported and we have
+ // encrypted /data/rollback and non-encrypted /data/apex/active. For now this works
+ // because we happen to store encrypted files under /data/apex/active which is no
+ // longer the case when compressed apex rolls out. We have to handle this case in
+ // order not to fall back to copy.
+ Os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
+ } catch (ErrnoException e) {
+ boolean isRollbackTest =
+ SystemProperties.getBoolean("persist.rollback.is_test", false);
+ if (isRollbackTest) {
+ throw new IOException(e);
+ } else {
+ fallbackToCopy = true;
+ }
+ }
+ }
+
+ if (fallbackToCopy) {
// Fall back to copy if hardlink can't be created
Files.copy(sourceFile.toPath(), targetFile.toPath());
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 7523671..970420a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -160,4 +160,10 @@
* Handles a logging command from the WM shell command.
*/
void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd);
+
+ /**
+ * @see com.android.internal.statusbar.IStatusBar#setNavigationBarLumaSamplingEnabled(int,
+ * boolean)
+ */
+ void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 546e420..302a23f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -588,6 +588,15 @@
} catch (RemoteException ex) { }
}
}
+
+ @Override
+ public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ if (mBar != null) {
+ try {
+ mBar.setNavigationBarLumaSamplingEnabled(displayId, enable);
+ } catch (RemoteException ex) { }
+ }
+ }
};
private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
new file mode 100644
index 0000000..c8c828f
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static libcore.io.IoUtils.closeQuietly;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A class that provides time zone detector state information for metrics.
+ *
+ * <p>
+ * Regarding time zone ID ordinals:
+ * <p>
+ * We don't want to leak user location information by reporting time zone IDs. Instead, time zone
+ * IDs are consistently identified within a given instance of this class by a numeric ID. This
+ * allows comparison of IDs without revealing what those IDs are.
+ */
+public final class MetricsTimeZoneDetectorState {
+
+ @IntDef(prefix = "DETECTION_MODE_",
+ value = { DETECTION_MODE_MANUAL, DETECTION_MODE_GEO, DETECTION_MODE_TELEPHONY})
+ @interface DetectionMode {};
+
+ @DetectionMode
+ public static final int DETECTION_MODE_MANUAL = 0;
+ @DetectionMode
+ public static final int DETECTION_MODE_GEO = 1;
+ @DetectionMode
+ public static final int DETECTION_MODE_TELEPHONY = 2;
+
+ @NonNull
+ private final ConfigurationInternal mConfigurationInternal;
+ @NonNull
+ private final int mDeviceTimeZoneIdOrdinal;
+ @Nullable
+ private final MetricsTimeZoneSuggestion mLatestManualSuggestion;
+ @Nullable
+ private final MetricsTimeZoneSuggestion mLatestTelephonySuggestion;
+ @Nullable
+ private final MetricsTimeZoneSuggestion mLatestGeolocationSuggestion;
+
+ private MetricsTimeZoneDetectorState(
+ @NonNull ConfigurationInternal configurationInternal,
+ int deviceTimeZoneIdOrdinal,
+ @Nullable MetricsTimeZoneSuggestion latestManualSuggestion,
+ @Nullable MetricsTimeZoneSuggestion latestTelephonySuggestion,
+ @Nullable MetricsTimeZoneSuggestion latestGeolocationSuggestion) {
+ mConfigurationInternal = Objects.requireNonNull(configurationInternal);
+ mDeviceTimeZoneIdOrdinal = deviceTimeZoneIdOrdinal;
+ mLatestManualSuggestion = latestManualSuggestion;
+ mLatestTelephonySuggestion = latestTelephonySuggestion;
+ mLatestGeolocationSuggestion = latestGeolocationSuggestion;
+ }
+
+ /**
+ * Creates {@link MetricsTimeZoneDetectorState} from the supplied parameters, using the {@link
+ * OrdinalGenerator} to generate time zone ID ordinals.
+ */
+ public static MetricsTimeZoneDetectorState create(
+ @NonNull OrdinalGenerator<String> tzIdOrdinalGenerator,
+ @NonNull ConfigurationInternal configurationInternal,
+ @NonNull String deviceTimeZoneId,
+ @Nullable ManualTimeZoneSuggestion latestManualSuggestion,
+ @Nullable TelephonyTimeZoneSuggestion latestTelephonySuggestion,
+ @Nullable GeolocationTimeZoneSuggestion latestGeolocationSuggestion) {
+
+ // TODO(b/172934905) Add logic to canonicalize the time zone IDs to Android's preferred IDs
+ // so that the ordinals will match even when the ID is not identical, just equivalent.
+ int deviceTimeZoneIdOrdinal =
+ tzIdOrdinalGenerator.ordinal(Objects.requireNonNull(deviceTimeZoneId));
+ MetricsTimeZoneSuggestion latestObfuscatedManualSuggestion =
+ createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestManualSuggestion);
+ MetricsTimeZoneSuggestion latestObfuscatedTelephonySuggestion =
+ createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestTelephonySuggestion);
+ MetricsTimeZoneSuggestion latestObfuscatedGeolocationSuggestion =
+ createMetricsTimeZoneSuggestion(tzIdOrdinalGenerator, latestGeolocationSuggestion);
+
+ return new MetricsTimeZoneDetectorState(
+ configurationInternal, deviceTimeZoneIdOrdinal, latestObfuscatedManualSuggestion,
+ latestObfuscatedTelephonySuggestion, latestObfuscatedGeolocationSuggestion);
+ }
+
+ /** Returns true if the device supports telephony time zone detection. */
+ public boolean isTelephonyDetectionSupported() {
+ return mConfigurationInternal.isTelephonyDetectionSupported();
+ }
+
+ /** Returns true if the device supports geolocation time zone detection. */
+ public boolean isGeoDetectionSupported() {
+ return mConfigurationInternal.isGeoDetectionSupported();
+ }
+
+ /** Returns true if user's location can be used generally. */
+ public boolean isUserLocationEnabled() {
+ return mConfigurationInternal.isLocationEnabled();
+ }
+
+ /** Returns the value of the geolocation time zone detection enabled setting. */
+ public boolean getGeoDetectionEnabledSetting() {
+ return mConfigurationInternal.getGeoDetectionEnabledSetting();
+ }
+
+ /** Returns the value of the auto time zone detection enabled setting. */
+ public boolean getAutoDetectionEnabledSetting() {
+ return mConfigurationInternal.getAutoDetectionEnabledSetting();
+ }
+
+ /**
+ * Returns the detection mode the device is currently using, which can be influenced by various
+ * things besides the user's setting.
+ */
+ @DetectionMode
+ public int getDetectionMode() {
+ if (!mConfigurationInternal.getAutoDetectionEnabledBehavior()) {
+ return DETECTION_MODE_MANUAL;
+ } else if (mConfigurationInternal.getGeoDetectionEnabledBehavior()) {
+ return DETECTION_MODE_GEO;
+ } else {
+ return DETECTION_MODE_TELEPHONY;
+ }
+ }
+
+ /**
+ * Returns the ordinal for the device's currently set time zone ID.
+ * See {@link MetricsTimeZoneDetectorState} for information about ordinals.
+ */
+ @NonNull
+ public int getDeviceTimeZoneIdOrdinal() {
+ return mDeviceTimeZoneIdOrdinal;
+ }
+
+ /**
+ * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last manual
+ * suggestion received.
+ */
+ @Nullable
+ public byte[] getLatestManualSuggestionProtoBytes() {
+ return suggestionProtoBytes(mLatestManualSuggestion);
+ }
+
+ /**
+ * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last, best
+ * telephony suggestion received.
+ */
+ @Nullable
+ public byte[] getLatestTelephonySuggestionProtoBytes() {
+ return suggestionProtoBytes(mLatestTelephonySuggestion);
+ }
+
+ /**
+ * Returns bytes[] for a {@link MetricsTimeZoneSuggestion} for the last geolocation
+ * suggestion received.
+ */
+ @Nullable
+ public byte[] getLatestGeolocationSuggestionProtoBytes() {
+ return suggestionProtoBytes(mLatestGeolocationSuggestion);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MetricsTimeZoneDetectorState that = (MetricsTimeZoneDetectorState) o;
+ return mDeviceTimeZoneIdOrdinal == that.mDeviceTimeZoneIdOrdinal
+ && mConfigurationInternal.equals(that.mConfigurationInternal)
+ && Objects.equals(mLatestManualSuggestion, that.mLatestManualSuggestion)
+ && Objects.equals(mLatestTelephonySuggestion, that.mLatestTelephonySuggestion)
+ && Objects.equals(mLatestGeolocationSuggestion, that.mLatestGeolocationSuggestion);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mConfigurationInternal, mDeviceTimeZoneIdOrdinal,
+ mLatestManualSuggestion, mLatestTelephonySuggestion, mLatestGeolocationSuggestion);
+ }
+
+ @Override
+ public String toString() {
+ return "MetricsTimeZoneDetectorState{"
+ + "mConfigurationInternal=" + mConfigurationInternal
+ + ", mDeviceTimeZoneIdOrdinal=" + mDeviceTimeZoneIdOrdinal
+ + ", mLatestManualSuggestion=" + mLatestManualSuggestion
+ + ", mLatestTelephonySuggestion=" + mLatestTelephonySuggestion
+ + ", mLatestGeolocationSuggestion=" + mLatestGeolocationSuggestion
+ + '}';
+ }
+
+ private static byte[] suggestionProtoBytes(
+ @Nullable MetricsTimeZoneSuggestion suggestion) {
+ if (suggestion == null) {
+ return null;
+ }
+ return suggestion.toBytes();
+ }
+
+ @Nullable
+ private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
+ @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
+ @NonNull ManualTimeZoneSuggestion manualSuggestion) {
+ if (manualSuggestion == null) {
+ return null;
+ }
+
+ int zoneIdOrdinal = zoneIdOrdinalGenerator.ordinal(manualSuggestion.getZoneId());
+ return MetricsTimeZoneSuggestion.createCertain(
+ new int[] { zoneIdOrdinal });
+ }
+
+ @Nullable
+ private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
+ @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
+ @NonNull TelephonyTimeZoneSuggestion telephonySuggestion) {
+ if (telephonySuggestion == null) {
+ return null;
+ }
+ if (telephonySuggestion.getZoneId() == null) {
+ return MetricsTimeZoneSuggestion.createUncertain();
+ }
+ int zoneIdOrdinal = zoneIdOrdinalGenerator.ordinal(telephonySuggestion.getZoneId());
+ return MetricsTimeZoneSuggestion.createCertain(new int[] { zoneIdOrdinal });
+ }
+
+ @Nullable
+ private static MetricsTimeZoneSuggestion createMetricsTimeZoneSuggestion(
+ @NonNull OrdinalGenerator<String> zoneIdOrdinalGenerator,
+ @Nullable GeolocationTimeZoneSuggestion geolocationSuggestion) {
+ if (geolocationSuggestion == null) {
+ return null;
+ }
+
+ List<String> zoneIds = geolocationSuggestion.getZoneIds();
+ if (zoneIds == null) {
+ return MetricsTimeZoneSuggestion.createUncertain();
+ }
+ return MetricsTimeZoneSuggestion.createCertain(zoneIdOrdinalGenerator.ordinals(zoneIds));
+ }
+
+ /**
+ * A Java class that closely matches the android.app.time.MetricsTimeZoneSuggestion
+ * proto definition.
+ */
+ private static final class MetricsTimeZoneSuggestion {
+ @Nullable
+ private final int[] mZoneIdOrdinals;
+
+ MetricsTimeZoneSuggestion(@Nullable int[] zoneIdOrdinals) {
+ mZoneIdOrdinals = zoneIdOrdinals;
+ }
+
+ @NonNull
+ static MetricsTimeZoneSuggestion createUncertain() {
+ return new MetricsTimeZoneSuggestion(null);
+ }
+
+ public static MetricsTimeZoneSuggestion createCertain(
+ @NonNull int[] zoneIdOrdinals) {
+ return new MetricsTimeZoneSuggestion(zoneIdOrdinals);
+ }
+
+ boolean isCertain() {
+ return mZoneIdOrdinals != null;
+ }
+
+ @Nullable
+ int[] getZoneIdOrdinals() {
+ return mZoneIdOrdinals;
+ }
+
+ byte[] toBytes() {
+ // We don't get access to the atoms.proto definition for nested proto fields, so we use
+ // an identically specified proto.
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ ProtoOutputStream protoOutputStream = new ProtoOutputStream(byteArrayOutputStream);
+ int typeProtoValue = isCertain()
+ ? android.app.time.MetricsTimeZoneSuggestion.CERTAIN
+ : android.app.time.MetricsTimeZoneSuggestion.UNCERTAIN;
+ protoOutputStream.write(android.app.time.MetricsTimeZoneSuggestion.TYPE,
+ typeProtoValue);
+ if (isCertain()) {
+ for (int zoneIdOrdinal : getZoneIdOrdinals()) {
+ protoOutputStream.write(
+ android.app.time.MetricsTimeZoneSuggestion.TIME_ZONE_ORDINALS,
+ zoneIdOrdinal);
+ }
+ }
+ protoOutputStream.flush();
+ closeQuietly(byteArrayOutputStream);
+ return byteArrayOutputStream.toByteArray();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MetricsTimeZoneSuggestion that = (MetricsTimeZoneSuggestion) o;
+ return Arrays.equals(mZoneIdOrdinals, that.mZoneIdOrdinals);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(mZoneIdOrdinals);
+ }
+
+ @Override
+ public String toString() {
+ return "MetricsTimeZoneSuggestion{"
+ + "mZoneIdOrdinals=" + Arrays.toString(mZoneIdOrdinals)
+ + '}';
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
new file mode 100644
index 0000000..a448773
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/OrdinalGenerator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.timezonedetector;
+
+import android.util.ArraySet;
+
+import java.util.List;
+
+/**
+ * A helper class that turns a set of objects into ordinal values, i.e. each object is offered
+ * up via {@link #ordinal(Object)} or similar method, and a number will be returned. If the
+ * object has been seen before by the instance then the same number will be returned. Intended
+ * for situations where it is useful to know if values from some finite set are the same or
+ * different, but the value is either large or may reveal PII. This class relies on {@link
+ * Object#equals(Object)} and {@link Object#hashCode()}.
+ */
+class OrdinalGenerator<T> {
+ private final ArraySet<T> mKnownIds = new ArraySet<>();
+
+ int ordinal(T object) {
+ int ordinal = mKnownIds.indexOf(object);
+ if (ordinal < 0) {
+ ordinal = mKnownIds.size();
+ mKnownIds.add(object);
+ }
+ return ordinal;
+ }
+
+ int[] ordinals(List<T> objects) {
+ int[] ordinals = new int[objects.size()];
+ for (int i = 0; i < ordinals.length; i++) {
+ ordinals[i] = ordinal(objects.get(i));
+ }
+ return ordinals;
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index cd220b1..d429b87 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -50,4 +50,8 @@
* available, and so on. This method may be implemented asynchronously.
*/
void suggestGeolocationTimeZone(@NonNull GeolocationTimeZoneSuggestion timeZoneSuggestion);
+
+ /** Generates a state snapshot for metrics. */
+ @NonNull
+ MetricsTimeZoneDetectorState generateMetricsState();
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index 7ba20ee..4e78f5a 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -90,4 +90,10 @@
mHandler.post(
() -> mTimeZoneDetectorStrategy.suggestGeolocationTimeZone(timeZoneSuggestion));
}
+
+ @Override
+ @NonNull
+ public MetricsTimeZoneDetectorState generateMetricsState() {
+ return mTimeZoneDetectorStrategy.generateMetricsState();
+ }
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 8266f12..e3f31b6 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -66,9 +66,10 @@
* <p>Threading:
*
* <p>Suggestion calls with a void return type may be handed off to a separate thread and handled
- * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()}, and debug
- * calls like {@link #dump(IndentingPrintWriter, String[])}, may be called on a different thread
- * concurrently with other operations.
+ * asynchronously. Synchronous calls like {@link #getCurrentUserConfigurationInternal()},
+ * {@link #generateMetricsState()} and debug calls like {@link
+ * #dump(IndentingPrintWriter, String[])}, may be called on a different thread concurrently with
+ * other operations.
*
* @hide
*/
@@ -123,4 +124,8 @@
* suggestion.
*/
void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
+
+ /** Generates a state snapshot for metrics. */
+ @NonNull
+ MetricsTimeZoneDetectorState generateMetricsState();
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index 2e96a10..5d34dd7 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -371,6 +371,28 @@
}
}
+ @Override
+ @NonNull
+ public synchronized MetricsTimeZoneDetectorState generateMetricsState() {
+ int currentUserId = mEnvironment.getCurrentUserId();
+ // Just capture one telephony suggestion: the one that would be used right now if telephony
+ // detection is in use.
+ QualifiedTelephonyTimeZoneSuggestion bestQualifiedTelephonySuggestion =
+ findBestTelephonySuggestion();
+ TelephonyTimeZoneSuggestion telephonySuggestion =
+ bestQualifiedTelephonySuggestion == null
+ ? null : bestQualifiedTelephonySuggestion.suggestion;
+ // A new generator is created each time: we don't want / require consistency.
+ OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>();
+ return MetricsTimeZoneDetectorState.create(
+ tzIdOrdinalGenerator,
+ getConfigurationInternal(currentUserId),
+ mEnvironment.getDeviceTimeZone(),
+ getLatestManualSuggestion(),
+ telephonySuggestion,
+ getLatestGeolocationSuggestion());
+ }
+
private static int scoreTelephonySuggestion(@NonNull TelephonyTimeZoneSuggestion suggestion) {
int score;
if (suggestion.getZoneId() == null) {
diff --git a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
index 417a636..4fa920e 100644
--- a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java
@@ -42,10 +42,12 @@
@NonNull private final LocationTimeZoneProviderProxy mProxy;
BinderLocationTimeZoneProvider(
+ @NonNull ProviderMetricsLogger providerMetricsLogger,
@NonNull ThreadingDomain threadingDomain,
@NonNull String providerName,
@NonNull LocationTimeZoneProviderProxy proxy) {
- super(threadingDomain, providerName, new ZoneInfoDbTimeZoneIdValidator());
+ super(providerMetricsLogger, threadingDomain, providerName,
+ new ZoneInfoDbTimeZoneIdValidator());
mProxy = Objects.requireNonNull(proxy);
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
index 5883821..ca4a640 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java
@@ -45,6 +45,7 @@
import com.android.server.SystemService;
import com.android.server.timezonedetector.ServiceConfigAccessor;
import com.android.server.timezonedetector.TimeZoneDetectorInternal;
+import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -297,7 +298,9 @@
R.string.config_primaryLocationTimeZoneProviderPackageName
);
}
- return new BinderLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
+ ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(0);
+ return new BinderLocationTimeZoneProvider(
+ providerMetricsLogger, mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
}
@NonNull
@@ -317,7 +320,9 @@
R.string.config_secondaryLocationTimeZoneProviderPackageName
);
}
- return new BinderLocationTimeZoneProvider(mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
+ ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(1);
+ return new BinderLocationTimeZoneProvider(
+ providerMetricsLogger, mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
}
/** Used for bug triage and in tests to simulate provider events. */
diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
index b97c838..cc815dc6 100644
--- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java
@@ -98,6 +98,14 @@
}
/**
+ * Listener interface used to log provider events for metrics.
+ */
+ interface ProviderMetricsLogger {
+ /** Logs that a provider changed state. */
+ void onProviderStateChanged(@ProviderStateEnum int stateEnum);
+ }
+
+ /**
* Information about the provider's current state.
*/
static class ProviderState {
@@ -349,6 +357,7 @@
}
}
+ @NonNull private final ProviderMetricsLogger mProviderMetricsLogger;
@NonNull final ThreadingDomain mThreadingDomain;
@NonNull final Object mSharedLock;
@NonNull final String mProviderName;
@@ -380,10 +389,12 @@
@NonNull private TimeZoneIdValidator mTimeZoneIdValidator;
/** Creates the instance. */
- LocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain,
+ LocationTimeZoneProvider(@NonNull ProviderMetricsLogger providerMetricsLogger,
+ @NonNull ThreadingDomain threadingDomain,
@NonNull String providerName,
@NonNull TimeZoneIdValidator timeZoneIdValidator) {
mThreadingDomain = Objects.requireNonNull(threadingDomain);
+ mProviderMetricsLogger = Objects.requireNonNull(providerMetricsLogger);
mInitializationTimeoutQueue = threadingDomain.createSingleRunnableQueue();
mSharedLock = threadingDomain.getLockObject();
mProviderName = Objects.requireNonNull(providerName);
@@ -485,6 +496,7 @@
mCurrentState.set(newState);
onSetCurrentState(newState);
if (!Objects.equals(newState, oldState)) {
+ mProviderMetricsLogger.onProviderStateChanged(newState.stateEnum);
if (mStateChangeRecording) {
mRecordedStates.add(newState);
}
diff --git a/services/core/java/com/android/server/timezonedetector/location/RealProviderMetricsLogger.java b/services/core/java/com/android/server/timezonedetector/location/RealProviderMetricsLogger.java
new file mode 100644
index 0000000..dfff6f2
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/location/RealProviderMetricsLogger.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector.location;
+
+import android.annotation.IntRange;
+
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger;
+import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
+
+/**
+ * The real implementation of {@link ProviderMetricsLogger} which logs using
+ * {@link FrameworkStatsLog}.
+ */
+public class RealProviderMetricsLogger implements ProviderMetricsLogger {
+
+ @IntRange(from = 0, to = 1)
+ private final int mProviderIndex;
+
+ public RealProviderMetricsLogger(@IntRange(from = 0, to = 1) int providerIndex) {
+ mProviderIndex = providerIndex;
+ }
+
+ @Override
+ public void onProviderStateChanged(@ProviderStateEnum int stateEnum) {
+ // TODO(b/172934905): Implement once the atom has landed.
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index aeeabe2..db3d7ad 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -137,6 +137,7 @@
import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
+import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING;
import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START;
import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN;
@@ -2114,7 +2115,7 @@
}
}
if (abort) {
- surface.remove();
+ surface.remove(false /* prepareAnimation */);
}
} else {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
@@ -2128,7 +2129,8 @@
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated,
TaskSnapshot snapshot) {
- if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ if ((newTask || !processRunning || (taskSwitch && !activityCreated))
+ && !isActivityTypeHome()) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
if (isSnapshotCompatible(snapshot)) {
@@ -2179,7 +2181,6 @@
+ ActivityRecord.this + " state " + mTransferringSplashScreenState);
if (isTransferringSplashScreen()) {
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
- // TODO show default exit splash screen animation
removeStartingWindow();
}
}
@@ -2196,6 +2197,9 @@
}
private boolean transferSplashScreenIfNeeded() {
+ if (!mWmService.mStartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) {
+ return false;
+ }
if (!mHandleExitSplashScreen || mStartingSurface == null || mStartingWindow == null
|| mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH) {
return false;
@@ -2265,10 +2269,14 @@
}
// no matter what, remove the starting window.
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
- removeStartingWindow();
+ removeStartingWindowAnimation(false /* prepareAnimation */);
}
void removeStartingWindow() {
+ removeStartingWindowAnimation(true /* prepareAnimation */);
+ }
+
+ void removeStartingWindowAnimation(boolean prepareAnimation) {
if (transferSplashScreenIfNeeded()) {
return;
}
@@ -2313,7 +2321,7 @@
mWmService.mAnimationHandler.post(() -> {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface);
try {
- surface.remove();
+ surface.remove(prepareAnimation);
} catch (Exception e) {
Slog.w(TAG_WM, "Exception when removing starting window", e);
}
@@ -6190,7 +6198,7 @@
// Remove orphaned starting window.
if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
mStartingWindowState = STARTING_WINDOW_REMOVED;
- removeStartingWindow();
+ removeStartingWindowAnimation(false /* prepareAnimation */);
}
if (isState(INITIALIZING) && !shouldBeVisible(
true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) {
@@ -8255,6 +8263,7 @@
proto.write(PROC_ID, app.getPid());
}
proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
+ proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
}
@Override
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index 13295e8..128d452 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -22,12 +22,17 @@
import android.os.RemoteException;
import android.view.ICrossWindowBlurEnabledListener;
+import com.android.internal.annotations.GuardedBy;
+
final class BlurController {
private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
mBlurEnabledListeners = new RemoteCallbackList<>();
private final Object mLock = new Object();
+ @GuardedBy("mLock")
boolean mBlurEnabled;
+ @GuardedBy("mLock")
+ boolean mBlurForceDisabled;
BlurController() {
mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
@@ -46,19 +51,24 @@
mBlurEnabledListeners.unregister(listener);
}
- private void updateBlurEnabled() {
- // TODO: add other factors disabling blurs
- final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED;
+ void setForceCrossWindowBlurDisabled(boolean disable) {
synchronized (mLock) {
- if (mBlurEnabled == newEnabled) {
- return;
- }
- mBlurEnabled = newEnabled;
- notifyBlurEnabledChanged(newEnabled);
+ mBlurForceDisabled = disable;
+ updateBlurEnabledLocked();
}
+
}
- private void notifyBlurEnabledChanged(boolean enabled) {
+ private void updateBlurEnabledLocked() {
+ final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurForceDisabled;
+ if (mBlurEnabled == newEnabled) {
+ return;
+ }
+ mBlurEnabled = newEnabled;
+ notifyBlurEnabledChangedLocked(newEnabled);
+ }
+
+ private void notifyBlurEnabledChangedLocked(boolean enabled) {
int i = mBlurEnabledListeners.beginBroadcast();
while (i > 0) {
i--;
@@ -71,6 +81,4 @@
}
mBlurEnabledListeners.finishBroadcast();
}
-
-
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1d45c6e..426e631 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -131,7 +131,6 @@
import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
-import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
@@ -1811,11 +1810,6 @@
w.mReportOrientationChanged = true;
}, true /* traverseTopToBottom */);
- if (rotateSeamlessly) {
- mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT,
- this, SEAMLESS_ROTATION_TIMEOUT_DURATION);
- }
-
for (int i = mWmService.mRotationWatchers.size() - 1; i >= 0; i--) {
final WindowManagerService.RotationWatcher rotationWatcher
= mWmService.mRotationWatchers.get(i);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 32152ec..01f0359 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1410,9 +1410,9 @@
boolean localClient) {
final InsetsState state =
mDisplayContent.getInsetsPolicy().getInsetsForWindowMetrics(attrs);
- final boolean inSizeCompatMode = WindowState.inSizeCompatMode(attrs, windowToken);
- outInsetsState.set(state, inSizeCompatMode || localClient);
- if (inSizeCompatMode) {
+ final boolean hasCompatScale = WindowState.hasCompatScale(attrs, windowToken);
+ outInsetsState.set(state, hasCompatScale || localClient);
+ if (hasCompatScale) {
final float compatScale = windowToken != null
? windowToken.getSizeCompatScale()
: mDisplayContent.mCompatibleScreenScale;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 63cb38a..5df1355 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -567,7 +567,7 @@
}
mDisplayContent.forAllWindows(w -> {
if (w.mSeamlesslyRotated) {
- w.finishSeamlessRotation(false /* timeout */);
+ w.cancelSeamlessRotation();
w.mSeamlesslyRotated = false;
}
}, true /* traverseTopToBottom */);
@@ -670,24 +670,6 @@
}
}
- void onSeamlessRotationTimeout() {
- final boolean[] isLayoutNeeded = { false };
-
- mDisplayContent.forAllWindows(w -> {
- if (!w.mSeamlesslyRotated) {
- return;
- }
- isLayoutNeeded[0] = true;
- w.setDisplayLayoutNeeded();
- w.finishSeamlessRotation(true /* timeout */);
- markForSeamlessRotation(w, false /* seamlesslyRotated */);
- }, true /* traverseTopToBottom */);
-
- if (isLayoutNeeded[0]) {
- mService.mWindowPlacerLocked.performSurfacePlacement();
- }
- }
-
/**
* Returns the animation to run for a rotation transition based on the top fullscreen windows
* {@link android.view.WindowManager.LayoutParams#rotationAnimation} and whether it is currently
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 627af91..1120a07 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -182,8 +182,6 @@
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
}
-
- mDragState.notifyLocationLocked(touchX, touchY);
} finally {
if (surface != null) {
surface.release();
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 0b3c065..08d5e80 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -515,50 +515,6 @@
mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply();
ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: pos=(%d,%d)", mSurfaceControl,
(int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY));
-
- notifyLocationLocked(x, y);
- }
-
- void notifyLocationLocked(float x, float y) {
- // Tell the affected window
- WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
- if (touchedWin != null && !isWindowNotified(touchedWin)) {
- // The drag point is over a window which was not notified about a drag start.
- // Pretend it's over empty space.
- touchedWin = null;
- }
-
- try {
- final int myPid = Process.myPid();
-
- // have we dragged over a new window?
- if ((touchedWin != mTargetWindow) && (mTargetWindow != null)) {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "sending DRAG_EXITED to " + mTargetWindow);
- }
- // force DRAG_EXITED_EVENT if appropriate
- DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
- 0, 0, 0, 0, null, null, null, null, null, false);
- mTargetWindow.mClient.dispatchDragEvent(evt);
- if (myPid != mTargetWindow.mSession.mPid) {
- evt.recycle();
- }
- }
- if (touchedWin != null) {
- if (false && DEBUG_DRAG) {
- Slog.d(TAG_WM, "sending DRAG_LOCATION to " + touchedWin);
- }
- DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
- x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, null, null, false);
- touchedWin.mClient.dispatchDragEvent(evt);
- if (myPid != touchedWin.mSession.mPid) {
- evt.recycle();
- }
- }
- } catch (RemoteException e) {
- Slog.w(TAG_WM, "can't send drag notification to windows");
- }
- mTargetWindow = touchedWin;
}
/**
diff --git a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
index a1e3ac7..aa73170 100644
--- a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java
@@ -37,10 +37,15 @@
super(displayContent);
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
mStatusBar = displayPolicy.getStatusBar();
- // Do not animate movable navigation bar (e.g. non-gesture mode).
+
+ final RecentsAnimationController controller =
+ displayContent.mWmService.getRecentsAnimationController();
+ final boolean navBarControlledByRecents =
+ controller != null && controller.isNavigationBarAttachedToApp();
+ // Do not animate movable navigation bar (e.g. non-gesture mode) or when the navigation bar
+ // is currently controlled by recents animation.
mNavigationBar = !displayPolicy.navigationBarCanMove()
- ? displayPolicy.getNavigationBar()
- : null;
+ && !navBarControlledByRecents ? displayPolicy.getNavigationBar() : null;
}
/** Applies show animation on the previously hidden window tokens. */
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index c6c7fe0..35e5491 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -30,7 +30,6 @@
import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET;
import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL;
import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET;
-import static com.android.server.wm.InsetsSourceProviderProto.FINISH_SEAMLESS_ROTATE_FRAME_NUMBER;
import static com.android.server.wm.InsetsSourceProviderProto.FRAME;
import static com.android.server.wm.InsetsSourceProviderProto.IME_OVERRIDDEN_FRAME;
import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING;
@@ -59,6 +58,7 @@
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* Controller for a specific inset source on the server. It's called provider as it provides the
@@ -84,6 +84,16 @@
private final Rect mImeOverrideFrame = new Rect();
private boolean mIsLeashReadyForDispatching;
+ private final Consumer<Transaction> mSetLeashPositionConsumer = t -> {
+ if (mControl != null) {
+ final SurfaceControl leash = mControl.getLeash();
+ if (leash != null) {
+ final Point position = mControl.getSurfacePosition();
+ t.setPosition(leash, position.x, position.y);
+ }
+ }
+ };
+
/** The visibility override from the current controlling window. */
private boolean mClientVisible;
@@ -93,7 +103,6 @@
private boolean mServerVisible;
private boolean mSeamlessRotating;
- private long mFinishSeamlessRotateFrameNumber = -1;
private final boolean mControllable;
@@ -150,7 +159,6 @@
// TODO: Ideally, we should wait for the animation to finish so previous window can
// animate-out as new one animates-in.
mWin.cancelAnimation();
- mWin.mPendingPositionChanged = null;
mWin.mProvidedInsetsSources.remove(mSource.getType());
}
ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
@@ -249,31 +257,16 @@
if (mControl != null) {
final Point position = getWindowFrameSurfacePosition();
if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) {
- if (!mWin.getWindowFrames().didFrameSizeChange()) {
- updateLeashPosition(-1 /* frameNumber */);
- } else if (mWin.mInRelayout) {
- updateLeashPosition(mWin.getFrameNumber());
+ if (mWin.getWindowFrames().didFrameSizeChange()) {
+ mWin.applyWithNextDraw(mSetLeashPositionConsumer);
} else {
- mWin.mPendingPositionChanged = this;
+ mSetLeashPositionConsumer.accept(mWin.getPendingTransaction());
}
mStateController.notifyControlChanged(mControlTarget);
}
}
}
- void updateLeashPosition(long frameNumber) {
- if (mControl == null) {
- return;
- }
- final SurfaceControl leash = mControl.getLeash();
- if (leash != null) {
- final Transaction t = mDisplayContent.getPendingTransaction();
- final Point position = mControl.getSurfacePosition();
- t.setPosition(leash, position.x, position.y);
- deferTransactionUntil(t, leash, frameNumber);
- }
- }
-
private Point getWindowFrameSurfacePosition() {
final Rect frame = mWin.getFrame();
final Point position = new Point();
@@ -281,14 +274,6 @@
return position;
}
- private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) {
- if (frameNumber >= 0) {
- final SurfaceControl barrier = mWin.getClientViewRootSurface();
- t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
- t.deferTransactionUntil(leash, barrier, frameNumber);
- }
- }
-
/**
* @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
*/
@@ -342,15 +327,6 @@
mIsLeashReadyForDispatching = false;
final SurfaceControl leash = mAdapter.mCapturedLeash;
- final long frameNumber = mFinishSeamlessRotateFrameNumber;
- mFinishSeamlessRotateFrameNumber = -1;
- if (mWin.mHasSurface && leash != null) {
- // We just finished the seamless rotation. We don't want to change the position or the
- // window crop of the surface controls (including the leash) until the client finishes
- // drawing the new frame of the new orientation. Although we cannot defer the reparent
- // operation, it is fine, because reparent won't cause any visual effect.
- deferTransactionUntil(t, leash, frameNumber);
- }
mControlTarget = target;
updateVisibility();
mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition);
@@ -359,19 +335,14 @@
}
void startSeamlessRotation() {
- if (!mSeamlessRotating) {
- mSeamlessRotating = true;
-
- // This will revoke the leash and clear the control target.
- mWin.cancelAnimation();
- }
+ if (!mSeamlessRotating) {
+ mSeamlessRotating = true;
+ mWin.cancelAnimation();
+ }
}
- void finishSeamlessRotation(boolean timeout) {
- if (mSeamlessRotating) {
- mSeamlessRotating = false;
- mFinishSeamlessRotateFrameNumber = timeout ? -1 : mWin.getFrameNumber();
- }
+ void finishSeamlessRotation() {
+ mSeamlessRotating = false;
}
boolean updateClientVisibility(InsetsControlTarget caller) {
@@ -529,7 +500,6 @@
proto.write(CLIENT_VISIBLE, mClientVisible);
proto.write(SERVER_VISIBLE, mServerVisible);
proto.write(SEAMLESS_ROTATING, mSeamlessRotating);
- proto.write(FINISH_SEAMLESS_ROTATE_FRAME_NUMBER, mFinishSeamlessRotateFrameNumber);
proto.write(CONTROLLABLE, mControllable);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e02cce4..914e456 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -17,7 +17,9 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -104,7 +106,8 @@
public @interface ReorderMode {}
private final WindowManagerService mService;
- private final StatusBarManagerInternal mStatusBar;
+ @VisibleForTesting
+ final StatusBarManagerInternal mStatusBar;
private IRecentsAnimationRunner mRunner;
private final RecentsAnimationCallbacks mCallbacks;
private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
@@ -149,6 +152,7 @@
@VisibleForTesting
boolean mShouldAttachNavBarToAppDuringTransition;
+ private boolean mNavigationBarAttachedToApp;
/**
* Animates the screenshot of task that used to be controlled by RecentsAnimation.
@@ -369,7 +373,17 @@
}
@Override
- public void detachNavigationBarFromApp() {}
+ public void detachNavigationBarFromApp(boolean moveHomeToTop) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService.getWindowManagerLock()) {
+ restoreNavigationBarFromApp(moveHomeToTop);
+ mService.mWindowPlacerLocked.requestTraversal();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
};
/**
@@ -440,9 +454,7 @@
return;
}
- if (mShouldAttachNavBarToAppDuringTransition) {
- attachNavBarToApp();
- }
+ attachNavigationBarToApp();
// Adjust the wallpaper visibility for the showing target activity
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
@@ -577,32 +589,52 @@
}
}
- @VisibleForTesting
- WindowToken getNavigationBarWindowToken() {
- WindowState navBar = mDisplayContent.getDisplayPolicy().getNavigationBar();
- if (navBar != null) {
- return navBar.mToken;
- }
- return null;
+ boolean isNavigationBarAttachedToApp() {
+ return mNavigationBarAttachedToApp;
}
- private void attachNavBarToApp() {
+ @VisibleForTesting
+ WindowState getNavigationBarWindow() {
+ return mDisplayContent.getDisplayPolicy().getNavigationBar();
+ }
+
+ private void attachNavigationBarToApp() {
+ if (!mShouldAttachNavBarToAppDuringTransition
+ // Skip the case where the nav bar is controlled by fixed rotation.
+ || mDisplayContent.getFixedRotationAnimationController() != null) {
+ return;
+ }
ActivityRecord topActivity = null;
+ boolean shouldTranslateNavBar = false;
+ final boolean isDisplayLandscape =
+ mDisplayContent.getConfiguration().orientation == ORIENTATION_LANDSCAPE;
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
final Task task = adapter.mTask;
- if (!task.isHomeOrRecentsRootTask()) {
- topActivity = task.getTopVisibleActivity();
- break;
+ final boolean isSplitScreenSecondary =
+ task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ if (task.isHomeOrRecentsRootTask()
+ // TODO(b/178449492): Will need to update for the new split screen mode once
+ // it's ready.
+ // Skip if the task is the secondary split screen and in landscape.
+ || (isSplitScreenSecondary && isDisplayLandscape)) {
+ continue;
}
- }
- final WindowToken navToken = getNavigationBarWindowToken();
- if (topActivity == null || navToken == null) {
- return;
+ shouldTranslateNavBar = isSplitScreenSecondary;
+ topActivity = task.getTopVisibleActivity();
+ break;
}
- final SurfaceControl.Transaction t = navToken.getPendingTransaction();
- final SurfaceControl navSurfaceControl = navToken.getSurfaceControl();
+ final WindowState navWindow = getNavigationBarWindow();
+ if (topActivity == null || navWindow == null || navWindow.mToken == null) {
+ return;
+ }
+ mNavigationBarAttachedToApp = true;
+ final SurfaceControl.Transaction t = navWindow.mToken.getPendingTransaction();
+ final SurfaceControl navSurfaceControl = navWindow.mToken.getSurfaceControl();
+ if (shouldTranslateNavBar) {
+ navWindow.setSurfaceTranslationY(-topActivity.getBounds().top);
+ }
t.reparent(navSurfaceControl, topActivity.getSurfaceControl());
t.show(navSurfaceControl);
@@ -613,16 +645,32 @@
// Place the nav bar on top of anything else in the top activity.
t.setLayer(navSurfaceControl, Integer.MAX_VALUE);
}
+ if (mStatusBar != null) {
+ mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, false);
+ }
}
- private void restoreNavBarFromApp(boolean animate) {
- // Reparent the SurfaceControl of nav bar token back.
- final WindowToken navToken = getNavigationBarWindowToken();
- final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
- if (navToken != null) {
- final WindowContainer parent = navToken.getParent();
- t.reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+ private void restoreNavigationBarFromApp(boolean animate) {
+ if (!mNavigationBarAttachedToApp) {
+ return;
}
+ if (mStatusBar != null) {
+ mStatusBar.setNavigationBarLumaSamplingEnabled(mDisplayId, true);
+ }
+
+ final WindowState navWindow = getNavigationBarWindow();
+ if (navWindow == null) {
+ return;
+ }
+ navWindow.setSurfaceTranslationY(0);
+
+ if (navWindow.mToken == null) {
+ return;
+ }
+ final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
+ final WindowContainer parent = navWindow.mToken.getParent();
+ // Reparent the SurfaceControl of nav bar token back.
+ t.reparent(navWindow.mToken.getSurfaceControl(), parent.getSurfaceControl());
if (animate) {
// Run fade-in animation to show navigation bar back to bottom of the display.
@@ -852,9 +900,7 @@
removeWallpaperAnimation(wallpaperAdapter);
}
- if (mShouldAttachNavBarToAppDuringTransition) {
- restoreNavBarFromApp(reorderMode == REORDER_MOVE_TO_TOP);
- }
+ restoreNavigationBarFromApp(reorderMode == REORDER_MOVE_TO_TOP);
// Clear any pending failsafe runnables
mService.mH.removeCallbacks(mFailsafeRunnable);
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index 3d305e4..1e8b8a5 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -35,9 +35,6 @@
* Helper class for seamless rotation.
*
* Works by transforming the {@link WindowState} back into the old display rotation.
- *
- * Uses {@link Transaction#deferTransactionUntil(SurfaceControl, IBinder, long)} instead of
- * latching on the buffer size to allow for seamless 180 degree rotations.
*/
public class SeamlessRotator {
@@ -103,22 +100,7 @@
* Removing the transform and the result of the {@link WindowState} layout are both tied to the
* {@link WindowState} next frame, such that they apply at the same time the client draws the
* window in the new orientation.
- *
- * In the case of a rotation timeout, we want to remove the transform immediately and not defer
- * it.
*/
- public void finish(WindowState win, boolean timeout) {
- final Transaction t = win.getPendingTransaction();
- finish(t, win);
- if (win.mWinAnimator.mSurfaceController != null && !timeout) {
- t.deferTransactionUntil(win.mSurfaceControl,
- win.getClientViewRootSurface(), win.getFrameNumber());
- t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
- win.getClientViewRootSurface(), win.getFrameNumber());
- }
- }
-
- /** Removes the transform and restore to the original last position. */
void finish(Transaction t, WindowContainer win) {
mTransform.reset();
t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index ef4a40f..6c46135 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -40,9 +40,8 @@
private static final String TAG = TAG_WITH_CLASS_NAME
? StartingSurfaceController.class.getSimpleName() : TAG_WM;
/** Set to {@code true} to enable shell starting surface drawer. */
- private static final boolean DEBUG_ENABLE_SHELL_DRAWER =
- SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
-
+ static final boolean DEBUG_ENABLE_SHELL_DRAWER =
+ SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
private final WindowManagerService mService;
public StartingSurfaceController(WindowManagerService wm) {
@@ -139,8 +138,9 @@
}
@Override
- public void remove() {
- mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask);
+ public void remove(boolean animate) {
+ mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask,
+ animate);
}
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 04a254c..a4b4726 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4135,6 +4135,8 @@
final StartingWindowInfo info = new StartingWindowInfo();
info.taskInfo = getTaskInfo();
+ info.isKeyguardOccluded =
+ mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY);
final ActivityRecord topActivity = getTopMostActivity();
if (topActivity != null) {
info.startingWindowTypeParameter =
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index fc6db61..5d22f8f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -32,6 +32,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ParceledListSlice;
+import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@@ -131,10 +132,28 @@
});
}
- void removeStartingWindow(Task task) {
+ void removeStartingWindow(Task task, boolean prepareAnimation) {
mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ SurfaceControl firstWindowLeash = null;
+ Rect mainFrame = null;
+ // TODO enable shift up animation once we fix flicker test
+// final boolean playShiftUpAnimation = !task.inMultiWindowMode();
+// if (prepareAnimation && playShiftUpAnimation) {
+// final ActivityRecord topActivity = task.topActivityWithStartingWindow();
+// if (topActivity != null) {
+// final WindowState mainWindow =
+// topActivity.findMainWindow(false/* includeStartingApp */);
+// if (mainWindow != null) {
+ // TODO create proper leash instead of the copied SC
+// firstWindowLeash = new SurfaceControl(mainWindow.getSurfaceControl(),
+// "TaskOrganizerController.removeStartingWindow");
+// mainFrame = mainWindow.getRelativeFrame();
+// }
+// }
+// }
try {
- mTaskOrganizer.removeStartingWindow(task.mTaskId);
+ mTaskOrganizer.removeStartingWindow(task.mTaskId, firstWindowLeash, mainFrame,
+ prepareAnimation);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
}
@@ -249,8 +268,8 @@
mOrganizer.addStartingWindow(t, appToken, launchTheme);
}
- void removeStartingWindow(Task t) {
- mOrganizer.removeStartingWindow(t);
+ void removeStartingWindow(Task t, boolean prepareAnimation) {
+ mOrganizer.removeStartingWindow(t, prepareAnimation);
}
void copySplashScreenView(Task t) {
@@ -495,14 +514,14 @@
return true;
}
- void removeStartingWindow(Task task) {
+ void removeStartingWindow(Task task, boolean prepareAnimation) {
final Task rootTask = task.getRootTask();
if (rootTask == null || rootTask.mTaskOrganizer == null) {
return;
}
final TaskOrganizerState state =
mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
- state.removeStartingWindow(task);
+ state.removeStartingWindow(task, prepareAnimation);
}
boolean copySplashScreenView(Task task) {
@@ -865,6 +884,7 @@
mPendingTaskEvents.remove(pending);
}
mPendingTaskEvents.add(pending);
+ mService.mWindowManager.mWindowPlacerLocked.requestTraversal();
return true;
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 9d35c25..525420e 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -188,7 +188,8 @@
transferFocusFromWin = displayContent.mCurrentFocus;
}
if (!mInputManager.transferTouchFocus(
- transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel)) {
+ transferFocusFromWin.mInputChannel, mTaskPositioner.mClientChannel,
+ false /* isDragDrop */)) {
Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
cleanUpTaskPositioner();
return false;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index b810de9..8915eba 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -37,6 +37,7 @@
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
+import android.view.Display;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
@@ -624,7 +625,7 @@
/**
* Called when screen is being turned off.
*/
- void screenTurningOff(ScreenOffListener listener) {
+ void screenTurningOff(int displayId, ScreenOffListener listener) {
if (shouldDisableSnapshots()) {
listener.onScreenOff();
return;
@@ -635,7 +636,7 @@
try {
synchronized (mService.mGlobalLock) {
mTmpTasks.clear();
- mService.mRoot.forAllTasks(task -> {
+ mService.mRoot.getDisplayContent(displayId).forAllTasks(task -> {
// Since RecentsAnimation will handle task snapshot while switching apps
// with the best capture timing (e.g. IME window capture), No need
// additional task capture while task is controlled by RecentsAnimation.
@@ -645,7 +646,7 @@
});
// Allow taking snapshot of home when turning screen off to reduce the delay of
// waking from secure lock to home.
- final boolean allowSnapshotHome =
+ final boolean allowSnapshotHome = displayId == Display.DEFAULT_DISPLAY &&
mService.mPolicy.isKeyguardSecure(mService.mCurrentUserId);
snapshotTasks(mTmpTasks, allowSnapshotHome);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 07610ab..79a6bd7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -281,13 +281,14 @@
}
@Override
- public void remove() {
+ public void remove(boolean animate) {
synchronized (mService.mGlobalLock) {
final long now = SystemClock.uptimeMillis();
if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
// Show the latest content as soon as possible for unlocking to home.
&& mActivityType != ACTIVITY_TYPE_HOME) {
- mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
+ mHandler.postAtTime(() -> remove(false /* prepareAnimation */),
+ mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Defer removing snapshot surface in %dms", (now - mShownTime));
@@ -517,7 +518,7 @@
// The orientation of the screen is changing. We better remove the snapshot ASAP as
// we are going to wait on the new window in any case to unfreeze the screen, and
// the starting window is not needed anymore.
- sHandler.post(mOuter::remove);
+ sHandler.post(() -> mOuter.remove(false /* prepareAnimation */));
}
if (reportDraw) {
sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9245f8c..ffd6d21 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -113,7 +113,7 @@
}
/**
- * @return true if the width or height has changed since last reported to the client.
+ * @return true if the width or height has changed since last updating resizing window.
*/
boolean didFrameSizeChange() {
return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
@@ -135,6 +135,13 @@
}
/**
+ * @return true if the width or height has changed since last reported to the client.
+ */
+ boolean isFrameSizeChangeReported() {
+ return mFrameSizeChanged || didFrameSizeChange();
+ }
+
+ /**
* Resets the size changed flags so they're all set to false again. This should be called
* after the frames are reported to client.
*/
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 7450782..53ebfb2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -221,7 +221,8 @@
DragState state, Display display, InputManagerService service,
InputChannel source) {
state.register(display);
- return service.transferTouchFocus(source, state.getInputChannel());
+ return service.transferTouchFocus(source, state.getInputChannel(),
+ true /* isDragDrop */);
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3ddb6fc..b95674e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -366,9 +366,6 @@
/** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
- /** Amount of time (in milliseconds) to delay before declaring a seamless rotation timeout. */
- static final int SEAMLESS_ROTATION_TIMEOUT_DURATION = 2000;
-
/** Amount of time (in milliseconds) to delay before declaring a window replacement timeout. */
static final int WINDOW_REPLACEMENT_TIMEOUT_DURATION = 2000;
@@ -2236,16 +2233,9 @@
win.setFrameNumber(frameNumber);
final DisplayContent dc = win.getDisplayContent();
- if (!dc.mWaitingForConfig) {
- win.finishSeamlessRotation(false /* timeout */);
- }
-
- if (win.mPendingPositionChanged != null) {
- win.mPendingPositionChanged.updateLeashPosition(frameNumber);
- win.mPendingPositionChanged = null;
- }
if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) {
+ win.prepareDrawHandlers();
result |= RELAYOUT_RES_BLAST_SYNC;
}
@@ -2990,8 +2980,8 @@
}
@Override
- public void screenTurningOff(ScreenOffListener listener) {
- mTaskSnapshotController.screenTurningOff(listener);
+ public void screenTurningOff(int displayId, ScreenOffListener listener) {
+ mTaskSnapshotController.screenTurningOff(displayId, listener);
}
@Override
@@ -5086,7 +5076,6 @@
public static final int UPDATE_ANIMATION_SCALE = 51;
public static final int WINDOW_HIDE_TIMEOUT = 52;
- public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
public static final int RESTORE_POINTER_ICON = 55;
public static final int SET_HAS_OVERLAY_UI = 58;
public static final int ANIMATION_FAILSAFE = 60;
@@ -5369,13 +5358,6 @@
}
break;
}
- case SEAMLESS_ROTATION_TIMEOUT: {
- final DisplayContent displayContent = (DisplayContent) msg.obj;
- synchronized (mGlobalLock) {
- displayContent.getDisplayRotation().onSeamlessRotationTimeout();
- }
- break;
- }
case SET_HAS_OVERLAY_UI: {
mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
break;
@@ -5693,6 +5675,11 @@
mBlurController.unregisterCrossWindowBlurEnabledListener(listener);
}
+ @Override
+ public void setForceCrossWindowBlurDisabled(boolean disable) {
+ mBlurController.setForceCrossWindowBlurDisabled(disable);
+ }
+
// -------------------------------------------------------------
// Internals
// -------------------------------------------------------------
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d9b879f..7ebc1cc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -168,8 +168,8 @@
import static com.android.server.wm.WindowStateProto.FORCE_SEAMLESS_ROTATION;
import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS;
import static com.android.server.wm.WindowStateProto.GLOBAL_SCALE;
+import static com.android.server.wm.WindowStateProto.HAS_COMPAT_SCALE;
import static com.android.server.wm.WindowStateProto.HAS_SURFACE;
-import static com.android.server.wm.WindowStateProto.IN_SIZE_COMPAT_MODE;
import static com.android.server.wm.WindowStateProto.IS_ON_SCREEN;
import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY;
import static com.android.server.wm.WindowStateProto.IS_VISIBLE;
@@ -261,6 +261,7 @@
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/** A window in the window manager. */
@@ -725,8 +726,6 @@
*/
private InsetsState mFrozenInsetsState;
- @Nullable InsetsSourceProvider mPendingPositionChanged;
-
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
private KeyInterceptionInfo mKeyInterceptionInfo;
@@ -749,6 +748,42 @@
private final WindowProcessController mWpcForDisplayAreaConfigChanges;
/**
+ * We split the draw handlers in to a "pending" and "ready" list, in order to solve
+ * sequencing problems. Think of it this way, let's say I update a windows orientation
+ * (in configuration), and then I call applyWithNextDraw. What I'm hoping for is to
+ * apply with the draw that contains the orientation change. However, since the client
+ * can call finishDrawing at any time, it could be about to call a previous call to
+ * finishDrawing (or maybe its already called it, we just haven't handled it). Since this
+ * frame was already completed it had no time to include the orientation change we made.
+ * To solve this problem we accumulate draw handlers in mPendingDrawHandlers, and then force
+ * the client to call relayout. Only the frame post relayout will contain the configuration
+ * change since the window has to relayout), and so in relayout we drain mPendingDrawHandlers
+ * into mReadyDrawHandlers. Finally once we get to finishDrawing we know everything in
+ * mReadyDrawHandlers corresponds to state which was observed by the client and we can
+ * invoke the consumers.
+ */
+ private final List<Consumer<SurfaceControl.Transaction>> mPendingDrawHandlers
+ = new ArrayList<>();
+ private final List<Consumer<SurfaceControl.Transaction>> mReadyDrawHandlers
+ = new ArrayList<>();
+
+ private final Consumer<SurfaceControl.Transaction> mSeamlessRotationFinishedConsumer = t -> {
+ finishSeamlessRotation(t);
+ updateSurfacePosition(t);
+ };
+
+ private final Consumer<SurfaceControl.Transaction> mSetSurfacePositionConsumer = t -> {
+ if (mSurfaceControl != null && mSurfaceControl.isValid()) {
+ t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ }
+ };
+
+ /**
+ * @see #setSurfaceTranslationY(int)
+ */
+ private int mSurfaceTranslationY;
+
+ /**
* Returns the visibility of the given {@link InternalInsetsType type} requested by the client.
*
* @param type the given {@link InternalInsetsType type}.
@@ -831,19 +866,27 @@
mPendingSeamlessRotate.unrotate(transaction, this);
getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
true /* seamlesslyRotated */);
+ applyWithNextDraw(mSeamlessRotationFinishedConsumer);
}
}
- void finishSeamlessRotation(boolean timeout) {
- if (mPendingSeamlessRotate != null) {
- mPendingSeamlessRotate.finish(this, timeout);
- mFinishSeamlessRotateFrameNumber = getFrameNumber();
- mPendingSeamlessRotate = null;
- getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
- false /* seamlesslyRotated */);
- if (mControllableInsetProvider != null) {
- mControllableInsetProvider.finishSeamlessRotation(timeout);
- }
+ void cancelSeamlessRotation() {
+ finishSeamlessRotation(getPendingTransaction());
+ }
+
+ void finishSeamlessRotation(SurfaceControl.Transaction t) {
+ if (mPendingSeamlessRotate == null) {
+ return;
+ }
+
+ mPendingSeamlessRotate.finish(t, this);
+ mFinishSeamlessRotateFrameNumber = getFrameNumber();
+ mPendingSeamlessRotate = null;
+
+ getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
+ false /* seamlesslyRotated */);
+ if (mControllableInsetProvider != null) {
+ mControllableInsetProvider.finishSeamlessRotation();
}
}
@@ -1050,18 +1093,18 @@
* scaling override set.
* @see CompatModePackages#getCompatScale
* @see android.content.res.CompatibilityInfo#supportsScreen
- * @see ActivityRecord#inSizeCompatMode()
+ * @see ActivityRecord#hasSizeCompatBounds()
*/
- boolean inSizeCompatMode() {
- return mOverrideScale != 1f || inSizeCompatMode(mAttrs, mActivityRecord);
+ boolean hasCompatScale() {
+ return mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord);
}
/**
* @return {@code true} if the application runs in size compatibility mode.
* @see android.content.res.CompatibilityInfo#supportsScreen
- * @see ActivityRecord#inSizeCompatMode()
+ * @see ActivityRecord#hasSizeCompatBounds()
*/
- static boolean inSizeCompatMode(WindowManager.LayoutParams attrs, WindowToken windowToken) {
+ static boolean hasCompatScale(WindowManager.LayoutParams attrs, WindowToken windowToken) {
return (attrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0
|| (windowToken != null && windowToken.hasSizeCompatBounds()
// Exclude starting window because it is not displayed by the application.
@@ -1266,7 +1309,7 @@
windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
windowFrames.mCompatFrame.set(windowFrames.mFrame);
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
// Also the scaled frame that we report to the app needs to be
// adjusted to be in its coordinate space.
windowFrames.mCompatFrame.scale(mInvGlobalScale);
@@ -1538,7 +1581,7 @@
*/
InsetsState getCompatInsetsState() {
InsetsState state = getInsetsState();
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
state = new InsetsState(state, true);
state.scale(mInvGlobalScale);
}
@@ -1676,7 +1719,7 @@
}
void prelayout() {
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
if (mOverrideScale != 1f) {
mGlobalScale = mToken.hasSizeCompatBounds()
? mToken.getSizeCompatScale() * mOverrideScale
@@ -2090,6 +2133,8 @@
: getTask().getWindowConfiguration().hasMovementAnimations();
if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
+ && !mWindowFrames.didFrameSizeChange()
+ && !surfaceInsetsChanging()
&& !isDragResizing()
&& hasMovementAnimation
&& !mWinAnimator.mLastHidden
@@ -3590,7 +3635,7 @@
void fillClientWindowFrames(ClientWindowFrames outFrames) {
outFrames.frame.set(mWindowFrames.mCompatFrame);
outFrames.displayFrame.set(mWindowFrames.mDisplayFrame);
- if (mInvGlobalScale != 1.0f && inSizeCompatMode()) {
+ if (mInvGlobalScale != 1.0f && hasCompatScale()) {
outFrames.displayFrame.scale(mInvGlobalScale);
}
@@ -3990,7 +4035,7 @@
proto.write(PENDING_SEAMLESS_ROTATION, mPendingSeamlessRotate != null);
proto.write(FINISHED_SEAMLESS_ROTATION_FRAME, mFinishSeamlessRotateFrameNumber);
proto.write(FORCE_SEAMLESS_ROTATION, mForceSeamlesslyRotate);
- proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
+ proto.write(HAS_COMPAT_SCALE, hasCompatScale());
proto.write(GLOBAL_SCALE, mGlobalScale);
proto.end(token);
}
@@ -4092,7 +4137,7 @@
pw.println(prefix + "mHasSurface=" + mHasSurface
+ " isReadyForDisplay()=" + isReadyForDisplay()
+ " mWindowRemovalAllowed=" + mWindowRemovalAllowed);
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB));
}
if (dumpAll) {
@@ -4215,18 +4260,18 @@
float x, y;
int w,h;
- final boolean inSizeCompatMode = inSizeCompatMode();
+ final boolean hasCompatScale = hasCompatScale();
if ((mAttrs.flags & FLAG_SCALED) != 0) {
if (mAttrs.width < 0) {
w = pw;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
w = (int)(mAttrs.width * mGlobalScale + .5f);
} else {
w = mAttrs.width;
}
if (mAttrs.height < 0) {
h = ph;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
h = (int)(mAttrs.height * mGlobalScale + .5f);
} else {
h = mAttrs.height;
@@ -4234,21 +4279,21 @@
} else {
if (mAttrs.width == MATCH_PARENT) {
w = pw;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
w = (int)(mRequestedWidth * mGlobalScale + .5f);
} else {
w = mRequestedWidth;
}
if (mAttrs.height == MATCH_PARENT) {
h = ph;
- } else if (inSizeCompatMode) {
+ } else if (hasCompatScale) {
h = (int)(mRequestedHeight * mGlobalScale + .5f);
} else {
h = mRequestedHeight;
}
}
- if (inSizeCompatMode) {
+ if (hasCompatScale) {
x = mAttrs.x * mGlobalScale;
y = mAttrs.y * mGlobalScale;
} else {
@@ -4276,7 +4321,7 @@
// We need to make sure we update the CompatFrame as it is used for
// cropping decisions, etc, on systems where we lack a decor layer.
windowFrames.mCompatFrame.set(windowFrames.mFrame);
- if (inSizeCompatMode) {
+ if (hasCompatScale) {
// See comparable block in computeFrameLw.
windowFrames.mCompatFrame.scale(mInvGlobalScale);
}
@@ -4394,7 +4439,7 @@
float translateToWindowX(float x) {
float winX = x - mWindowFrames.mFrame.left;
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
winX *= mGlobalScale;
}
return winX;
@@ -4402,7 +4447,7 @@
float translateToWindowY(float y) {
float winY = y - mWindowFrames.mFrame.top;
- if (inSizeCompatMode()) {
+ if (hasCompatScale()) {
winY *= mGlobalScale;
}
return winY;
@@ -5279,13 +5324,17 @@
// prior to the rotation.
if (!mSurfaceAnimator.hasLeash() && mPendingSeamlessRotate == null
&& !mLastSurfacePosition.equals(mSurfacePosition)) {
- t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y);
+ final boolean frameSizeChanged = mWindowFrames.isFrameSizeChangeReported();
+ final boolean surfaceInsetsChanged = surfaceInsetsChanging();
+ final boolean surfaceSizeChanged = frameSizeChanged || surfaceInsetsChanged;
mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
- if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) {
+ if (surfaceInsetsChanged) {
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
- t.deferTransactionUntil(mSurfaceControl,
- mWinAnimator.mSurfaceController.mSurfaceControl,
- getFrameNumber());
+ }
+ if (surfaceSizeChanged) {
+ applyWithNextDraw(mSetSurfacePositionConsumer);
+ } else {
+ mSetSurfacePositionConsumer.accept(t);
}
}
}
@@ -5324,6 +5373,8 @@
// Expand for surface insets. See WindowState.expandForSurfaceInsets.
transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
outPoint.offset(-mTmpPoint.x, -mTmpPoint.y);
+
+ outPoint.y += mSurfaceTranslationY;
}
/**
@@ -5331,7 +5382,7 @@
* scaled, the insets also need to be scaled for surface position in global coordinate.
*/
private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) {
- if (!inSizeCompatMode()) {
+ if (!hasCompatScale()) {
outPos.x = surfaceInsets.left;
outPos.y = surfaceInsets.top;
return;
@@ -5684,6 +5735,8 @@
Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms");
mActivityRecord.mRelaunchStartTime = 0;
}
+
+ executeDrawHandlers(postDrawTransaction);
if (!onSyncFinishedDrawing()) {
return mWinAnimator.finishDrawingLocked(postDrawTransaction);
}
@@ -5698,6 +5751,7 @@
}
void immediatelyNotifyBlastSync() {
+ prepareDrawHandlers();
finishDrawing(null);
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (!useBLASTSync()) return;
@@ -5777,4 +5831,75 @@
outSize.inset(-attrs.surfaceInsets.left, -attrs.surfaceInsets.top,
-attrs.surfaceInsets.right, -attrs.surfaceInsets.bottom);
}
+
+ /**
+ * This method is used to control whether we return the BLAST_SYNC flag
+ * from relayoutWindow calls on this window (triggering the client to redirect
+ * it's next draw in to a transaction). If we have pending draw handlers, we are
+ * looking for the client to sync.
+ *
+ * See {@link WindowState#mPendingDrawHandlers}
+ */
+ @Override
+ boolean useBLASTSync() {
+ return super.useBLASTSync() || (mPendingDrawHandlers.size() != 0);
+ }
+
+ /**
+ * Apply the transaction with the next window redraw. A full relayout/finishDrawing
+ * cycle must occur before completion. This means if you call the function while
+ * "in relayout", the results may be undefined but at all other times the function
+ * should sort of transparently work like this:
+ * 1. Make changes to WM hierarchy (say change app configuration)
+ * 2. Call apply with next draw.
+ * 3. After finishDrawing, our consumer will be passed the Transaction
+ * containing the buffer, and we can merge in additional operations.
+ * See {@link WindowState#mPendingDrawHandlers}
+ */
+ void applyWithNextDraw(Consumer<SurfaceControl.Transaction> consumer) {
+ mPendingDrawHandlers.add(consumer);
+ requestRedrawForSync();
+
+ mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,
+ BLAST_TIMEOUT_DURATION);
+ }
+
+ /**
+ * Called from relayout, to indicate the next "finishDrawing" will contain
+ * all changes applied by the time mPendingDrawHandlers was populated.
+ *
+ * See {@link WindowState#mPendingDrawHandlers}
+ */
+ void prepareDrawHandlers() {
+ mReadyDrawHandlers.addAll(mPendingDrawHandlers);
+ mPendingDrawHandlers.clear();
+ }
+
+ /**
+ * Drain the draw handlers, called from finishDrawing()
+ * See {@link WindowState#mPendingDrawHandlers}
+ */
+ boolean executeDrawHandlers(SurfaceControl.Transaction t) {
+ if (t == null) t = mTmpTransaction;
+ boolean hadHandlers = false;
+ for (int i = 0; i < mReadyDrawHandlers.size(); i++) {
+ mReadyDrawHandlers.get(i).accept(t);
+ hadHandlers = true;
+ }
+ mReadyDrawHandlers.clear();
+ mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
+
+ t.apply();
+
+ return hadHandlers;
+ }
+
+ /**
+ * Adds an additional translation offset to be applied when positioning the surface. Used to
+ * correct offsets in specific reparenting situations, e.g. the navigation bar window attached
+ * on the lower split-screen app.
+ */
+ void setSurfaceTranslationY(int translationY) {
+ mSurfaceTranslationY = translationY;
+ }
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 10705af..be06d03 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1783,8 +1783,9 @@
im->setSystemUiLightsOut(lightsOut);
}
-static jboolean nativeTransferTouchFocus(JNIEnv* env,
- jclass /* clazz */, jlong ptr, jobject fromChannelTokenObj, jobject toChannelTokenObj) {
+static jboolean nativeTransferTouchFocus(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jobject fromChannelTokenObj, jobject toChannelTokenObj,
+ jboolean isDragDrop) {
if (fromChannelTokenObj == nullptr || toChannelTokenObj == nullptr) {
return JNI_FALSE;
}
@@ -1793,8 +1794,8 @@
sp<IBinder> toChannelToken = ibinderForJavaObject(env, toChannelTokenObj);
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- if (im->getInputManager()->getDispatcher()->transferTouchFocus(
- fromChannelToken, toChannelToken)) {
+ if (im->getInputManager()->getDispatcher()->transferTouchFocus(fromChannelToken, toChannelToken,
+ isDragDrop)) {
return JNI_TRUE;
} else {
return JNI_FALSE;
@@ -2267,7 +2268,7 @@
(void*)nativeRequestPointerCapture},
{"nativeSetInputDispatchMode", "(JZZ)V", (void*)nativeSetInputDispatchMode},
{"nativeSetSystemUiLightsOut", "(JZ)V", (void*)nativeSetSystemUiLightsOut},
- {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z",
+ {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;Z)Z",
(void*)nativeTransferTouchFocus},
{"nativeSetPointerSpeed", "(JI)V", (void*)nativeSetPointerSpeed},
{"nativeSetShowTouches", "(JZ)V", (void*)nativeSetShowTouches},
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 6a8f6d4..d43cf3f 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -45,13 +45,6 @@
}
xsd_config {
- name: "cec-config",
- srcs: ["cec-config/cec-config.xsd"],
- api_dir: "cec-config/schema",
- package_name: "com.android.server.hdmi.cec.config",
-}
-
-xsd_config {
name: "device-state-config",
srcs: ["device-state-config/device-state-config.xsd"],
api_dir: "device-state-config/schema",
diff --git a/services/core/xsd/cec-config/cec-config.xsd b/services/core/xsd/cec-config/cec-config.xsd
deleted file mode 100644
index b59c93c..0000000
--- a/services/core/xsd/cec-config/cec-config.xsd
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema version="2.0"
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:element name="cec-settings">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="setting" type="setting" minOccurs="0" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:complexType name="setting">
- <xs:attribute name="name" type="xs:string"/>
- <xs:attribute name="value-type" type="xs:string"/>
- <xs:attribute name="user-configurable" type="xs:boolean"/>
- <xs:element name="allowed-values" type="value-list" minOccurs="1" maxOccurs="1"/>
- <xs:element name="default-value" type="value" minOccurs="1" maxOccurs="1"/>
- </xs:complexType>
- <xs:complexType name="value-list">
- <xs:sequence>
- <xs:element name="value" type="value" minOccurs="1" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- <xs:complexType name="value">
- <xs:attribute name="string-value" type="xs:string"/>
- <xs:attribute name="int-value" type="xs:string"/>
- </xs:complexType>
-</xs:schema>
diff --git a/services/core/xsd/cec-config/schema/current.txt b/services/core/xsd/cec-config/schema/current.txt
deleted file mode 100644
index 75872d4..0000000
--- a/services/core/xsd/cec-config/schema/current.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-// Signature format: 2.0
-package com.android.server.hdmi.cec.config {
-
- public class CecSettings {
- ctor public CecSettings();
- method public java.util.List<com.android.server.hdmi.cec.config.Setting> getSetting();
- }
-
- public class Setting {
- ctor public Setting();
- method public com.android.server.hdmi.cec.config.ValueList getAllowedValues();
- method public com.android.server.hdmi.cec.config.Value getDefaultValue();
- method public String getName();
- method public boolean getUserConfigurable();
- method public String getValueType();
- method public void setAllowedValues(com.android.server.hdmi.cec.config.ValueList);
- method public void setDefaultValue(com.android.server.hdmi.cec.config.Value);
- method public void setName(String);
- method public void setUserConfigurable(boolean);
- method public void setValueType(String);
- }
-
- public class Value {
- ctor public Value();
- method public String getIntValue();
- method public String getStringValue();
- method public void setIntValue(String);
- method public void setStringValue(String);
- }
-
- public class ValueList {
- ctor public ValueList();
- method public java.util.List<com.android.server.hdmi.cec.config.Value> getValue();
- }
-
- public class XmlParser {
- ctor public XmlParser();
- method public static com.android.server.hdmi.cec.config.CecSettings read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- }
-
-}
-
diff --git a/services/core/xsd/cec-config/schema/last_current.txt b/services/core/xsd/cec-config/schema/last_current.txt
deleted file mode 100644
index e69de29..0000000
--- a/services/core/xsd/cec-config/schema/last_current.txt
+++ /dev/null
diff --git a/services/core/xsd/cec-config/schema/last_removed.txt b/services/core/xsd/cec-config/schema/last_removed.txt
deleted file mode 100644
index e69de29..0000000
--- a/services/core/xsd/cec-config/schema/last_removed.txt
+++ /dev/null
diff --git a/services/core/xsd/cec-config/schema/removed.txt b/services/core/xsd/cec-config/schema/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/core/xsd/cec-config/schema/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1590ef1..2855c70 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1588,7 +1588,7 @@
CryptoTestHelper.runAndLogSelfTest();
}
- public String[] getPersonalAppsForSuspension(int userId) {
+ public String[] getPersonalAppsForSuspension(@UserIdInt int userId) {
return PersonalAppsSuspensionHelper.forUser(mContext, userId)
.getPersonalAppsForSuspension();
}
@@ -2969,7 +2969,7 @@
private class DpmsUpgradeDataProvider implements PolicyUpgraderDataProvider {
@Override
- public boolean isUserDeviceOwner(int userId, ComponentName who) {
+ public boolean isDeviceOwner(int userId, ComponentName who) {
return mOwners.isDeviceOwnerUserId(userId)
&& mOwners.getDeviceOwnerComponent().equals(who);
}
@@ -2999,14 +2999,19 @@
return component -> findAdmin(component, userId, /* throwForMissingPermission= */
false);
}
+
+ @Override
+ public int[] getUsersForUpgrade() {
+ List<UserInfo> allUsers = mUserManager.getUsers();
+ return allUsers.stream().mapToInt(u -> u.id).toArray();
+ }
}
private void performPolicyVersionUpgrade() {
- List<UserInfo> allUsers = mUserManager.getUsers();
PolicyVersionUpgrader upgrader = new PolicyVersionUpgrader(
new DpmsUpgradeDataProvider());
- upgrader.upgradePolicy(allUsers.stream().mapToInt(u -> u.id).toArray(), DPMS_VERSION);
+ upgrader.upgradePolicy(DPMS_VERSION);
}
private void revertTransferOwnershipIfNecessaryLocked() {
@@ -10615,6 +10620,30 @@
}
@Override
+ public List<String> listPolicyExemptApps() {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+
+ // TODO(b/181238156): decide whether it should only list the apps set by the resources,
+ // or also the "critical" apps defined by PersonalAppsSuspensionHelper (like SMS app).
+ // If it's the latter, refactor PersonalAppsSuspensionHelper so it (or a superclass) takes
+ // the resources on constructor.
+ String[] core = mContext.getResources().getStringArray(R.array.policy_exempt_apps);
+ String[] vendor = mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps);
+
+ int size = core.length + vendor.length;
+ Set<String> apps = new ArraySet<>(size);
+ for (String app : core) {
+ apps.add(app);
+ }
+ for (String app : vendor) {
+ apps.add(app);
+ }
+
+ return new ArrayList<>(apps);
+ }
+
+ @Override
public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
boolean parent) {
Objects.requireNonNull(who, "ComponentName is null");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 5484a14..8e31029 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -21,6 +21,7 @@
import com.android.server.devicepolicy.Owners.OwnerDto;
import java.io.PrintWriter;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
@@ -30,6 +31,7 @@
private static final String CMD_IS_SAFE_OPERATION_BY_REASON = "is-operation-safe-by-reason";
private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
private static final String CMD_LIST_OWNERS = "list-owners";
+ private static final String CMD_LIST_POLICY_EXEMPT_APPS = "list-policy-exempt-apps";
private final DevicePolicyManagerService mService;
@@ -60,6 +62,8 @@
return runSetSafeOperation(pw);
case CMD_LIST_OWNERS:
return runListOwners(pw);
+ case CMD_LIST_POLICY_EXEMPT_APPS:
+ return runListPolicyExemptApps(pw);
default:
return onInvalidCommand(pw, cmd);
}
@@ -88,6 +92,8 @@
+ " \n\n");
pw.printf(" %s\n", CMD_LIST_OWNERS);
pw.printf(" Lists the device / profile owners per user \n\n");
+ pw.printf(" %s\n", CMD_LIST_POLICY_EXEMPT_APPS);
+ pw.printf(" Lists the apps that are exempt from policies\n\n");
}
private int runIsSafeOperation(PrintWriter pw) {
@@ -119,18 +125,20 @@
return 0;
}
- private int runListOwners(PrintWriter pw) {
- List<OwnerDto> owners = mService.listAllOwners();
- if (owners.isEmpty()) {
- pw.println("none");
+ private int printAndGetSize(PrintWriter pw, Collection<?> collection, String nameOnSingular) {
+ if (collection.isEmpty()) {
+ pw.printf("no %ss\n", nameOnSingular);
return 0;
}
- int size = owners.size();
- if (size == 1) {
- pw.println("1 owner:");
- } else {
- pw.printf("%d owners:\n", size);
- }
+ int size = collection.size();
+ pw.printf("%d %s%s:\n", size, nameOnSingular, (size == 1 ? "" : "s"));
+ return size;
+ }
+
+ private int runListOwners(PrintWriter pw) {
+ List<OwnerDto> owners = mService.listAllOwners();
+ int size = printAndGetSize(pw, owners, "owner");
+ if (size == 0) return 0;
for (int i = 0; i < size; i++) {
OwnerDto owner = owners.get(i);
@@ -150,4 +158,17 @@
return 0;
}
+
+ private int runListPolicyExemptApps(PrintWriter pw) {
+ List<String> apps = mService.listPolicyExemptApps();
+ int size = printAndGetSize(pw, apps, "policy exempt app");
+
+ if (size == 0) return 0;
+
+ for (int i = 0; i < size; i++) {
+ String app = apps.get(i);
+ pw.printf(" %d: %s\n", i, app);
+ }
+ return 0;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
index c20d0f5..19a7659 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyUpgraderDataProvider.java
@@ -33,7 +33,7 @@
* Returns true if the provided {@code userId} is a device owner. May affect some policy
* defaults.
*/
- boolean isUserDeviceOwner(int userId, ComponentName who);
+ boolean isDeviceOwner(int userId, ComponentName who);
/**
* Returns true if the storage manager indicates file-based encryption is enabled.
@@ -60,4 +60,9 @@
* user.
*/
Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId);
+
+ /**
+ * Returns the users to upgrade.
+ */
+ int[] getUsersForUpgrade();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 2ab4b66..6bc7ba6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -62,7 +62,7 @@
* managed profile user IDs.
* @param dpmsVersion The version to upgrade to.
*/
- public void upgradePolicy(int[] allUsers, int dpmsVersion) {
+ public void upgradePolicy(int dpmsVersion) {
int oldVersion = readVersion();
if (oldVersion >= dpmsVersion) {
Slog.i(LOG_TAG, String.format("Current version %d, latest version %d, not upgrading.",
@@ -70,6 +70,8 @@
return;
}
+ final int[] allUsers = mProvider.getUsersForUpgrade();
+
//NOTE: The current version is provided in case the XML file format changes in a
// non-backwards-compatible way, so that DeviceAdminData could load it with
// old tags, for example.
@@ -94,7 +96,7 @@
continue;
}
for (ActiveAdmin admin : userData.mAdminList) {
- if (mProvider.isUserDeviceOwner(userId, admin.info.getComponent())) {
+ if (mProvider.isDeviceOwner(userId, admin.info.getComponent())) {
Slog.i(LOG_TAG, String.format(
"Marking Device Owner in user %d for permission grant ", userId));
admin.mAdminCanGrantSensorsPermissions = true;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 1fcc284..c38d0b3 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -74,6 +74,13 @@
// If DL was up and not crashing for 10mins, we consider it healthy and reset all delays.
static constexpr auto healthyDataLoaderUptime = 10min;
+
+ // For healthy DLs, we'll retry every ~5secs for ~10min
+ static constexpr auto bindRetryInterval = 5s;
+ static constexpr auto bindGracePeriod = 10min;
+
+ static constexpr auto bindingTimeout = 1min;
+
// 10s, 100s (~2min), 1000s (~15min), 10000s (~3hrs)
static constexpr auto minBindDelay = 10s;
static constexpr auto maxBindDelay = 10000s;
@@ -293,6 +300,7 @@
mTimedQueue(sm.getTimedQueue()),
mProgressUpdateJobQueue(sm.getProgressUpdateJobQueue()),
mFs(sm.getFs()),
+ mClock(sm.getClock()),
mIncrementalDir(rootDir) {
CHECK(mVold) << "Vold service is unavailable";
CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable";
@@ -302,6 +310,7 @@
CHECK(mTimedQueue) << "TimedQueue is unavailable";
CHECK(mProgressUpdateJobQueue) << "mProgressUpdateJobQueue is unavailable";
CHECK(mFs) << "Fs is unavailable";
+ CHECK(mClock) << "Clock is unavailable";
mJobQueue.reserve(16);
mJobProcessor = std::thread([this]() {
@@ -2241,17 +2250,44 @@
<< status << " (current " << mCurrentStatus << ")";
}
-Milliseconds IncrementalService::DataLoaderStub::updateBindDelay() {
+std::optional<Milliseconds> IncrementalService::DataLoaderStub::needToBind() {
std::unique_lock lock(mMutex);
+
+ const auto now = mService.mClock->now();
+ const bool healthy = (mPreviousBindDelay == 0ms);
+
+ if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_BINDING &&
+ now - mCurrentStatusTs <= Constants::bindingTimeout) {
+ LOG(INFO) << "Binding still in progress. "
+ << (healthy ? "The DL is healthy/freshly bound, ok to retry for a few times."
+ : "Already unhealthy, don't do anything.");
+ // Binding still in progress.
+ if (!healthy) {
+ // Already unhealthy, don't do anything.
+ return {};
+ }
+ // The DL is healthy/freshly bound, ok to retry for a few times.
+ if (now - mPreviousBindTs <= Constants::bindGracePeriod) {
+ // Still within grace period.
+ if (now - mCurrentStatusTs >= Constants::bindRetryInterval) {
+ // Retry interval passed, retrying.
+ mCurrentStatusTs = now;
+ mPreviousBindDelay = 0ms;
+ return 0ms;
+ }
+ return {};
+ }
+ // fallthrough, mark as unhealthy, and retry with delay
+ }
+
const auto previousBindTs = mPreviousBindTs;
- const auto now = Clock::now();
mPreviousBindTs = now;
const auto nonCrashingInterval = std::max(castToMs(now - previousBindTs), 100ms);
if (previousBindTs.time_since_epoch() == Clock::duration::zero() ||
nonCrashingInterval > Constants::healthyDataLoaderUptime) {
mPreviousBindDelay = 0ms;
- return mPreviousBindDelay;
+ return 0ms;
}
constexpr auto minBindDelayMs = castToMs(Constants::minBindDelay);
@@ -2264,12 +2300,16 @@
const auto bindDelayJitterRangeMs = bindDelayMs / Constants::bindDelayJitterDivider;
const auto bindDelayJitterMs = rand() % (bindDelayJitterRangeMs * 2) - bindDelayJitterRangeMs;
mPreviousBindDelay = std::chrono::milliseconds(bindDelayMs + bindDelayJitterMs);
-
return mPreviousBindDelay;
}
bool IncrementalService::DataLoaderStub::bind() {
- const auto bindDelay = updateBindDelay();
+ const auto maybeBindDelay = needToBind();
+ if (!maybeBindDelay) {
+ LOG(DEBUG) << "Skipping bind to " << mParams.packageName << " because of pending bind.";
+ return true;
+ }
+ const auto bindDelay = *maybeBindDelay;
if (bindDelay > 1s) {
LOG(INFO) << "Delaying bind to " << mParams.packageName << " by "
<< bindDelay.count() / 1000 << "s";
@@ -2279,7 +2319,21 @@
auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, bindDelay.count(),
this, &result);
if (!status.isOk() || !result) {
- LOG(ERROR) << "Failed to bind a data loader for mount " << id();
+ const bool healthy = (bindDelay == 0ms);
+ LOG(ERROR) << "Failed to bind a data loader for mount " << id()
+ << (healthy ? ", retrying." : "");
+
+ // Internal error, retry for healthy/new DLs.
+ // Let needToBind migrate it to unhealthy after too many retries.
+ if (healthy) {
+ if (mService.addTimedJob(*mService.mTimedQueue, id(), Constants::bindRetryInterval,
+ [this]() { fsmStep(); })) {
+ // Mark as binding so that we know it's not the DL's fault.
+ setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_BINDING);
+ return true;
+ }
+ }
+
return false;
}
return true;
@@ -2339,7 +2393,14 @@
// Do nothing, this is a reset state.
break;
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
- return destroy();
+ switch (currentStatus) {
+ case IDataLoaderStatusListener::DATA_LOADER_BINDING:
+ setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
+ return true;
+ default:
+ return destroy();
+ }
+ break;
}
case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
switch (currentStatus) {
@@ -2353,6 +2414,7 @@
switch (currentStatus) {
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED:
case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
+ case IDataLoaderStatusListener::DATA_LOADER_BINDING:
return bind();
case IDataLoaderStatusListener::DATA_LOADER_BOUND:
return create();
@@ -2372,7 +2434,8 @@
fromServiceSpecificError(-EINVAL, "onStatusChange came to invalid DataLoaderStub");
}
if (id() != mountId) {
- LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId;
+ LOG(ERROR) << "onStatusChanged: mount ID mismatch: expected " << id()
+ << ", but got: " << mountId;
return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
}
if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
@@ -2396,11 +2459,13 @@
}
oldStatus = mCurrentStatus;
- mCurrentStatus = newStatus;
targetStatus = mTargetStatus;
-
listener = mStatusListener;
+ // Change the status.
+ mCurrentStatus = newStatus;
+ mCurrentStatusTs = mService.mClock->now();
+
if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE ||
mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
// For unavailable, unbind from DataLoader to ensure proper re-commit.
@@ -2428,7 +2493,8 @@
"reportStreamHealth came to invalid DataLoaderStub");
}
if (id() != mountId) {
- LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId;
+ LOG(ERROR) << "reportStreamHealth: mount ID mismatch: expected " << id()
+ << ", but got: " << mountId;
return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
}
{
@@ -2694,6 +2760,8 @@
void IncrementalService::DataLoaderStub::onDump(int fd) {
dprintf(fd, " dataLoader: {\n");
dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
+ dprintf(fd, " currentStatusTs: %lldmcs\n",
+ (long long)(elapsedMcs(mCurrentStatusTs, Clock::now())));
dprintf(fd, " targetStatus: %d\n", mTargetStatus);
dprintf(fd, " targetStatusTs: %lldmcs\n",
(long long)(elapsedMcs(mTargetStatusTs, Clock::now())));
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 14e5a77..4eb5138 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -267,7 +267,10 @@
BootClockTsUs getOldestTsFromLastPendingReads();
Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs);
- Milliseconds updateBindDelay();
+ // If the stub has to bind to the DL.
+ // Returns {} if bind operation is already in progress.
+ // Or bind delay in ms.
+ std::optional<Milliseconds> needToBind();
void registerForPendingReads();
void unregisterFromPendingReads();
@@ -283,6 +286,7 @@
std::condition_variable mStatusCondition;
int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
+ TimePoint mCurrentStatusTs = {};
int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
TimePoint mTargetStatusTs = {};
@@ -443,6 +447,7 @@
const std::unique_ptr<TimedQueueWrapper> mTimedQueue;
const std::unique_ptr<TimedQueueWrapper> mProgressUpdateJobQueue;
const std::unique_ptr<FsWrapper> mFs;
+ const std::unique_ptr<ClockWrapper> mClock;
const std::string mIncrementalDir;
mutable std::mutex mLock;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index d613289..80f409f 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -329,6 +329,14 @@
}
};
+class RealClockWrapper final : public ClockWrapper {
+public:
+ RealClockWrapper() = default;
+ ~RealClockWrapper() = default;
+
+ TimePoint now() const final { return Clock::now(); }
+};
+
RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
: mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
@@ -388,6 +396,10 @@
return std::make_unique<RealFsWrapper>();
}
+std::unique_ptr<ClockWrapper> RealServiceManager::getClock() {
+ return std::make_unique<RealClockWrapper>();
+}
+
static JavaVM* getJavaVm(JNIEnv* env) {
CHECK(env);
JavaVM* jvm = nullptr;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 245bb31..d113f99 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -158,6 +158,12 @@
virtual void listFilesRecursive(std::string_view directoryPath, FileCallback onFile) const = 0;
};
+class ClockWrapper {
+public:
+ virtual ~ClockWrapper() = default;
+ virtual TimePoint now() const = 0;
+};
+
class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
@@ -170,6 +176,7 @@
virtual std::unique_ptr<TimedQueueWrapper> getTimedQueue() = 0;
virtual std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() = 0;
virtual std::unique_ptr<FsWrapper> getFs() = 0;
+ virtual std::unique_ptr<ClockWrapper> getClock() = 0;
};
// --- Real stuff ---
@@ -187,6 +194,7 @@
std::unique_ptr<TimedQueueWrapper> getTimedQueue() final;
std::unique_ptr<TimedQueueWrapper> getProgressUpdateJobQueue() final;
std::unique_ptr<FsWrapper> getFs() final;
+ std::unique_ptr<ClockWrapper> getClock() final;
private:
template <class INTERFACE>
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 5236983..25b34b56 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -248,6 +248,27 @@
}
return binder::Status::ok();
}
+ binder::Status bindToDataLoaderNotOkWithNoDelay(int32_t mountId,
+ const DataLoaderParamsParcel& params,
+ int bindDelayMs,
+ const sp<IDataLoaderStatusListener>& listener,
+ bool* _aidl_return) {
+ CHECK(bindDelayMs == 0) << bindDelayMs;
+ *_aidl_return = false;
+ return binder::Status::ok();
+ }
+ binder::Status bindToDataLoaderBindingWithNoDelay(int32_t mountId,
+ const DataLoaderParamsParcel& params,
+ int bindDelayMs,
+ const sp<IDataLoaderStatusListener>& listener,
+ bool* _aidl_return) {
+ CHECK(bindDelayMs == 0) << bindDelayMs;
+ *_aidl_return = true;
+ if (listener) {
+ listener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_BINDING);
+ }
+ return binder::Status::ok();
+ }
binder::Status bindToDataLoaderOkWith10sDelay(int32_t mountId,
const DataLoaderParamsParcel& params,
int bindDelayMs,
@@ -557,6 +578,21 @@
}
};
+class MockClockWrapper : public ClockWrapper {
+public:
+ MOCK_CONST_METHOD0(now, TimePoint());
+
+ void start() { ON_CALL(*this, now()).WillByDefault(Invoke(this, &MockClockWrapper::getClock)); }
+ template <class Delta>
+ void advance(Delta delta) {
+ mClock += delta;
+ }
+
+ TimePoint getClock() const { return mClock; }
+
+ TimePoint mClock = Clock::now();
+};
+
class MockStorageHealthListener : public os::incremental::BnStorageHealthListener {
public:
MOCK_METHOD2(onHealthStatus, binder::Status(int32_t storageId, int32_t status));
@@ -594,7 +630,7 @@
std::unique_ptr<MockLooperWrapper> looper,
std::unique_ptr<MockTimedQueueWrapper> timedQueue,
std::unique_ptr<MockTimedQueueWrapper> progressUpdateJobQueue,
- std::unique_ptr<MockFsWrapper> fs)
+ std::unique_ptr<MockFsWrapper> fs, std::unique_ptr<MockClockWrapper> clock)
: mVold(std::move(vold)),
mDataLoaderManager(std::move(dataLoaderManager)),
mIncFs(std::move(incfs)),
@@ -603,7 +639,8 @@
mLooper(std::move(looper)),
mTimedQueue(std::move(timedQueue)),
mProgressUpdateJobQueue(std::move(progressUpdateJobQueue)),
- mFs(std::move(fs)) {}
+ mFs(std::move(fs)),
+ mClock(std::move(clock)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
return std::move(mDataLoaderManager);
@@ -619,6 +656,7 @@
return std::move(mProgressUpdateJobQueue);
}
std::unique_ptr<FsWrapper> getFs() final { return std::move(mFs); }
+ std::unique_ptr<ClockWrapper> getClock() final { return std::move(mClock); }
private:
std::unique_ptr<MockVoldService> mVold;
@@ -630,6 +668,7 @@
std::unique_ptr<MockTimedQueueWrapper> mTimedQueue;
std::unique_ptr<MockTimedQueueWrapper> mProgressUpdateJobQueue;
std::unique_ptr<MockFsWrapper> mFs;
+ std::unique_ptr<MockClockWrapper> mClock;
};
// --- IncrementalServiceTest ---
@@ -657,6 +696,8 @@
mProgressUpdateJobQueue = progressUpdateJobQueue.get();
auto fs = std::make_unique<NiceMock<MockFsWrapper>>();
mFs = fs.get();
+ auto clock = std::make_unique<NiceMock<MockClockWrapper>>();
+ mClock = clock.get();
mIncrementalService = std::make_unique<
IncrementalService>(MockServiceManager(std::move(vold),
std::move(dataloaderManager),
@@ -664,12 +705,13 @@
std::move(jni), std::move(looper),
std::move(timedQueue),
std::move(progressUpdateJobQueue),
- std::move(fs)),
+ std::move(fs), std::move(clock)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
mDataLoaderManager->unbindFromDataLoaderSuccess();
mIncrementalService->onSystemReady();
+ mClock->start();
setupSuccess();
}
@@ -724,6 +766,7 @@
NiceMock<MockTimedQueueWrapper>* mTimedQueue = nullptr;
NiceMock<MockTimedQueueWrapper>* mProgressUpdateJobQueue = nullptr;
NiceMock<MockFsWrapper>* mFs = nullptr;
+ NiceMock<MockClockWrapper>* mClock = nullptr;
NiceMock<MockDataLoader>* mDataLoader = nullptr;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
@@ -853,6 +896,119 @@
mDataLoaderManager->setDataLoaderStatusDestroyed();
}
+TEST_F(IncrementalServiceTest, testDataLoaderOnRestart) {
+ mIncFs->waitForPendingReadsSuccess();
+ mIncFs->openMountSuccess();
+
+ constexpr auto bindRetryInterval = 5s;
+
+ EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(10);
+ EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(1);
+ EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(6);
+ EXPECT_CALL(*mDataLoader, start(_)).Times(6);
+ EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(2);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+
+ // First binds to DataLoader fails... because it's restart.
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderNotOkWithNoDelay));
+
+ // Request DL start.
+ mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {}, {}, {});
+
+ // Retry callback present.
+ ASSERT_EQ(storageId, mTimedQueue->mId);
+ ASSERT_EQ(mTimedQueue->mAfter, bindRetryInterval);
+ auto retryCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // Expecting the same bindToDataLoaderNotOkWithNoDelay call.
+ mClock->advance(5s);
+
+ retryCallback();
+ // Retry callback present.
+ ASSERT_EQ(storageId, mTimedQueue->mId);
+ ASSERT_EQ(mTimedQueue->mAfter, bindRetryInterval);
+ retryCallback = mTimedQueue->mWhat;
+ mTimedQueue->clearJob(storageId);
+
+ // Returning "binding" so that we can retry.
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderBindingWithNoDelay));
+
+ // Expecting bindToDataLoaderBindingWithNoDelay call.
+ mClock->advance(5s);
+
+ retryCallback();
+ // No retry callback.
+ ASSERT_EQ(mTimedQueue->mAfter, 0ms);
+ ASSERT_EQ(mTimedQueue->mWhat, nullptr);
+
+ // Should not change the bindToDataLoader call count
+ ASSERT_NE(nullptr, mLooper->mCallback);
+ ASSERT_NE(nullptr, mLooper->mCallbackData);
+ auto looperCb = mLooper->mCallback;
+ auto looperCbData = mLooper->mCallbackData;
+ looperCb(-1, -1, looperCbData);
+
+ // Expecting the same bindToDataLoaderBindingWithNoDelay call.
+ mClock->advance(5s);
+
+ // Use pending reads callback to trigger binding.
+ looperCb(-1, -1, looperCbData);
+
+ // No retry callback.
+ ASSERT_EQ(mTimedQueue->mAfter, 0ms);
+ ASSERT_EQ(mTimedQueue->mWhat, nullptr);
+
+ // Now we are out of 10m "retry" budget, let's finally bind.
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager, &MockDataLoaderManager::bindToDataLoaderOk));
+ mClock->advance(11min);
+
+ // Use pending reads callback to trigger binding.
+ looperCb(-1, -1, looperCbData);
+
+ // No retry callback.
+ ASSERT_EQ(mTimedQueue->mAfter, 0ms);
+ ASSERT_EQ(mTimedQueue->mWhat, nullptr);
+
+ // And test the rest of the backoff.
+ // Simulated crash/other connection breakage.
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWith10sDelay));
+ mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWith100sDelay));
+ mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWith1000sDelay));
+ mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay));
+ mDataLoaderManager->setDataLoaderStatusDestroyed();
+
+ ON_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _))
+ .WillByDefault(Invoke(mDataLoaderManager,
+ &MockDataLoaderManager::bindToDataLoaderOkWith10000sDelay));
+ mDataLoaderManager->setDataLoaderStatusDestroyed();
+}
+
TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) {
mDataLoader->initializeCreateOkNoStatus();
EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _, _)).Times(1);
diff --git a/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java b/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java
index 169b85e..b07fe19 100644
--- a/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java
+++ b/services/smartspace/java/com/android/server/smartspace/SmartspaceManagerService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.MANAGE_SMARTSPACE;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.content.Context.SMARTSPACE_SERVICE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -161,11 +162,13 @@
Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
}
- if (!(mServiceNameResolver.isTemporary(userId)
+ Context ctx = getContext();
+ if (!(ctx.checkCallingPermission(MANAGE_SMARTSPACE) == PERMISSION_GRANTED
+ || mServiceNameResolver.isTemporary(userId)
|| mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) {
- String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid();
+ String msg = "Permission Denial: Cannot call " + func + " from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index f00edcc..fcd6b84 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -120,6 +120,11 @@
return this;
}
+ CompatConfigBuilder addEnabledSinceApexChangeWithId(int sdk, long id) {
+ mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "", false));
+ return this;
+ }
+
CompatConfig build() {
CompatConfig config = new CompatConfig(mBuildClassifier, mContext);
config.forceNonDebuggableFinalForTest(false);
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index b6b6932..bd77405 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -86,6 +86,7 @@
// Assume userdebug/eng non-final build
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+ when(mBuildClassifier.platformTargetSdk()).thenReturn(30);
ChangeIdStateCache.disable();
when(mPackageManager.getApplicationInfo(anyString(), anyInt()))
.thenThrow(new NameNotFoundException());
@@ -567,6 +568,34 @@
}
@Test
+ public void testReadApexConfig() throws IOException {
+ String configXml = "<config>"
+ + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
+ + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />"
+ + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />"
+ + "<compat-change id=\"1237\" name=\"MY_CHANGE4\" enableSinceTargetSdk=\"31\" />"
+ + "</config>";
+
+ File dir = createTempDir();
+ writeToFile(dir, "platform_compat_config.xml", configXml);
+ CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
+ compatConfig.forceNonDebuggableFinalForTest(false);
+
+ compatConfig.initConfigFromLib(dir);
+
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1234L,
+ ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1235L,
+ ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
+ assertThat(compatConfig.isChangeEnabled(1236L,
+ ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
+ assertThat(compatConfig.isChangeEnabled(1237L,
+ ApplicationInfoBuilder.create().withTargetSdk(31).build())).isTrue();
+ }
+
+ @Test
public void testReadConfigMultipleFiles() throws IOException {
String configXml1 = "<config>"
+ "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index 0fd6445..57fdcd3 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -22,6 +22,7 @@
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
+import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD;
import static com.google.common.truth.Truth.assertThat;
@@ -52,6 +53,7 @@
private static final int TARGET_SDK = 10;
private static final int TARGET_SDK_BEFORE = 9;
private static final int TARGET_SDK_AFTER = 11;
+ private static final int PLATFORM_SDK_VERSION = 30;
@Mock
private PackageManager mPackageManager;
@@ -61,6 +63,7 @@
private AndroidBuildClassifier debuggableBuild() {
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
when(buildClassifier.isDebuggableBuild()).thenReturn(true);
+ when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
return buildClassifier;
}
@@ -68,6 +71,7 @@
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
when(buildClassifier.isDebuggableBuild()).thenReturn(false);
when(buildClassifier.isFinalBuild()).thenReturn(false);
+ when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
return buildClassifier;
}
@@ -75,6 +79,7 @@
AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class);
when(buildClassifier.isDebuggableBuild()).thenReturn(false);
when(buildClassifier.isFinalBuild()).thenReturn(true);
+ when(buildClassifier.platformTargetSdk()).thenReturn(PLATFORM_SDK_VERSION);
return buildClassifier;
}
@@ -333,6 +338,26 @@
}
@Test
+ public void getOverrideAllowedState_targetSdkChangeGreaterThanOsVersion_rejectOverride()
+ throws Exception {
+ final AndroidBuildClassifier buildClassifier = finalBuild();
+ CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
+ .addEnabledSinceApexChangeWithId(PLATFORM_SDK_VERSION + 1, 1).build();
+ IOverrideValidator overrideValidator = config.getOverrideValidator();
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create()
+ .withPackageName(PACKAGE_NAME)
+ .debuggable()
+ .build());
+
+ OverrideAllowedState stateTargetSdkLessChange =
+ overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
+ assertThat(stateTargetSdkLessChange).isEqualTo(
+ new OverrideAllowedState(PLATFORM_TOO_OLD, -1,
+ PLATFORM_SDK_VERSION));
+ }
+
+ @Test
public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 799b067..3fc6e99 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -78,11 +78,12 @@
when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
.thenThrow(new PackageManager.NameNotFoundException());
mCompatConfig = new CompatConfig(mBuildClassifier, mContext);
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
// Assume userdebug/eng non-final build
mCompatConfig.forceNonDebuggableFinalForTest(false);
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
when(mBuildClassifier.isFinalBuild()).thenReturn(false);
+ when(mBuildClassifier.platformTargetSdk()).thenReturn(30);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
}
@@ -99,7 +100,7 @@
.addLoggingOnlyChangeWithId(7L)
.addOverridableChangeWithId(8L)
.build();
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly(
new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -125,8 +126,9 @@
.addEnableSinceSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
.addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 6L)
.addLoggingOnlyChangeWithId(7L)
+ .addEnableSinceSdkChangeWithId(31, 8L)
.build();
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly(
new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false),
new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false),
@@ -144,7 +146,7 @@
.addEnableAfterSdkChangeWithId(Build.VERSION_CODES.O, 3L)
.build();
mCompatConfig.forceNonDebuggableFinalForTest(true);
- mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
+ mPlatformCompat = new PlatformCompat(mContext, mCompatConfig, mBuildClassifier);
// Before adding overrides.
assertThat(mPlatformCompat.isChangeEnabledByPackageName(1, PACKAGE_NAME, 0)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 89435e9..77a39d8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -107,6 +107,7 @@
import android.telephony.data.ApnSetting;
import android.test.MoreAsserts; // TODO(b/171932723): replace by Truth
import android.util.ArraySet;
+import android.util.Log;
import android.util.Pair;
import androidx.test.filters.SmallTest;
@@ -154,6 +155,9 @@
@SmallTest
@Presubmit
public class DevicePolicyManagerTest extends DpmTestBase {
+
+ private static final String TAG = DevicePolicyManagerTest.class.getSimpleName();
+
private static final List<String> OWNER_SETUP_PERMISSIONS = Arrays.asList(
permission.MANAGE_DEVICE_ADMINS, permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
@@ -7187,6 +7191,47 @@
assertThat(dpm.isUsbDataSignalingEnabled()).isEqualTo(enabled);
}
+ @Test
+ public void testGetPolicyExemptApps_noPermission() {
+ assertThrows(SecurityException.class, () -> dpm.getPolicyExemptApps());
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_empty() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps();
+ mockVendorPolicyExemptApps();
+
+ assertThat(dpm.getPolicyExemptApps()).isEmpty();
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_baseOnly() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps("foo");
+ mockVendorPolicyExemptApps();
+
+ assertThat(dpm.getPolicyExemptApps()).containsExactly("foo");
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_vendorOnly() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps();
+ mockVendorPolicyExemptApps("bar");
+
+ assertThat(dpm.getPolicyExemptApps()).containsExactly("bar");
+ }
+
+ @Test
+ public void testGetPolicyExemptApps_baseAndVendor() {
+ grantManageDeviceAdmins();
+ mockPolicyExemptApps("4", "23", "15", "42", "8");
+ mockVendorPolicyExemptApps("16", "15", "4");
+
+ assertThat(dpm.getPolicyExemptApps()).containsExactly("4", "8", "15", "16", "23", "42");
+ }
+
private void setUserUnlocked(int userHandle, boolean unlocked) {
when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
}
@@ -7408,4 +7453,18 @@
return new StringParceledListSlice(Arrays.asList(s));
}
+ private void grantManageDeviceAdmins() {
+ Log.d(TAG, "Granting " + permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ }
+
+ private void mockPolicyExemptApps(String... apps) {
+ Log.d(TAG, "Mocking R.array.policy_exempt_apps to return " + Arrays.toString(apps));
+ when(mContext.resources.getStringArray(R.array.policy_exempt_apps)).thenReturn(apps);
+ }
+
+ private void mockVendorPolicyExemptApps(String... apps) {
+ Log.d(TAG, "Mocking R.array.vendor_policy_exempt_apps to return " + Arrays.toString(apps));
+ when(mContext.resources.getStringArray(R.array.vendor_policy_exempt_apps)).thenReturn(apps);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index 2fe47d3..2fe2f40 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -65,9 +65,10 @@
Map<Integer, ComponentName> mUserToComponent = new HashMap<>();
Map<ComponentName, DeviceAdminInfo> mComponentToDeviceAdminInfo = new HashMap<>();
File mDataDir;
+ int[] mUsers;
@Override
- public boolean isUserDeviceOwner(int userId, ComponentName who) {
+ public boolean isDeviceOwner(int userId, ComponentName who) {
return userId == mDeviceOwnerUserId && mDeviceOwnerComponent.equals(who);
}
@@ -105,6 +106,11 @@
public Function<ComponentName, DeviceAdminInfo> getAdminInfoSupplier(int userId) {
return componentName -> mComponentToDeviceAdminInfo.get(componentName);
}
+
+ @Override
+ public int[] getUsersForUpgrade() {
+ return mUsers;
+ }
}
private final Context mRealTestContext = InstrumentationRegistry.getTargetContext();
@@ -126,16 +132,17 @@
ActivityInfo activityInfo = createActivityInfo(mFakeAdmin);
DeviceAdminInfo dai = createDeviceAdminInfo(activityInfo);
mProvider.mComponentToDeviceAdminInfo.put(mFakeAdmin, dai);
+ mProvider.mUsers = new int[] {0};
}
@Test
public void testSameVersionDoesNothing() throws IOException {
- int[] users = new int[] {0};
writeVersionToXml(DevicePolicyManagerService.DPMS_VERSION);
- preparePoliciesFile(users[0]);
- String oldContents = readPoliciesFile(0);
+ final int userId = mProvider.mUsers[0];
+ preparePoliciesFile(userId);
+ String oldContents = readPoliciesFile(userId);
- mUpgrader.upgradePolicy(users, DevicePolicyManagerService.DPMS_VERSION);
+ mUpgrader.upgradePolicy(DevicePolicyManagerService.DPMS_VERSION);
String newContents = readPoliciesFile(0);
assertThat(newContents).isEqualTo(oldContents);
@@ -144,18 +151,18 @@
@Test
public void testUpgrade0To1RemovesPasswordMetrics() throws IOException, XmlPullParserException {
final String activePasswordTag = "active-password";
- int[] users = new int[] {0, 10};
+ mProvider.mUsers = new int[] {0, 10};
writeVersionToXml(0);
- for (int userId : users) {
+ for (int userId : mProvider.mUsers) {
preparePoliciesFile(userId);
}
// Validate test set-up.
assertThat(isTagPresent(readPoliciesFileToStream(0), activePasswordTag)).isTrue();
- mUpgrader.upgradePolicy(users, 1);
+ mUpgrader.upgradePolicy(1);
assertThat(readVersionFromXml()).isGreaterThan(1);
- for (int user: users) {
+ for (int user: mProvider.mUsers) {
assertThat(isTagPresent(readPoliciesFileToStream(user), activePasswordTag)).isFalse();
}
}
@@ -163,21 +170,22 @@
@Test
public void testUpgrade1To2MarksDoForPermissionControl()
throws IOException, XmlPullParserException {
- int[] users = new int[] {0, 10};
+ final int ownerUser = 10;
+ mProvider.mUsers = new int[] {0, ownerUser};
writeVersionToXml(1);
- for (int userId : users) {
+ for (int userId : mProvider.mUsers) {
preparePoliciesFile(userId);
}
- mProvider.mDeviceOwnerUserId = 10;
+ mProvider.mDeviceOwnerUserId = ownerUser;
mProvider.mDeviceOwnerComponent = mFakeAdmin;
- mProvider.mUserToComponent.put(10, mFakeAdmin);
+ mProvider.mUserToComponent.put(ownerUser, mFakeAdmin);
- mUpgrader.upgradePolicy(users, 2);
+ mUpgrader.upgradePolicy(2);
assertThat(readVersionFromXml()).isEqualTo(2);
- assertThat(getBooleanValueTag(readPoliciesFileToStream(users[0]),
+ assertThat(getBooleanValueTag(readPoliciesFileToStream(mProvider.mUsers[0]),
PERMISSIONS_TAG)).isFalse();
- assertThat(getBooleanValueTag(readPoliciesFileToStream(users[1]),
+ assertThat(getBooleanValueTag(readPoliciesFileToStream(ownerUser),
PERMISSIONS_TAG)).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index 843296e..dbb415c 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -68,7 +68,7 @@
*/
private static class FakeFontFileParser implements UpdatableFontDir.FontFileParser {
@Override
- public String getPostScriptName(File file) throws IOException {
+ public String getCanonicalFileName(File file) throws IOException {
String content = FileUtils.readTextFile(file, 100, "");
return content.split(",")[0];
}
@@ -160,10 +160,10 @@
assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis())
.isEqualTo(expectedModifiedDate);
dirForPreparation.update(Arrays.asList(
- newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
- newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family name='foobar'>"
+ " <font>foo.ttf</font>"
+ " <font>bar.ttf</font>"
@@ -214,10 +214,10 @@
mConfigFile);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
- newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
- newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family name='foobar'>"
+ " <font>foo.ttf</font>"
+ " <font>bar.ttf</font>"
@@ -246,10 +246,10 @@
mConfigFile);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
- newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
- newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family name='foobar'>"
+ " <font>foo.ttf</font>"
+ " <font>bar.ttf</font>"
@@ -279,10 +279,10 @@
mConfigFile);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
- newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,2", GOOD_SIGNATURE),
- newFontUpdateRequest("foo,3", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,4", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,3", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,4", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family name='foobar'>"
+ " <font>foo.ttf</font>"
+ " <font>bar.ttf</font>"
@@ -332,14 +332,14 @@
mConfigFile);
dirForPreparation.loadFontFileMap();
dirForPreparation.update(Arrays.asList(
- newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family name='foobar'>"
+ " <font>foo.ttf</font>"
+ "</family>")));
try {
dirForPreparation.update(Arrays.asList(
- newFontUpdateRequest("foo,2", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,2", "Invalid signature"),
+ newFontUpdateRequest("foo.ttf,2", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,2", "Invalid signature"),
newAddFontFamilyRequest("<family name='foobar'>"
+ " <font>foo.ttf</font>"
+ " <font>bar.ttf</font>"
@@ -372,7 +372,7 @@
mConfigFile);
dir.loadFontFileMap();
- dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE)));
assertThat(dir.getFontFileMap()).containsKey("test.ttf");
assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(1);
File fontFile = dir.getFontFileMap().get("test.ttf");
@@ -390,9 +390,9 @@
mConfigFile);
dir.loadFontFileMap();
- dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE)));
Map<String, File> mapBeforeUpgrade = dir.getFontFileMap();
- dir.update(Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2", GOOD_SIGNATURE)));
assertThat(dir.getFontFileMap()).containsKey("test.ttf");
assertThat(parser.getRevision(dir.getFontFileMap().get("test.ttf"))).isEqualTo(2);
assertThat(mapBeforeUpgrade).containsKey("test.ttf");
@@ -409,9 +409,10 @@
mConfigFile);
dir.loadFontFileMap();
- dir.update(Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2", GOOD_SIGNATURE)));
try {
- dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1",
+ GOOD_SIGNATURE)));
fail("Expect SystemFontException");
} catch (FontManagerService.SystemFontException e) {
assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
@@ -430,8 +431,8 @@
mConfigFile);
dir.loadFontFileMap();
- dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
- dir.update(Collections.singletonList(newFontUpdateRequest("bar,2", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE)));
assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1);
assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
@@ -448,8 +449,8 @@
dir.loadFontFileMap();
dir.update(Arrays.asList(
- newFontUpdateRequest("foo,1", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,2", GOOD_SIGNATURE)));
+ newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,2", GOOD_SIGNATURE)));
assertThat(dir.getFontFileMap()).containsKey("foo.ttf");
assertThat(parser.getRevision(dir.getFontFileMap().get("foo.ttf"))).isEqualTo(1);
assertThat(dir.getFontFileMap()).containsKey("bar.ttf");
@@ -467,7 +468,8 @@
try {
dir.update(
- Collections.singletonList(newFontUpdateRequest("test,1", "Invalid signature")));
+ Collections.singletonList(newFontUpdateRequest("test.ttf,1",
+ "Invalid signature")));
fail("Expect SystemFontException");
} catch (FontManagerService.SystemFontException e) {
assertThat(e.getErrorCode())
@@ -480,14 +482,15 @@
public void installFontFile_olderThanPreinstalledFont() throws Exception {
FakeFontFileParser parser = new FakeFontFileParser();
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
- FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test,1");
+ FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1");
UpdatableFontDir dir = new UpdatableFontDir(
mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil,
mConfigFile);
dir.loadFontFileMap();
try {
- dir.update(Collections.singletonList(newFontUpdateRequest("test,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1",
+ GOOD_SIGNATURE)));
fail("Expect SystemFontException");
} catch (FontManagerService.SystemFontException e) {
assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING);
@@ -500,7 +503,7 @@
long expectedModifiedDate = 1234567890;
FakeFontFileParser parser = new FakeFontFileParser();
FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
- FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test,1");
+ FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1");
File readonlyDir = new File(mCacheDir, "readonly");
assertThat(readonlyDir.mkdir()).isTrue();
@@ -519,7 +522,8 @@
try {
dir.update(
- Collections.singletonList(newFontUpdateRequest("test,2", GOOD_SIGNATURE)));
+ Collections.singletonList(newFontUpdateRequest("test.ttf,2",
+ GOOD_SIGNATURE)));
} catch (FontManagerService.SystemFontException e) {
assertThat(e.getErrorCode())
.isEqualTo(FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG);
@@ -539,7 +543,7 @@
mUpdatableFontFilesDir, mPreinstalledFontDirs,
new UpdatableFontDir.FontFileParser() {
@Override
- public String getPostScriptName(File file) throws IOException {
+ public String getCanonicalFileName(File file) throws IOException {
return null;
}
@@ -551,7 +555,8 @@
dir.loadFontFileMap();
try {
- dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1",
+ GOOD_SIGNATURE)));
fail("Expect SystemFontException");
} catch (FontManagerService.SystemFontException e) {
assertThat(e.getErrorCode())
@@ -567,7 +572,7 @@
mUpdatableFontFilesDir, mPreinstalledFontDirs,
new UpdatableFontDir.FontFileParser() {
@Override
- public String getPostScriptName(File file) throws IOException {
+ public String getCanonicalFileName(File file) throws IOException {
throw new IOException();
}
@@ -579,7 +584,8 @@
dir.loadFontFileMap();
try {
- dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1",
+ GOOD_SIGNATURE)));
fail("Expect SystemFontException");
} catch (FontManagerService.SystemFontException e) {
assertThat(e.getErrorCode())
@@ -615,7 +621,8 @@
dir.loadFontFileMap();
try {
- dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1",
+ GOOD_SIGNATURE)));
fail("Expect SystemFontException");
} catch (FontManagerService.SystemFontException e) {
assertThat(e.getErrorCode())
@@ -633,11 +640,11 @@
mConfigFile);
dir.loadFontFileMap();
- dir.update(Collections.singletonList(newFontUpdateRequest("foo,1", GOOD_SIGNATURE)));
+ dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1", GOOD_SIGNATURE)));
try {
dir.update(Arrays.asList(
- newFontUpdateRequest("foo,2", GOOD_SIGNATURE),
- newFontUpdateRequest("bar,2", "Invalid signature")));
+ newFontUpdateRequest("foo.ttf,2", GOOD_SIGNATURE),
+ newFontUpdateRequest("bar.ttf,2", "Invalid signature")));
fail("Batch update with invalid signature should fail");
} catch (FontManagerService.SystemFontException e) {
// Expected
@@ -657,7 +664,7 @@
dir.loadFontFileMap();
dir.update(Arrays.asList(
- newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family name='test'>"
+ " <font>test.ttf</font>"
+ "</family>")));
@@ -680,7 +687,7 @@
try {
dir.update(Arrays.asList(
- newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family lang='en'>"
+ " <font>test.ttf</font>"
+ "</family>")));
@@ -722,7 +729,7 @@
assertNamedFamilyExists(dir.getSystemFontConfig(), "monospace");
dir.update(Arrays.asList(
- newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
// Updating an existing font family.
newAddFontFamilyRequest("<family name='monospace'>"
+ " <font>test.ttf</font>"
@@ -755,7 +762,7 @@
assertThat(firstFontFamily.getName()).isNotEmpty();
dir.update(Arrays.asList(
- newFontUpdateRequest("test,1", GOOD_SIGNATURE),
+ newFontUpdateRequest("test.ttf,1", GOOD_SIGNATURE),
newAddFontFamilyRequest("<family name='" + firstFontFamily.getName() + "'>"
+ " <font>test.ttf</font>"
+ "</family>")));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index 137bd88..375704e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -16,183 +16,206 @@
package com.android.server.hdmi;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
import android.annotation.NonNull;
import android.content.Context;
-import android.util.Slog;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
-import com.android.server.hdmi.cec.config.CecSettings;
-import com.android.server.hdmi.cec.config.XmlParser;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import javax.xml.datatype.DatatypeConfigurationException;
+import com.android.internal.R;
/**
- * Fake class which loads default system configuration with user-configurable
+ * Fake class which stubs default system configuration with user-configurable
* settings (useful for testing).
*/
final class FakeHdmiCecConfig extends HdmiCecConfig {
private static final String TAG = "FakeHdmiCecConfig";
- private static final String SYSTEM_CONFIG_XML =
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + " <setting name=\"power_state_change_on_active_source_lost\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"none\" />"
- + " <value string-value=\"standby_now\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"none\" />"
- + " </setting>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"hdmi_cec_version\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x05\" />"
- + " <value int-value=\"0x06\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x05\" />"
- + " </setting>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"volume_control_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"tv_wake_on_one_touch_play\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"tv_send_standby_on_sleep\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_tv\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0x0\" />"
- + " <value int-value=\"0x2\" />"
- + " <value int-value=\"0x6\" />"
- + " <value int-value=\"0xA\" />"
- + " <value int-value=\"0xE\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x0\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_root_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_setup_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_contents_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_top_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0\" />"
- + " </setting>"
- + " <setting name=\"rc_profile_source_handles_media_context_sensitive_menu\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0\" />"
- + " </setting>"
- + "</cec-settings>";
-
- FakeHdmiCecConfig(@NonNull Context context) {
- super(context, new StorageAdapter(context), parseFromString(SYSTEM_CONFIG_XML), null);
+ public static Context buildContext(Context context) {
+ Context contextSpy = spy(new ContextWrapper(context));
+ doReturn(buildResources(context)).when(contextSpy).getResources();
+ return contextSpy;
}
- private static CecSettings parseFromString(@NonNull String configXml) {
- CecSettings config = null;
- try {
- config = XmlParser.read(
- new ByteArrayInputStream(configXml.getBytes()));
- } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
- Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
- }
- return config;
+ private static Resources buildResources(Context context) {
+ Resources resources = spy(context.getResources());
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecEnabled_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecControlDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion14b_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion14b_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion20_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecHdmiCecVersion20_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSendStandbyOnSleep_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeTv_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeTv_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeBroadcast_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeBroadcast_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeNone_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecPowerControlModeNone_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLost_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostNone_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecPowerStateChangeOnActiveSourceLostStandbyNow_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMuting_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecSystemAudioModeMutingDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlMode_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecVolumeControlModeDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlay_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecTvWakeOnOneTouchPlayDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleep_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTv_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvNone_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvNone_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvOne_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvOne_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvTwo_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvTwo_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvThree_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvThree_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvFour_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileTvFour_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceRootMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceSetupMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceContentsMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceTopMenuNotHandled_default);
+
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenu_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuHandled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecRcProfileSourceMediaContextSensitiveMenuNotHandled_default);
+
+ return resources;
+ }
+
+ FakeHdmiCecConfig(@NonNull Context context) {
+ super(buildContext(context), new StorageAdapter(context));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index 798cf85..c834510 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -20,6 +20,7 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,6 +28,7 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.hdmi.HdmiControlManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -35,6 +37,8 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -61,265 +65,118 @@
@Mock private HdmiCecConfig.StorageAdapter mStorageAdapter;
@Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener;
+ private void setBooleanResource(int resId, boolean value) {
+ Resources resources = mContext.getResources();
+ doReturn(value).when(resources).getBoolean(resId);
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getTargetContext();
- }
-
- @Test
- public void getAllCecSettings_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThat(hdmiCecConfig.getAllSettings()).isEmpty();
- }
-
- @Test
- public void getAllCecSettings_Empty() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
- assertThat(hdmiCecConfig.getAllSettings()).isEmpty();
+ mContext = FakeHdmiCecConfig.buildContext(InstrumentationRegistry.getTargetContext());
}
@Test
public void getAllCecSettings_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllSettings())
.containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
}
@Test
- public void getUserCecSettings_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThat(hdmiCecConfig.getUserSettings()).isEmpty();
- }
-
- @Test
- public void getUserCecSettings_Empty() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
- assertThat(hdmiCecConfig.getUserSettings()).isEmpty();
- }
-
- @Test
- public void getUserCecSettings_OnlyMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ public void getUserCecSettings_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getUserSettings())
.containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
}
@Test
public void getUserCecSettings_WithOverride() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>",
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>");
+ setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getUserSettings())
- .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
- }
-
- @Test
- public void isStringValueType_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.isStringValueType("foo"));
+ .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
+ HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
+ HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ HdmiControlManager
+ .CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU);
}
@Test
public void isStringValueType_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.isStringValueType("foo"));
}
@Test
public void isStringValueType_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertTrue(hdmiCecConfig.isStringValueType(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
}
@Test
- public void isIntValueType_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.isIntValueType("foo"));
- }
-
- @Test
public void isIntValueType_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.isIntValueType("foo"));
}
@Test
public void isIntValueType_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertTrue(hdmiCecConfig.isIntValueType(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
}
@Test
- public void getAllowedStringValues_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedStringValues("foo"));
- }
-
- @Test
public void getAllowedStringValues_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedStringValues("foo"));
}
@Test
public void getAllowedStringValues_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedStringValues(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -327,21 +184,7 @@
@Test
public void getAllowedStringValues_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllowedStringValues(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
.containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
@@ -350,41 +193,25 @@
}
@Test
- public void getAllowedIntValues_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedIntValues("foo"));
+ public void getAllowedStringValues_WithOverride() {
+ setBooleanResource(R.bool.config_cecPowerControlModeNone_allowed, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
+ assertThat(hdmiCecConfig.getAllowedStringValues(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+ .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
+ HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
}
@Test
public void getAllowedIntValues_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedIntValues("foo"));
}
@Test
public void getAllowedIntValues_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getAllowedIntValues(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -392,20 +219,7 @@
@Test
public void getAllowedIntValues_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllowedIntValues(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
.containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
@@ -413,62 +227,24 @@
}
@Test
- public void getAllowedIntValues_HexValues() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x00\" />"
- + " <value int-value=\"0x01\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x01\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ public void getAllowedIntValues_WithOverride() {
+ setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_allowed, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getAllowedIntValues(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
- .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
- HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
- }
-
- @Test
- public void getDefaultStringValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultStringValue("foo"));
+ .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
}
@Test
public void getDefaultStringValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultStringValue("foo"));
}
@Test
public void getDefaultStringValue_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultStringValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -476,62 +252,46 @@
@Test
public void getDefaultStringValue_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getDefaultStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
.isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_TV);
}
@Test
- public void getDefaultIntValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultIntValue("foo"));
+ public void getDefaultStringValue_WithOverride() {
+ setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+ setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
+ assertThat(hdmiCecConfig.getDefaultStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+ .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
+ }
+
+ @Test
+ public void getDefaultStringValue_MultipleDefaults() {
+ setBooleanResource(R.bool.config_cecPowerControlModeBroadcast_default, true);
+ assertThrows(RuntimeException.class,
+ () -> new HdmiCecConfig(mContext, mStorageAdapter));
+ }
+
+ @Test
+ public void getDefaultStringValue_NoDefault() {
+ setBooleanResource(R.bool.config_cecPowerControlModeTv_default, false);
+ assertThrows(RuntimeException.class,
+ () -> new HdmiCecConfig(mContext, mStorageAdapter));
}
@Test
public void getDefaultIntValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultIntValue("foo"));
}
@Test
public void getDefaultIntValue_InvalidValueType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getDefaultIntValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -539,81 +299,32 @@
@Test
public void getDefaultIntValue_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getDefaultIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
.isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
}
@Test
- public void getDefaultIntValue_HexValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x00\" />"
- + " <value int-value=\"0x01\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x01\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ public void getDefaultIntValue_WithOverride() {
+ setBooleanResource(R.bool.config_cecHdmiCecControlEnabled_default, false);
+ setBooleanResource(R.bool.config_cecHdmiCecControlDisabled_default, true);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getDefaultIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
- .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
- }
-
- @Test
- public void getStringValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getStringValue("foo"));
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
}
@Test
public void getStringValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getStringValue("foo"));
}
@Test
public void getStringValue_InvalidType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
@@ -625,21 +336,7 @@
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.POWER_CONTROL_MODE_TV))
.thenReturn(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
.isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
@@ -652,61 +349,22 @@
HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_NONE))
.thenReturn(
HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"power_state_change_on_active_source_lost\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"none\" />"
- + " <value string-value=\"standby_now\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"none\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST))
.isEqualTo(HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
}
@Test
- public void getIntValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getIntValue("foo"));
- }
-
- @Test
public void getIntValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getIntValue("foo"));
}
@Test
public void getIntValue_InvalidType() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.getIntValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
@@ -718,45 +376,7 @@
Global.HDMI_CONTROL_ENABLED,
Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
.thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- assertThat(hdmiCecConfig.getIntValue(
- HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
- .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
- }
-
- @Test
- public void getIntValue_GlobalSetting_HexValue() {
- when(mStorageAdapter.retrieveGlobalSetting(
- Global.HDMI_CONTROL_ENABLED,
- Integer.toHexString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
- .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x0\" />"
- + " <value int-value=\"0x1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
.isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
@@ -768,61 +388,23 @@
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED)))
.thenReturn(Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThat(hdmiCecConfig.getIntValue(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING))
.isEqualTo(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
}
@Test
- public void setStringValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setStringValue("foo", "bar"));
- }
-
- @Test
public void setStringValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setStringValue("foo", "bar"));
}
@Test
public void setStringValue_NotConfigurable() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ setBooleanResource(R.bool.config_cecSendStandbyOnSleep_userConfigurable, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
@@ -831,21 +413,7 @@
@Test
public void setStringValue_InvalidValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
@@ -854,21 +422,7 @@
@Test
public void setStringValue_GlobalSetting_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"send_standby_on_sleep\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"to_tv\" />"
- + " <value string-value=\"broadcast\" />"
- + " <value string-value=\"none\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"to_tv\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
verify(mStorageAdapter).storeGlobalSetting(
@@ -878,20 +432,7 @@
@Test
public void setStringValue_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"power_state_change_on_active_source_lost\""
- + " value-type=\"string\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value string-value=\"none\" />"
- + " <value string-value=\"standby_now\" />"
- + " </allowed-values>"
- + " <default-value string-value=\"none\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
@@ -901,40 +442,16 @@
}
@Test
- public void setIntValue_NoMasterXml() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter, null, null);
- assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setIntValue("foo", 0));
- }
-
- @Test
public void setIntValue_InvalidSetting() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setIntValue("foo", 0));
}
@Test
public void setIntValue_NotConfigurable() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"false\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ setBooleanResource(R.bool.config_cecHdmiCecEnabled_userConfigurable, false);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
@@ -943,20 +460,7 @@
@Test
public void setIntValue_InvalidValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
assertThrows(IllegalArgumentException.class,
() -> hdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
@@ -965,43 +469,7 @@
@Test
public void setIntValue_GlobalSetting_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
- verify(mStorageAdapter).storeGlobalSetting(
- Global.HDMI_CONTROL_ENABLED,
- Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
- }
-
- @Test
- public void setIntValue_GlobalSetting_HexValue() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0x0\" />"
- + " <value int-value=\"0x1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"0x1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
verify(mStorageAdapter).storeGlobalSetting(
@@ -1011,20 +479,7 @@
@Test
public void setIntValue_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.setIntValue(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
@@ -1035,20 +490,7 @@
@Test
public void registerChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.registerChangeListener(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
mSettingChangeListener);
@@ -1061,20 +503,7 @@
@Test
public void removeChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.registerChangeListener(
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
mSettingChangeListener);
@@ -1100,20 +529,7 @@
String originalValue = Global.getString(mContext.getContentResolver(),
Global.HDMI_CONTROL_ENABLED);
try {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
+ HdmiCecConfig hdmiCecConfig = new HdmiCecConfig(mContext, mStorageAdapter);
hdmiCecConfig.registerGlobalSettingsObserver(mTestLooper.getLooper());
HdmiCecConfig.SettingChangeListener latchUpdateListener =
new HdmiCecConfig.SettingChangeListener() {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 907cf3e..c61635c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -136,7 +136,6 @@
mPhysicalAddress = 0x2000;
mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
mTestLooper.dispatchAll();
- mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
}
private OneTouchPlayAction createOneTouchPlayAction(HdmiCecLocalDevicePlayback device,
@@ -147,7 +146,47 @@
}
@Test
+ public void succeedWithUnknownTvDevice() {
+ HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
+ mHdmiControlService);
+ playbackDevice.init();
+ mLocalDevices.add(playbackDevice);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ TestActionTimer actionTimer = new TestActionTimer();
+ TestCallback callback = new TestCallback();
+ OneTouchPlayAction action = createOneTouchPlayAction(playbackDevice, actionTimer, callback,
+ false);
+ playbackDevice.addAndStartAction(action);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.mAddress, mPhysicalAddress);
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
+ ADDR_TV);
+ HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder
+ .buildGiveDevicePowerStatus(playbackDevice.mAddress, ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
+ mNativeWrapper.clearResultMessages();
+ assertThat(actionTimer.getState()).isEqualTo(STATE_WAITING_FOR_REPORT_POWER_STATUS);
+ HdmiCecMessage reportPowerStatusOn = new HdmiCecMessage(
+ ADDR_TV, playbackDevice.mAddress, Constants.MESSAGE_REPORT_POWER_STATUS, POWER_ON);
+ action.processCommand(reportPowerStatusOn);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
+ assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
+ }
+
+ @Test
public void succeedAfterGettingPowerStatusOn_Cec14b() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -187,6 +226,7 @@
@Test
public void succeedAfterGettingTransientPowerStatus_Cec14b() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -236,6 +276,7 @@
@Test
public void timeOut_Cec14b() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -276,6 +317,7 @@
@Test
public void succeedIfPowerStatusOn_Cec20() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -307,6 +349,7 @@
@Test
public void succeedIfPowerStatusUnknown_Cec20() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
@@ -348,6 +391,7 @@
@Test
public void succeedIfPowerStatusStandby_Cec20() {
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
mHdmiControlService);
playbackDevice.init();
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 9a52643..9f428c7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -31,6 +31,7 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.parsing.ParsingPackage;
@@ -141,6 +142,10 @@
return pkg(packageName).addReceiver(receiver);
}
+ private static ParsingPackage pkgWithSharedLibrary(String packageName, String libName) {
+ return pkg(packageName).addLibraryName(libName);
+ }
+
private static ParsedActivity createActivity(String packageName, IntentFilter[] filters) {
ParsedActivity activity = new ParsedActivity();
activity.setPackageName(packageName);
@@ -413,6 +418,118 @@
}
@Test
+ public void testNoUsesLibrary_Filters() throws Exception {
+ final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+ mMockExecutor);
+
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ final Signature mockSignature = Mockito.mock(Signature.class);
+ final SigningDetails mockSigningDetails = new SigningDetails(
+ new Signature[]{mockSignature},
+ SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+ final PackageSetting target = simulateAddPackage(appsFilter,
+ pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+ DUMMY_TARGET_APPID,
+ setting -> setting.setSigningDetails(mockSigningDetails)
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+ final PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package"), DUMMY_CALLING_APPID);
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
+ @Test
+ public void testUsesLibrary_DoesntFilter() throws Exception {
+ final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+ mMockExecutor);
+
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ final Signature mockSignature = Mockito.mock(Signature.class);
+ final SigningDetails mockSigningDetails = new SigningDetails(
+ new Signature[]{mockSignature},
+ SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+ final PackageSetting target = simulateAddPackage(appsFilter,
+ pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+ DUMMY_TARGET_APPID,
+ setting -> setting.setSigningDetails(mockSigningDetails)
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+ final PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package").addUsesLibrary("com.some.shared_library"),
+ DUMMY_CALLING_APPID);
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
+ @Test
+ public void testUsesOptionalLibrary_DoesntFilter() throws Exception {
+ final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+ mMockExecutor);
+
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ final Signature mockSignature = Mockito.mock(Signature.class);
+ final SigningDetails mockSigningDetails = new SigningDetails(
+ new Signature[]{mockSignature},
+ SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+ final PackageSetting target = simulateAddPackage(appsFilter,
+ pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+ DUMMY_TARGET_APPID,
+ setting -> setting.setSigningDetails(mockSigningDetails)
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+ final PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package").addUsesOptionalLibrary("com.some.shared_library"),
+ DUMMY_CALLING_APPID);
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
+ @Test
+ public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception {
+ final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
+ new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
+ mMockExecutor);
+
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ final Signature mockSignature = Mockito.mock(Signature.class);
+ final SigningDetails mockSigningDetails = new SigningDetails(
+ new Signature[]{mockSignature},
+ SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2);
+
+ final PackageSetting target = simulateAddPackage(appsFilter,
+ pkgWithSharedLibrary("com.some.package", "com.some.shared_library"),
+ DUMMY_TARGET_APPID,
+ setting -> setting.setSigningDetails(mockSigningDetails)
+ .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
+ final PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package_a").setSharedUserId("com.some.uid"),
+ DUMMY_CALLING_APPID);
+ simulateAddPackage(appsFilter, pkg("com.some.other.package_b")
+ .setSharedUserId("com.some.uid").addUsesLibrary("com.some.shared_library"),
+ DUMMY_CALLING_APPID);
+
+ // Although package_a doesn't use library, it should be granted visibility. It's because
+ // package_a shares userId with package_b, and package_b uses that shared library.
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
+ @Test
public void testForceQueryable_SystemDoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index bad380a..51f627a 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -118,6 +118,11 @@
}
@Override
+ public MetricsTimeZoneDetectorState generateMetricsState() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void addDumpable(Dumpable dumpable) {
mDumpables.add(dumpable);
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java
new file mode 100644
index 0000000..af954d5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/OrdinalGeneratorTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class OrdinalGeneratorTest {
+
+ @Test
+ public void testOrdinal() {
+ OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>();
+ int oneOrd = ordinalGenerator.ordinal("One");
+ int twoOrd = ordinalGenerator.ordinal("Two");
+ assertNotEquals(oneOrd, twoOrd);
+
+ assertEquals(oneOrd, ordinalGenerator.ordinal("One"));
+ assertEquals(twoOrd, ordinalGenerator.ordinal("Two"));
+
+ int threeOrd = ordinalGenerator.ordinal("Three");
+ assertNotEquals(oneOrd, threeOrd);
+ assertNotEquals(twoOrd, threeOrd);
+ }
+
+ @Test
+ public void testOrdinals() {
+ OrdinalGenerator<String> ordinalGenerator = new OrdinalGenerator<>();
+ int[] oneTwoOrds = ordinalGenerator.ordinals(Arrays.asList("One", "Two"));
+ int[] twoThreeOrds = ordinalGenerator.ordinals(Arrays.asList("Two", "Three"));
+ assertEquals(oneTwoOrds[0], ordinalGenerator.ordinal("One"));
+ assertEquals(oneTwoOrds[1], ordinalGenerator.ordinal("Two"));
+ assertEquals(twoThreeOrds[0], ordinalGenerator.ordinal("Two"));
+ assertEquals(twoThreeOrds[1], ordinalGenerator.ordinal("Three"));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index b0341d7..f91ce87 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -925,6 +925,106 @@
assertTrue(dumpCalled.get());
}
+ @Test
+ public void testGenerateMetricsState() {
+ ConfigurationInternal expectedInternalConfig = CONFIG_INT_AUTO_DISABLED_GEO_DISABLED;
+ String expectedDeviceTimeZoneId = "InitialZoneId";
+
+ Script script = new Script()
+ .initializeConfig(expectedInternalConfig)
+ .initializeTimeZoneSetting(expectedDeviceTimeZoneId);
+
+ assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId, null, null,
+ null, MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
+
+ // Make sure the manual suggestion is recorded.
+ ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Zone1");
+ script.simulateManualTimeZoneSuggestion(USER_ID, manualSuggestion,
+ true /* expectedResult */)
+ .verifyTimeZoneChangedAndReset(manualSuggestion);
+ expectedDeviceTimeZoneId = manualSuggestion.getZoneId();
+ assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+ manualSuggestion, null, null,
+ MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
+
+ // With time zone auto detection off, telephony suggestions will be recorded, but geo
+ // suggestions won't out of an abundance of caution around respecting user privacy when
+ // geo detection is off.
+ TelephonyTimeZoneSuggestion telephonySuggestion =
+ createTelephonySuggestion(0 /* slotIndex */, MATCH_TYPE_NETWORK_COUNTRY_ONLY,
+ QUALITY_SINGLE_ZONE, "Zone2");
+ GeolocationTimeZoneSuggestion geolocationTimeZoneSuggestion =
+ createGeoLocationSuggestion(Arrays.asList("Zone3", "Zone2"));
+ script.simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
+ .verifyTimeZoneNotChanged()
+ .simulateGeolocationTimeZoneSuggestion(geolocationTimeZoneSuggestion)
+ .verifyTimeZoneNotChanged();
+
+ assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+ manualSuggestion, telephonySuggestion, null /* expectedGeoSuggestion */,
+ MetricsTimeZoneDetectorState.DETECTION_MODE_MANUAL);
+
+ // Update the config and confirm that the config metrics state updates also.
+ TimeZoneConfiguration configUpdate =
+ createConfig(true /* autoDetection */, true /* geoDetection */);
+ expectedInternalConfig = new ConfigurationInternal.Builder(expectedInternalConfig)
+ .setAutoDetectionEnabled(true)
+ .setGeoDetectionEnabled(true)
+ .build();
+ script.simulateUpdateConfiguration(USER_ID, configUpdate, true /* expectedResult */)
+ .verifyConfigurationChangedAndReset(expectedInternalConfig)
+ .verifyTimeZoneNotChanged();
+ assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+ manualSuggestion, telephonySuggestion, null /* expectedGeoSuggestion */,
+ MetricsTimeZoneDetectorState.DETECTION_MODE_GEO);
+
+ // Now simulate a geo suggestion and confirm it is used and reported in the metrics too.
+ expectedDeviceTimeZoneId = geolocationTimeZoneSuggestion.getZoneIds().get(0);
+ script.simulateGeolocationTimeZoneSuggestion(geolocationTimeZoneSuggestion)
+ .verifyTimeZoneChangedAndReset(expectedDeviceTimeZoneId);
+ assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId,
+ manualSuggestion, telephonySuggestion, geolocationTimeZoneSuggestion,
+ MetricsTimeZoneDetectorState.DETECTION_MODE_GEO);
+ }
+
+ /**
+ * Asserts that the information returned by {@link
+ * TimeZoneDetectorStrategy#generateMetricsState()} matches expectations.
+ */
+ private void assertMetricsState(
+ ConfigurationInternal expectedInternalConfig,
+ String expectedDeviceTimeZoneId, ManualTimeZoneSuggestion expectedManualSuggestion,
+ TelephonyTimeZoneSuggestion expectedTelephonySuggestion,
+ GeolocationTimeZoneSuggestion expectedGeolocationTimeZoneSuggestion,
+ int expectedDetectionMode) {
+
+ MetricsTimeZoneDetectorState actualState = mTimeZoneDetectorStrategy.generateMetricsState();
+
+ // Check the various feature state values are what we expect.
+ assertFeatureStateMatchesConfig(expectedInternalConfig, actualState, expectedDetectionMode);
+
+ OrdinalGenerator<String> tzIdOrdinalGenerator = new OrdinalGenerator<>();
+ MetricsTimeZoneDetectorState expectedState =
+ MetricsTimeZoneDetectorState.create(
+ tzIdOrdinalGenerator, expectedInternalConfig, expectedDeviceTimeZoneId,
+ expectedManualSuggestion, expectedTelephonySuggestion,
+ expectedGeolocationTimeZoneSuggestion);
+ // Rely on MetricsTimeZoneDetectorState.equals() for time zone ID ordinal comparisons.
+ assertEquals(expectedState, actualState);
+ }
+
+ private static void assertFeatureStateMatchesConfig(ConfigurationInternal config,
+ MetricsTimeZoneDetectorState actualState, int expectedDetectionMode) {
+ assertEquals(config.isTelephonyDetectionSupported(),
+ actualState.isTelephonyDetectionSupported());
+ assertEquals(config.isGeoDetectionSupported(), actualState.isGeoDetectionSupported());
+ assertEquals(config.getAutoDetectionEnabledSetting(),
+ actualState.getAutoDetectionEnabledSetting());
+ assertEquals(config.getGeoDetectionEnabledSetting(),
+ actualState.getGeoDetectionEnabledSetting());
+ assertEquals(expectedDetectionMode, actualState.getDetectionMode());
+ }
+
private static ManualTimeZoneSuggestion createManualSuggestion(String zoneId) {
return new ManualTimeZoneSuggestion(zoneId);
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
index 3daa7f0..5a100a2 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java
@@ -79,15 +79,18 @@
// For simplicity, the TestThreadingDomain uses the test's main thread. To execute posted
// runnables, the test must call methods on mTestThreadingDomain otherwise those runnables
// will never get a chance to execute.
+ LocationTimeZoneProvider.ProviderMetricsLogger stubbedProviderMetricsLogger = stateEnum -> {
+ // Stubbed.
+ };
mTestThreadingDomain = new TestThreadingDomain();
mTestCallback = new TestCallback(mTestThreadingDomain);
mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator();
- mTestPrimaryLocationTimeZoneProvider =
- new TestLocationTimeZoneProvider(
- mTestThreadingDomain, "primary", mTimeZoneAvailabilityChecker);
- mTestSecondaryLocationTimeZoneProvider =
- new TestLocationTimeZoneProvider(
- mTestThreadingDomain, "secondary", mTimeZoneAvailabilityChecker);
+ mTestPrimaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
+ stubbedProviderMetricsLogger, mTestThreadingDomain, "primary",
+ mTimeZoneAvailabilityChecker);
+ mTestSecondaryLocationTimeZoneProvider = new TestLocationTimeZoneProvider(
+ stubbedProviderMetricsLogger, mTestThreadingDomain, "secondary",
+ mTimeZoneAvailabilityChecker);
}
@Test
@@ -1181,10 +1184,11 @@
/**
* Creates the instance.
*/
- TestLocationTimeZoneProvider(ThreadingDomain threadingDomain,
- String providerName,
+ TestLocationTimeZoneProvider(ProviderMetricsLogger providerMetricsLogger,
+ ThreadingDomain threadingDomain, String providerName,
TimeZoneIdValidator timeZoneIdValidator) {
- super(threadingDomain, providerName, timeZoneIdValidator);
+ super(providerMetricsLogger, threadingDomain, providerName,
+ timeZoneIdValidator);
}
public void setFailDuringInitialization(boolean failInitialization) {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
index 278fdaf..d13a04e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java
@@ -53,6 +53,7 @@
import java.time.Duration;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
@@ -79,19 +80,18 @@
@Test
public void lifecycle() {
String providerName = "arbitrary";
- TestLocationTimeZoneProvider provider =
- new TestLocationTimeZoneProvider(
- mTestThreadingDomain,
- providerName,
- mTimeZoneAvailabilityChecker);
+ RecordingProviderMetricsLogger providerMetricsLogger = new RecordingProviderMetricsLogger();
+ TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+ providerMetricsLogger, mTestThreadingDomain, providerName,
+ mTimeZoneAvailabilityChecker);
mTimeZoneAvailabilityChecker.validIds("Europe/London");
// initialize()
provider.initialize(mProviderListener);
provider.assertOnInitializeCalled();
- ProviderState currentState = provider.getCurrentState();
- assertEquals(PROVIDER_STATE_STOPPED, currentState.stateEnum);
+ ProviderState currentState = assertAndReturnProviderState(
+ provider, providerMetricsLogger, PROVIDER_STATE_STOPPED);
assertNull(currentState.currentUserConfiguration);
assertSame(provider, currentState.provider);
mTestThreadingDomain.assertQueueEmpty();
@@ -105,9 +105,9 @@
provider.assertOnStartCalled(arbitraryInitializationTimeout);
- currentState = provider.getCurrentState();
+ currentState = assertAndReturnProviderState(
+ provider, providerMetricsLogger, PROVIDER_STATE_STARTED_INITIALIZING);
assertSame(provider, currentState.provider);
- assertEquals(PROVIDER_STATE_STARTED_INITIALIZING, currentState.stateEnum);
assertEquals(config, currentState.currentUserConfiguration);
assertNull(currentState.event);
// The initialization timeout should be queued.
@@ -129,9 +129,9 @@
TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(suggestion);
provider.simulateProviderEventReceived(event);
- currentState = provider.getCurrentState();
+ currentState = assertAndReturnProviderState(
+ provider, providerMetricsLogger, PROVIDER_STATE_STARTED_CERTAIN);
assertSame(provider, currentState.provider);
- assertEquals(PROVIDER_STATE_STARTED_CERTAIN, currentState.stateEnum);
assertEquals(event, currentState.event);
assertEquals(config, currentState.currentUserConfiguration);
mTestThreadingDomain.assertQueueEmpty();
@@ -141,9 +141,9 @@
event = TimeZoneProviderEvent.createUncertainEvent();
provider.simulateProviderEventReceived(event);
- currentState = provider.getCurrentState();
+ currentState = assertAndReturnProviderState(
+ provider, providerMetricsLogger, PROVIDER_STATE_STARTED_UNCERTAIN);
assertSame(provider, currentState.provider);
- assertEquals(PROVIDER_STATE_STARTED_UNCERTAIN, currentState.stateEnum);
assertEquals(event, currentState.event);
assertEquals(config, currentState.currentUserConfiguration);
mTestThreadingDomain.assertQueueEmpty();
@@ -153,7 +153,8 @@
provider.stopUpdates();
provider.assertOnStopUpdatesCalled();
- currentState = provider.getCurrentState();
+ currentState = assertAndReturnProviderState(
+ provider, providerMetricsLogger, PROVIDER_STATE_STOPPED);
assertSame(provider, currentState.provider);
assertEquals(PROVIDER_STATE_STOPPED, currentState.stateEnum);
assertNull(currentState.event);
@@ -171,11 +172,10 @@
@Test
public void defaultHandleTestCommandImpl() {
String providerName = "primary";
- TestLocationTimeZoneProvider provider =
- new TestLocationTimeZoneProvider(
- mTestThreadingDomain,
- providerName,
- mTimeZoneAvailabilityChecker);
+ StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
+ TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+ providerMetricsLogger, mTestThreadingDomain, providerName,
+ mTimeZoneAvailabilityChecker);
TestCommand testCommand = TestCommand.createForTests("test", new Bundle());
AtomicReference<Bundle> resultReference = new AtomicReference<>();
@@ -191,11 +191,10 @@
@Test
public void stateRecording() {
String providerName = "primary";
- TestLocationTimeZoneProvider provider =
- new TestLocationTimeZoneProvider(
- mTestThreadingDomain,
- providerName,
- mTimeZoneAvailabilityChecker);
+ StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
+ TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+ providerMetricsLogger, mTestThreadingDomain, providerName,
+ mTimeZoneAvailabilityChecker);
provider.setStateChangeRecordingEnabled(true);
mTimeZoneAvailabilityChecker.validIds("Europe/London");
@@ -237,11 +236,10 @@
@Test
public void considerSuggestionWithInvalidTimeZoneIdsAsUncertain() {
String providerName = "primary";
- TestLocationTimeZoneProvider provider =
- new TestLocationTimeZoneProvider(
- mTestThreadingDomain,
- providerName,
- mTimeZoneAvailabilityChecker);
+ StubbedProviderMetricsLogger providerMetricsLogger = new StubbedProviderMetricsLogger();
+ TestLocationTimeZoneProvider provider = new TestLocationTimeZoneProvider(
+ providerMetricsLogger, mTestThreadingDomain, providerName,
+ mTimeZoneAvailabilityChecker);
provider.setStateChangeRecordingEnabled(true);
provider.initialize(mProviderListener);
@@ -285,6 +283,20 @@
}
}
+ /**
+ * Returns the provider's state after asserting that the current state matches what is expected.
+ * This also asserts that the metrics logger was informed of the state change.
+ */
+ private static ProviderState assertAndReturnProviderState(
+ TestLocationTimeZoneProvider provider,
+ RecordingProviderMetricsLogger providerMetricsLogger, int expectedStateEnum) {
+ ProviderState currentState = provider.getCurrentState();
+ assertEquals(expectedStateEnum, currentState.stateEnum);
+ providerMetricsLogger.assertChangeLoggedAndRemove(expectedStateEnum);
+ providerMetricsLogger.assertNoMoreLogEntries();
+ return currentState;
+ }
+
private static class TestLocationTimeZoneProvider extends LocationTimeZoneProvider {
private boolean mOnInitializeCalled;
@@ -294,10 +306,11 @@
private boolean mOnStopUpdatesCalled;
/** Creates the instance. */
- TestLocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain,
+ TestLocationTimeZoneProvider(@NonNull ProviderMetricsLogger providerMetricsLogger,
+ @NonNull ThreadingDomain threadingDomain,
@NonNull String providerName,
@NonNull TimeZoneIdValidator timeZoneIdValidator) {
- super(threadingDomain, providerName, timeZoneIdValidator);
+ super(providerMetricsLogger, threadingDomain, providerName, timeZoneIdValidator);
}
@Override
@@ -366,6 +379,36 @@
public void validIds(String... timeZoneIdss) {
mValidTimeZoneIds.addAll(asList(timeZoneIdss));
}
+ }
+ private static class StubbedProviderMetricsLogger implements
+ LocationTimeZoneProvider.ProviderMetricsLogger {
+
+ @Override
+ public void onProviderStateChanged(int stateEnum) {
+ // Stubbed
+ }
+ }
+
+ private static class RecordingProviderMetricsLogger implements
+ LocationTimeZoneProvider.ProviderMetricsLogger {
+
+ private LinkedList<Integer> mStates = new LinkedList<>();
+
+ @Override
+ public void onProviderStateChanged(int stateEnum) {
+ mStates.add(stateEnum);
+ }
+
+ public void assertChangeLoggedAndRemove(int expectedLoggedState) {
+ assertEquals("expected loggedState=" + expectedLoggedState
+ + " but states logged were=" + mStates,
+ (Integer) expectedLoggedState, mStates.peekFirst());
+ mStates.removeFirst();
+ }
+
+ public void assertNoMoreLogEntries() {
+ assertTrue(mStates.isEmpty());
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index d8e7582..c19f348 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -159,6 +159,11 @@
setBooted(mAtm);
}
+ private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() {
+ return new TestStartingWindowOrganizer(mAtm,
+ mSystemServicesTestRule.getPowerManagerWrapper());
+ }
+
@Test
public void testStackCleanupOnClearingTask() {
final ActivityRecord activity = createActivityWith2LevelTask();
@@ -2294,6 +2299,7 @@
@Test
public void testCreateRemoveStartingWindow() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
@@ -2307,6 +2313,7 @@
@Test
public void testAddRemoveRace() {
+ registerTestStartingWindowOrganizer();
// There was once a race condition between adding and removing starting windows
final ActivityRecord appToken = new ActivityBuilder(mAtm).setCreateTask(true).build();
for (int i = 0; i < 1000; i++) {
@@ -2321,6 +2328,7 @@
@Test
public void testTransferStartingWindow() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity1.addStartingWindow(mPackageName,
@@ -2337,9 +2345,10 @@
@Test
public void testTransferStartingWindowWhileCreating() {
+ final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer();
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
- ((TestWindowManagerPolicy) activity1.mWmService.mPolicy).setRunnableWhenAddingSplashScreen(
+ organizer.setRunnableWhenAddingSplashScreen(
() -> {
// Surprise, ...! Transfer window in the middle of the creation flow.
activity2.addStartingWindow(mPackageName,
@@ -2357,6 +2366,7 @@
@Test
public void testTransferStartingWindowCanAnimate() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity1.addStartingWindow(mPackageName,
@@ -2380,6 +2390,7 @@
@Test
public void testTransferStartingWindowFromFinishingActivity() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
final Task task = activity.getTask();
activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* compatInfo */,
@@ -2423,6 +2434,7 @@
@Test
public void testTransferStartingWindowSetFixedRotation() {
+ registerTestStartingWindowOrganizer();
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
final Task task = activity.getTask();
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -2454,6 +2466,7 @@
@Test
public void testTryTransferStartingWindowFromHiddenAboveToken() {
+ registerTestStartingWindowOrganizer();
// Add two tasks on top of each other.
final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 8703c31..7f9e7da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -154,7 +154,7 @@
mWindow = createDropTargetWindow("Drag test window", 0);
doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
when(mWm.mInputManager.transferTouchFocus(any(InputChannel.class),
- any(InputChannel.class))).thenReturn(true);
+ any(InputChannel.class), any(boolean.class))).thenReturn(true);
mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
}
@@ -370,7 +370,7 @@
.build();
assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(),
- new InputChannel()));
+ new InputChannel(), true /* isDragDrop */));
mToken = mTarget.performDrag(0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 9830631..c483ae9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -141,7 +141,7 @@
assertNull(mProvider.getControlTarget());
// We can have the control and the control target after seamless rotation.
- mProvider.finishSeamlessRotation(false /* timeout */);
+ mProvider.finishSeamlessRotation();
mProvider.updateControlForTarget(target, false /* force */);
assertNotNull(mProvider.getControl(target));
assertNotNull(mProvider.getControlTarget());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index c6be987..7a4ad74 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -49,6 +52,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -511,6 +515,8 @@
final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
+ verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+ mDefaultDisplay.mDisplayId, false);
verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
final WindowContainer parent = navToken.getParent();
@@ -518,6 +524,8 @@
mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+ verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+ mDefaultDisplay.mDisplayId, true);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
verify(navBarFadeAnimationController).fadeWindowToken(true);
}
@@ -532,6 +540,8 @@
final WindowToken navToken = mDefaultDisplay.getDisplayPolicy().getNavigationBar().mToken;
final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
+ verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+ mDefaultDisplay.mDisplayId, false);
verify(transaction).reparent(navToken.getSurfaceControl(), activity.getSurfaceControl());
final WindowContainer parent = navToken.getParent();
@@ -539,6 +549,51 @@
mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+ verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+ mDefaultDisplay.mDisplayId, true);
+ verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
+ verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
+ }
+
+ @Test
+ public void testNotAttachNavigationBar_controlledByFixedRotationAnimation() {
+ setupForShouldAttachNavBarDuringTransition();
+ FixedRotationAnimationController mockController =
+ mock(FixedRotationAnimationController.class);
+ doReturn(mockController).when(mDefaultDisplay).getFixedRotationAnimationController();
+ final ActivityRecord homeActivity = createHomeActivity();
+ initializeRecentsAnimationController(mController, homeActivity);
+ assertFalse(mController.isNavigationBarAttachedToApp());
+ }
+
+ @Test
+ public void testAttachNavBarInSplitScreenMode() {
+ setupForShouldAttachNavBarDuringTransition();
+ final ActivityRecord primary = createActivityRecordWithParentTask(mDefaultDisplay,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord secondary = createActivityRecordWithParentTask(mDefaultDisplay,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD);
+ final ActivityRecord homeActivity = createHomeActivity();
+ homeActivity.setVisibility(true);
+ initializeRecentsAnimationController(mController, homeActivity);
+
+ WindowState navWindow = mController.getNavigationBarWindow();
+ final WindowToken navToken = navWindow.mToken;
+ final SurfaceControl.Transaction transaction = navToken.getPendingTransaction();
+
+ verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+ mDefaultDisplay.mDisplayId, false);
+ verify(navWindow).setSurfaceTranslationY(-secondary.getBounds().top);
+ verify(transaction).reparent(navToken.getSurfaceControl(), secondary.getSurfaceControl());
+ reset(navWindow);
+
+ mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
+ final WindowContainer parent = navToken.getParent();
+ final NavBarFadeAnimationController navBarFadeAnimationController =
+ mDefaultDisplay.getDisplayPolicy().getNavBarFadeAnimationController();
+ verify(mController.mStatusBar).setNavigationBarLumaSamplingEnabled(
+ mDefaultDisplay.mDisplayId, true);
+ verify(navWindow).setSurfaceTranslationY(0);
verify(transaction).reparent(navToken.getSurfaceControl(), parent.getSurfaceControl());
verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
}
@@ -600,9 +655,10 @@
private void setupForShouldAttachNavBarDuringTransition() {
mController.mShouldAttachNavBarToAppDuringTransition = true;
- final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
+ final WindowState navBar = spy(createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar"));
mDefaultDisplay.getDisplayPolicy().addWindowLw(navBar, navBar.mAttrs);
mWm.setRecentsAnimationController(mController);
+ doReturn(navBar).when(mController).getNavigationBarWindow();
final NavBarFadeAnimationController mockNavBarFadeAnimationController =
mock(NavBarFadeAnimationController.class);
final DisplayPolicy displayPolicy = spy(mDefaultDisplay.getDisplayPolicy());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 75226b7..8bc4ced 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -34,7 +34,6 @@
import android.platform.test.annotations.Presubmit;
import android.view.InputChannel;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -63,7 +62,8 @@
when(mWm.mInputManager.transferTouchFocus(
any(InputChannel.class),
- any(InputChannel.class))).thenReturn(true);
+ any(InputChannel.class),
+ any(boolean.class))).thenReturn(true);
mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
mWindow.getTask().setResizeMode(RESIZE_MODE_RESIZEABLE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 86d8eee..7822a85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -119,7 +119,7 @@
mRunnableWhenAddingSplashScreen.run();
mRunnableWhenAddingSplashScreen = null;
}
- return () -> {
+ return (a) -> {
synchronized (wm.mGlobalLock) {
activity.removeChild(window);
activity.mStartingWindow = null;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 2c2c09a..01c503e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -547,7 +547,8 @@
}
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@@ -614,7 +615,8 @@
}
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@Override
@@ -688,7 +690,8 @@
}
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@Override
@@ -832,7 +835,8 @@
@Override
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { }
@Override
- public void removeStartingWindow(int taskId) { }
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) { }
@Override
public void copySplashScreenView(int taskId) { }
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 51aec65..5b5b1da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -521,7 +521,7 @@
matrix.mapPoints(curSurfacePos);
verify(t).setPosition(eq(app.mSurfaceControl), eq(curSurfacePos[0]), eq(curSurfacePos[1]));
- app.finishSeamlessRotation(false /* timeout */);
+ app.finishSeamlessRotation(t);
assertFalse(app.mSeamlesslyRotated);
assertNull(app.mPendingSeamlessRotate);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 827ff6c..4a7784c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -36,6 +36,7 @@
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -50,6 +51,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -67,6 +69,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
@@ -74,6 +77,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.IDisplayWindowInsetsController;
@@ -100,6 +104,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.HashMap;
/** Common base class for window manager unit test classes. */
class WindowTestsBase extends SystemServiceTestsBase {
@@ -1123,6 +1128,88 @@
}
}
+ static class TestStartingWindowOrganizer extends ITaskOrganizer.Stub {
+ private final ActivityTaskManagerService mAtm;
+ private final WindowManagerService mWMService;
+ private final WindowState.PowerManagerWrapper mPowerManagerWrapper;
+
+ private Runnable mRunnableWhenAddingSplashScreen;
+ private final SparseArray<IBinder> mTaskAppMap = new SparseArray<>();
+ private final HashMap<IBinder, WindowState> mAppWindowMap = new HashMap<>();
+
+ TestStartingWindowOrganizer(ActivityTaskManagerService service,
+ WindowState.PowerManagerWrapper powerManagerWrapper) {
+ mAtm = service;
+ mWMService = mAtm.mWindowManager;
+ mPowerManagerWrapper = powerManagerWrapper;
+ if (DEBUG_ENABLE_SHELL_DRAWER) {
+ mAtm.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer(Runnable::run);
+ mAtm.mTaskOrganizerController.registerTaskOrganizer(this);
+ }
+ }
+
+ void setRunnableWhenAddingSplashScreen(Runnable r) {
+ if (DEBUG_ENABLE_SHELL_DRAWER) {
+ mRunnableWhenAddingSplashScreen = r;
+ } else {
+ ((TestWindowManagerPolicy) mWMService.mPolicy).setRunnableWhenAddingSplashScreen(r);
+ }
+ }
+
+ @Override
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
+ synchronized (mWMService.mGlobalLock) {
+ final ActivityRecord activity = mWMService.mRoot.getActivityRecord(
+ appToken);
+ IWindow iWindow = mock(IWindow.class);
+ doReturn(mock(IBinder.class)).when(iWindow).asBinder();
+ final WindowState window = WindowTestsBase.createWindow(null,
+ TYPE_APPLICATION_STARTING, activity,
+ "Starting window", 0 /* ownerId */, 0 /* userId*/,
+ false /* internalWindows */, mWMService, mock(Session.class),
+ iWindow,
+ mPowerManagerWrapper);
+ activity.mStartingWindow = window;
+ mAppWindowMap.put(appToken, window);
+ mTaskAppMap.put(info.taskInfo.taskId, appToken);
+ }
+ if (mRunnableWhenAddingSplashScreen != null) {
+ mRunnableWhenAddingSplashScreen.run();
+ mRunnableWhenAddingSplashScreen = null;
+ }
+ }
+ @Override
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
+ synchronized (mWMService.mGlobalLock) {
+ final IBinder appToken = mTaskAppMap.get(taskId);
+ if (appToken != null) {
+ mTaskAppMap.remove(taskId);
+ final ActivityRecord activity = mWMService.mRoot.getActivityRecord(
+ appToken);
+ WindowState win = mAppWindowMap.remove(appToken);
+ activity.removeChild(win);
+ activity.mStartingWindow = null;
+ }
+ }
+ }
+ @Override
+ public void copySplashScreenView(int taskId) {
+ }
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
+ }
+ @Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ }
+ }
+
static class TestSplitOrganizer extends ITaskOrganizer.Stub {
final ActivityTaskManagerService mService;
Task mPrimary;
@@ -1161,7 +1248,8 @@
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(int taskId) {
+ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
+ boolean playRevealAnimation) {
}
@Override
public void copySplashScreenView(int taskId) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index c82ba99..d967891 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -470,7 +470,7 @@
mWm, mockRunner, null, displayId);
spyOn(controller);
controller.mShouldAttachNavBarToAppDuringTransition = true;
- doReturn(mNavBarWindow.mToken).when(controller).getNavigationBarWindowToken();
+ doReturn(mNavBarWindow).when(controller).getNavigationBarWindow();
mWm.setRecentsAnimationController(controller);
// set ime visible
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index ed71d17..e089995a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -17,6 +17,7 @@
package com.android.server.voiceinteraction;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -25,8 +26,10 @@
import android.media.AudioAttributes;
import android.media.AudioRecord;
import android.media.MediaRecorder;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.os.SharedMemory;
import android.service.voice.AlwaysOnHotwordDetector;
import android.service.voice.HotwordDetectionService;
import android.service.voice.IDspHotwordDetectionCallback;
@@ -74,7 +77,8 @@
boolean mBound;
HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName,
- int userId, boolean bindInstantServiceAllowed) {
+ int userId, boolean bindInstantServiceAllowed, @Nullable Bundle options,
+ @Nullable SharedMemory sharedMemory) {
mLock = lock;
mContext = context;
mDetectionComponentName = serviceName;
@@ -90,6 +94,14 @@
boolean connected) {
synchronized (mLock) {
mBound = connected;
+ if (connected) {
+ try {
+ service.setConfig(options, sharedMemory);
+ } catch (RemoteException e) {
+ // TODO: (b/181842909) Report an error to voice interactor
+ Slog.w(TAG, "Failed to setConfig for HotwordDetectionService", e);
+ }
+ }
}
}
@@ -117,6 +129,11 @@
}
}
+ void setConfigLocked(Bundle options, SharedMemory sharedMemory) {
+ mRemoteHotwordDetectionService.run(
+ service -> service.setConfig(options, sharedMemory));
+ }
+
private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
IHotwordRecognitionStatusCallback externalCallback) {
if (DEBUG) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index dce63eb..2626bfd 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -60,6 +60,7 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.SharedMemory;
import android.os.ShellCallback;
import android.os.Trace;
import android.os.UserHandle;
@@ -982,23 +983,46 @@
}
@Override
- public int setHotwordDetectionConfig(Bundle options) {
+ public void setHotwordDetectionServiceConfig(@Nullable Bundle options,
+ @Nullable SharedMemory sharedMemory) {
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
if (mImpl == null) {
Slog.w(TAG,
- "setHotwordDetectionConfig without running voice interaction service");
- return VoiceInteractionService.HOTWORD_CONFIG_FAILURE;
+ "setHotwordDetectionServiceConfig without running voice"
+ + " interaction service");
+ return;
}
final long caller = Binder.clearCallingIdentity();
try {
- return mImpl.setHotwordDetectionConfigLocked(options);
+ mImpl.setHotwordDetectionServiceConfigLocked(options, sharedMemory);
} finally {
Binder.restoreCallingIdentity(caller);
}
}
}
+
+ @Override
+ public void shutdownHotwordDetectionService() {
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService();
+
+ if (mImpl == null) {
+ Slog.w(TAG,
+ "shutdownHotwordDetectionService without running voice"
+ + " interaction service");
+ return;
+ }
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.shutdownHotwordDetectionServiceLocked();
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
//----------------- Model management APIs --------------------------------//
@Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 04dea3f..5861610 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -43,11 +43,13 @@
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SharedMemory;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
+import android.system.OsConstants;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.view.IWindowManager;
@@ -389,25 +391,48 @@
return mInfo.getSupportsLocalInteraction();
}
- public int setHotwordDetectionConfigLocked(Bundle options) {
+ public void setHotwordDetectionServiceConfigLocked(@Nullable Bundle options,
+ @Nullable SharedMemory sharedMemory) {
if (DEBUG) {
- Slog.d(TAG, "setHotwordDetectionConfigLocked");
+ Slog.d(TAG, "setHotwordDetectionServiceConfigLocked");
}
if (mHotwordDetectionComponentName == null) {
- Slog.e(TAG, "Calling setHotwordDetectionConfigLocked, but hotword detection service"
- + " name not found");
- return VoiceInteractionService.HOTWORD_CONFIG_FAILURE;
+ Slog.w(TAG, "Hotword detection service name not found");
+ throw new IllegalStateException("Hotword detection service name not found");
}
if (!isIsolatedProcessLocked(mHotwordDetectionComponentName)) {
- return VoiceInteractionService.HOTWORD_CONFIG_FAILURE;
+ Slog.w(TAG, "Hotword detection service not in isolated process");
+ throw new IllegalStateException("Hotword detection service not in isolated process");
}
// TODO : Need to check related permissions for hotword detection service
// TODO : Sanitize for bundle
- mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
- mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false);
+ if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
+ Slog.w(TAG, "Can't set sharedMemory to be read-only");
+ throw new IllegalStateException("Can't set sharedMemory to be read-only");
+ }
- return VoiceInteractionService.HOTWORD_CONFIG_SUCCESS;
+ if (mHotwordDetectionConnection == null) {
+ mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
+ mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false,
+ options, sharedMemory);
+ } else {
+ mHotwordDetectionConnection.setConfigLocked(options, sharedMemory);
+ }
+ }
+
+ public void shutdownHotwordDetectionServiceLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "shutdownHotwordDetectionServiceLocked");
+ }
+
+ if (mHotwordDetectionConnection == null) {
+ Slog.w(TAG, "shutdown, but no hotword detection connection");
+ return;
+ }
+
+ mHotwordDetectionConnection.cancelLocked();
+ mHotwordDetectionConnection = null;
}
public IRecognitionStatusCallback createSoundTriggerCallbackLocked(
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index dc2fb94..f84dd7b 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -338,7 +338,7 @@
*
* @param videoState The video state in which to answer the connection.
*/
- public void onAnswer(int videoState) {}
+ public void onAnswer(@VideoProfile.VideoState int videoState) {}
/**
* Notifies this Conference, which is in {@code STATE_RINGING}, of
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 97a06a8..d8bd6a5 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2594,9 +2594,9 @@
* @return The {@code Connection} object to satisfy this call, or {@code null} to
* not handle the call.
*/
- public final RemoteConnection createRemoteIncomingConnection(
- PhoneAccountHandle connectionManagerPhoneAccount,
- ConnectionRequest request) {
+ public final @Nullable RemoteConnection createRemoteIncomingConnection(
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return mRemoteConnectionManager.createRemoteConnection(
connectionManagerPhoneAccount, request, true);
}
@@ -2613,9 +2613,9 @@
* @return The {@code Connection} object to satisfy this call, or {@code null} to
* not handle the call.
*/
- public final RemoteConnection createRemoteOutgoingConnection(
- PhoneAccountHandle connectionManagerPhoneAccount,
- ConnectionRequest request) {
+ public final @Nullable RemoteConnection createRemoteOutgoingConnection(
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return mRemoteConnectionManager.createRemoteConnection(
connectionManagerPhoneAccount, request, false);
}
@@ -2855,12 +2855,14 @@
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request Details about the incoming conference call.
- * @return The {@code Conference} object to satisfy this call, or {@code null} to
- * not handle the call.
+ * @return The {@code Conference} object to satisfy this call. If the conference attempt is
+ * failed, the return value will be a result of an invocation of
+ * {@link Connection#createFailedConnection(DisconnectCause)}.
+ * Return {@code null} if the {@link ConnectionService} cannot handle the call.
*/
public @Nullable Conference onCreateIncomingConference(
- @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
- @Nullable ConnectionRequest request) {
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return null;
}
@@ -2963,8 +2965,8 @@
* @param request The outgoing connection request.
*/
public void onCreateOutgoingConferenceFailed(
- @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
- @Nullable ConnectionRequest request) {
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
}
@@ -3028,12 +3030,14 @@
* a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
* making the connection.
* @param request Details about the outgoing call.
- * @return The {@code Conference} object to satisfy this call, or the result of an invocation
- * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
+ * @return The {@code Conference} object to satisfy this call. If the conference attempt is
+ * failed, the return value will be a result of an invocation of
+ * {@link Connection#createFailedConnection(DisconnectCause)}.
+ * Return {@code null} if the {@link ConnectionService} cannot handle the call.
*/
public @Nullable Conference onCreateOutgoingConference(
- @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
- @Nullable ConnectionRequest request) {
+ @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull ConnectionRequest request) {
return null;
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 17749e8..1677c8c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -314,8 +314,8 @@
public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
/**
- * A URI representing the picture that was downloaded when a call is received or uploaded
- * when a call is placed.
+ * A {@link Uri} representing the picture that was downloaded when a call is received or
+ * uploaded when a call is placed.
*
* This is a content URI within the call log provider which can be used to open a file
* descriptor. This could be set a short time after a call is added to the Dialer app if the
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 705e93f..1a71f80 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -27,6 +27,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.net.ipsec.ike.SaProposal;
import android.os.Build;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -4170,9 +4171,11 @@
KEY_PREFIX + "child_sa_rekey_soft_timer_sec_int";
/**
- * Supported DH groups for IKE negotiation. Possible values are {@link #DH_GROUP_NONE},
- * {@link #DH_GROUP_1024_BIT_MODP}, {@link #DH_GROUP_1536_BIT_MODP}, {@link
- * #DH_GROUP_2048_BIT_MODP}
+ * Supported DH groups for IKE negotiation. Possible values are:
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_NONE},
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1024_BIT_MODP},
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_1536_BIT_MODP},
+ * {@link android.net.ipsec.ike.SaProposal#DH_GROUP_2048_BIT_MODP}
*/
public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY =
KEY_PREFIX + "diffie_hellman_groups_int_array";
@@ -4208,23 +4211,29 @@
/**
* List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of child
- * session. Possible values are {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link
- * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * session. Possible values are:
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "child_session_aes_cbc_key_size_int_array";
/**
* List of supported key sizes for AES Counter (CTR) encryption mode of child session.
- * Possible values are {@link #KEY_LEN_UNUSED},
- * {@link #KEY_LEN_AES_128}, {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * Possible values are:
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "child_session_aes_ctr_key_size_int_array";
/**
* List of supported encryption algorithms for child session. Possible values are
- * {@link #ENCRYPTION_ALGORITHM_AES_CBC}
+ * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC}
*/
public static final String KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_child_session_encryption_algorithms_int_array";
@@ -4245,8 +4254,11 @@
/**
* List of supported key sizes for AES Cipher Block Chaining (CBC) encryption mode of IKE
- * session. Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128}, {@link
- * #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * session. Possible values:
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "ike_session_encryption_aes_cbc_key_size_int_array";
@@ -4254,24 +4266,31 @@
/**
* List of supported key sizes for AES Counter (CTR) encryption mode of IKE session.
- * Possible values - {@link #KEY_LEN_UNUSED}, {@link #KEY_LEN_AES_128},
- * {@link #KEY_LEN_AES_192}, {@link #KEY_LEN_AES_256}
+ * Possible values -
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_UNUSED},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_128},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_192},
+ * {@link android.net.ipsec.ike.SaProposal#KEY_LEN_AES_256}
*/
public static final String KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY =
KEY_PREFIX + "ike_session_encryption_aes_ctr_key_size_int_array";
/**
* List of supported encryption algorithms for IKE session. Possible values are
- * {@link #ENCRYPTION_ALGORITHM_AES_CBC}, {@link #ENCRYPTION_ALGORITHM_AES_CTR}
+ * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CBC},
+ * {@link android.net.ipsec.ike.SaProposal#ENCRYPTION_ALGORITHM_AES_CTR}
*/
public static final String KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_ike_session_encryption_algorithms_int_array";
/**
- * List of supported integrity algorithms for IKE session Possible values are {@link
- * #INTEGRITY_ALGORITHM_NONE}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA1_96}, {@link
- * #INTEGRITY_ALGORITHM_AES_XCBC_96}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_256_128}, {@link
- * #INTEGRITY_ALGORITHM_HMAC_SHA2_384_192}, {@link #INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
+ * List of supported integrity algorithms for IKE session. Possible values are
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_NONE},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA1_96},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_AES_XCBC_96},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_256_128},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_384_192},
+ * {@link android.net.ipsec.ike.SaProposal#INTEGRITY_ALGORITHM_HMAC_SHA2_512_256}
*/
public static final String KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_integrity_algorithms_int_array";
@@ -4291,9 +4310,11 @@
/**
* List of supported pseudo random function algorithms for IKE session. Possible values are
- * {@link #PSEUDORANDOM_FUNCTION_HMAC_SHA1}, {@link #PSEUDORANDOM_FUNCTION_AES128_XCBC},
- * {@link #PSEUDORANDOM_FUNCTION_SHA2_256}, {@link #PSEUDORANDOM_FUNCTION_SHA2_384},
- * {@link #PSEUDORANDOM_FUNCTION_SHA2_512}
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_HMAC_SHA1},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_AES128_XCBC},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_256},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_384},
+ * {@link android.net.ipsec.ike.SaProposal#PSEUDORANDOM_FUNCTION_SHA2_512}
*/
public static final String KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY =
KEY_PREFIX + "supported_prf_algorithms_int_array";
@@ -4366,182 +4387,6 @@
public static final int EPDG_ADDRESS_CELLULAR_LOC = 3;
/** @hide */
- @IntDef({KEY_LEN_UNUSED, KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256})
- public @interface EncrpytionKeyLengthType {}
-
- public static final int KEY_LEN_UNUSED = 0;
- /** AES Encryption/Ciphering Algorithm key length 128 bits. */
- public static final int KEY_LEN_AES_128 = 128;
- /** AES Encryption/Ciphering Algorithm key length 192 bits. */
- public static final int KEY_LEN_AES_192 = 192;
- /** AES Encryption/Ciphering Algorithm key length 256 bits. */
- public static final int KEY_LEN_AES_256 = 256;
-
- /** @hide */
- @IntDef({
- DH_GROUP_NONE,
- DH_GROUP_1024_BIT_MODP,
- DH_GROUP_1536_BIT_MODP,
- DH_GROUP_2048_BIT_MODP,
- DH_GROUP_3072_BIT_MODP,
- DH_GROUP_4096_BIT_MODP
- })
- public @interface DhGroup {}
-
- /** None Diffie-Hellman Group. */
- public static final int DH_GROUP_NONE = 0;
- /**
- * 1024-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_1024_BIT_MODP = 2;
- /**
- * 1536-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_1536_BIT_MODP = 5;
- /**
- * 2048-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_2048_BIT_MODP = 14;
- /**
- * 3072-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_3072_BIT_MODP = 15;
- /**
- * 4096-bit MODP Diffie-Hellman Group.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int DH_GROUP_4096_BIT_MODP = 16;
-
- /** @hide */
- @IntDef({ENCRYPTION_ALGORITHM_AES_CBC, ENCRYPTION_ALGORITHM_AES_CTR})
- public @interface EncryptionAlgorithm {}
-
- /**
- * AES-CBC Encryption/Ciphering Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12;
-
- /**
- * AES-CTR Encryption/Ciphering Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int ENCRYPTION_ALGORITHM_AES_CTR = 13;
-
- /** @hide */
- @IntDef({
- INTEGRITY_ALGORITHM_NONE,
- INTEGRITY_ALGORITHM_HMAC_SHA1_96,
- INTEGRITY_ALGORITHM_AES_XCBC_96,
- INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
- INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
- INTEGRITY_ALGORITHM_HMAC_SHA2_512_256
- })
- public @interface IntegrityAlgorithm {}
-
- /** None Authentication/Integrity Algorithm. */
- public static final int INTEGRITY_ALGORITHM_NONE = 0;
- /**
- * HMAC-SHA1 Authentication/Integrity Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2;
- /**
- * AES-XCBC-96 Authentication/Integrity Algorithm.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5;
- /**
- * HMAC-SHA256 Authentication/Integrity Algorithm with 128-bit truncation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12;
- /**
- * HMAC-SHA384 Authentication/Integrity Algorithm with 192-bit truncation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13;
- /**
- * HMAC-SHA512 Authentication/Integrity Algorithm with 256-bit truncation.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14;
-
- /** @hide */
- @IntDef({
- PSEUDORANDOM_FUNCTION_HMAC_SHA1,
- PSEUDORANDOM_FUNCTION_AES128_XCBC,
- PSEUDORANDOM_FUNCTION_SHA2_256,
- PSEUDORANDOM_FUNCTION_SHA2_384,
- PSEUDORANDOM_FUNCTION_SHA2_512
- })
- public @interface PseudorandomFunction {}
-
- /**
- * HMAC-SHA1 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2;
- /**
- * AES128-XCBC Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4;
- /**
- * HMAC-SHA2-256 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_SHA2_256 = 5;
- /**
- * HMAC-SHA2-384 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_SHA2_384 = 6;
- /**
- * HMAC-SHA2-384 Pseudorandom Function.
- *
- * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key
- * Exchange Protocol Version 2 (IKEv2)</a>
- */
- public static final int PSEUDORANDOM_FUNCTION_SHA2_512 = 7;
-
- /** @hide */
@IntDef({ID_TYPE_FQDN, ID_TYPE_RFC822_ADDR, ID_TYPE_KEY_ID})
public @interface IkeIdType {}
@@ -4582,31 +4427,33 @@
defaults.putIntArray(
KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY,
new int[] {
- DH_GROUP_1024_BIT_MODP, DH_GROUP_1536_BIT_MODP, DH_GROUP_2048_BIT_MODP
+ SaProposal.DH_GROUP_1024_BIT_MODP,
+ SaProposal.DH_GROUP_1536_BIT_MODP,
+ SaProposal.DH_GROUP_2048_BIT_MODP
});
defaults.putIntArray(
KEY_SUPPORTED_IKE_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
- new int[] {ENCRYPTION_ALGORITHM_AES_CBC});
+ new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC});
defaults.putIntArray(
KEY_SUPPORTED_CHILD_SESSION_ENCRYPTION_ALGORITHMS_INT_ARRAY,
- new int[] {ENCRYPTION_ALGORITHM_AES_CBC});
+ new int[] {SaProposal.ENCRYPTION_ALGORITHM_AES_CBC});
defaults.putIntArray(
KEY_SUPPORTED_INTEGRITY_ALGORITHMS_INT_ARRAY,
new int[] {
- INTEGRITY_ALGORITHM_AES_XCBC_96,
- INTEGRITY_ALGORITHM_HMAC_SHA1_96,
- INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
- INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
- INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
+ SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192,
+ SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_512_256,
});
defaults.putIntArray(
KEY_SUPPORTED_PRF_ALGORITHMS_INT_ARRAY,
new int[] {
- PSEUDORANDOM_FUNCTION_HMAC_SHA1,
- PSEUDORANDOM_FUNCTION_AES128_XCBC,
- PSEUDORANDOM_FUNCTION_SHA2_256,
- PSEUDORANDOM_FUNCTION_SHA2_384,
- PSEUDORANDOM_FUNCTION_SHA2_512
+ SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1,
+ SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC,
+ SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256,
+ SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384,
+ SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512
});
defaults.putInt(KEY_EPDG_AUTHENTICATION_METHOD_INT, AUTHENTICATION_METHOD_EAP_ONLY);
@@ -4616,16 +4463,28 @@
defaults.putInt(KEY_NATT_KEEP_ALIVE_TIMER_SEC_INT, 20);
defaults.putIntArray(
KEY_IKE_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_CHILD_SESSION_AES_CBC_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_IKE_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY,
- new int[] {KEY_LEN_AES_128, KEY_LEN_AES_192, KEY_LEN_AES_256});
+ new int[] {
+ SaProposal.KEY_LEN_AES_128,
+ SaProposal.KEY_LEN_AES_192,
+ SaProposal.KEY_LEN_AES_256});
defaults.putIntArray(
KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY,
new int[] {EPDG_ADDRESS_PLMN, EPDG_ADDRESS_STATIC});
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2d5f5fb..f7580d7 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -602,6 +602,43 @@
public @interface SimDisplayNameSource {}
/**
+ * Device status is not shared to a remote party.
+ */
+ public static final int D2D_SHARING_DISABLED = 0;
+
+ /**
+ * Device status is shared with all numbers in the user's contacts.
+ */
+ public static final int D2D_SHARING_ALL_CONTACTS = 1;
+
+ /**
+ * Device status is shared with all starred contacts.
+ */
+ public static final int D2D_SHARING_STARRED_CONTACTS = 2;
+
+ /**
+ * Device status is shared whenever possible.
+ */
+ public static final int D2D_SHARING_ALL = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"D2D_SHARING_"},
+ value = {
+ D2D_SHARING_DISABLED,
+ D2D_SHARING_ALL_CONTACTS,
+ D2D_SHARING_STARRED_CONTACTS,
+ D2D_SHARING_ALL
+ })
+ public @interface DeviceToDeviceStatusSharing {}
+
+ /**
+ * TelephonyProvider column name for device to device sharing status.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String D2D_STATUS_SHARING = SimInfo.COLUMN_D2D_STATUS_SHARING;
+
+ /**
* TelephonyProvider column name for the color of a SIM.
* <P>Type: INTEGER (int)</P>
*/
@@ -3374,6 +3411,36 @@
}
/**
+ * Set the device to device status sharing user preference for a subscription ID. The setting
+ * app uses this method to indicate with whom they wish to share device to device status
+ * information.
+ * @param sharing the status sharing preference
+ * @param subId the unique Subscription ID in database
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setDeviceToDeviceStatusSharing(@DeviceToDeviceStatusSharing int sharing,
+ int subId) {
+ if (VDBG) {
+ logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: " + subId);
+ }
+ setSubscriptionPropertyHelper(subId, "setDeviceToDeviceSharingStatus",
+ (iSub)->iSub.setDeviceToDeviceStatusSharing(sharing, subId));
+ }
+
+ /**
+ * Returns the user-chosen device to device status sharing preference
+ * @param subId Subscription id of subscription
+ * @return The device to device status sharing preference
+ */
+ public @DeviceToDeviceStatusSharing int getDeviceToDeviceStatusSharing(int subId) {
+ if (VDBG) {
+ logd("[getDeviceToDeviceStatusSharing] + subId: " + subId);
+ }
+ return getIntegerSubscriptionProperty(subId, D2D_STATUS_SHARING, D2D_SHARING_DISABLED,
+ mContext);
+ }
+
+ /**
* DO NOT USE.
* This API is designed for features that are not finished at this point. Do not call this API.
* @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3cb72b5..4dc6c7c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -139,6 +139,8 @@
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Provides access to information about the telephony services on
@@ -3147,6 +3149,10 @@
return NETWORK_TYPE_BITMASK_LTE_CA;
case NETWORK_TYPE_NR:
return NETWORK_TYPE_BITMASK_NR;
+ case NETWORK_TYPE_IWLAN:
+ return NETWORK_TYPE_BITMASK_IWLAN;
+ case NETWORK_TYPE_IDEN:
+ return (1 << (NETWORK_TYPE_IDEN - 1));
default:
return NETWORK_TYPE_BITMASK_UNKNOWN;
}
@@ -8642,8 +8648,8 @@
public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3;
/**
- * Set the allowed network types of the device and
- * provide the reason triggering the allowed network change.
+ * Set the allowed network types of the device and provide the reason triggering the allowed
+ * network change.
* This can be called for following reasons
* <ol>
* <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER}
@@ -8655,10 +8661,15 @@
* </ol>
* This API will result in allowing an intersection of allowed network types for all reasons,
* including the configuration done through other reasons.
+ *
+ * The functionality of this API with the parameter
+ * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API
+ * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of
+ * {@link TelephonyManager#setAllowedNetworkTypes}.
* <p>
* If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
* ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then
- * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
+ * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
* setPreferredNetworkTypesBitmap is used instead.
*
* @param reason the reason the allowed network type change is taking place
@@ -8698,21 +8709,17 @@
* {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
* specific reason.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
- * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
- *
* @param reason the reason the allowed network type change is taking place
* @return the allowed network type bitmask
* @throws IllegalStateException if the Telephony process is not currently available.
* @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
* @hide
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@RequiresFeature(
enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED)
+ @SystemApi
public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
@AllowedNetworkTypesReason int reason) {
if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -8757,6 +8764,25 @@
}
/**
+ * Returns a string representation of the allowed network types{@link NetworkTypeBitMask}.
+ *
+ * @param networkTypeBitmask The bitmask of allowed network types.
+ * @return the name of the allowed network types
+ * @hide
+ */
+ public static String convertNetworkTypeBitmaskToString(
+ @NetworkTypeBitMask long networkTypeBitmask) {
+ String networkTypeName = IntStream.rangeClosed(NETWORK_TYPE_GPRS, NETWORK_TYPE_NR)
+ .filter(x -> {
+ return (networkTypeBitmask & getBitMaskForNetworkType(x))
+ == getBitMaskForNetworkType(x);
+ })
+ .mapToObj(x -> getNetworkTypeName(x))
+ .collect(Collectors.joining("|"));
+ return TextUtils.isEmpty(networkTypeName) ? "UNKNOWN" : networkTypeName;
+ }
+
+ /**
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
* <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
@@ -9135,9 +9161,7 @@
/**
* Set the user-set status for enriched calling with call composer.
*
- * @param status user-set status for enriched calling with call composer;
- * it must be either {@link #CALL_COMPOSER_STATUS_ON} or
- * {@link #CALL_COMPOSER_STATUS_OFF}.
+ * @param status user-set status for enriched calling with call composer.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -12579,6 +12603,7 @@
NETWORK_TYPE_BITMASK_LTE,
NETWORK_TYPE_BITMASK_LTE_CA,
NETWORK_TYPE_BITMASK_NR,
+ NETWORK_TYPE_BITMASK_IWLAN
})
public @interface NetworkTypeBitMask {}
@@ -15218,13 +15243,17 @@
* </ul>
* @param appType icc application type, like {@link #APPTYPE_USIM} or {@link
* #APPTYPE_ISIM} or {@link#APPTYPE_UNKNOWN}
- * @param nafId Network Application Function(NAF) fully qualified domain name and
- * the selected GBA mode. It shall contain two parts delimited by "@" sign. The first
- * part is the constant string "3GPP-bootstrapping" (GBA_ME),
- * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest),
- * and the latter part shall be the FQDN of the NAF (e.g.
- * "3GPP-bootstrapping@naf1.operator.com" or "3GPP-bootstrapping-uicc@naf1.operator.com",
- * or "3GPP-bootstrapping-digest@naf1.operator.com").
+ * @param nafId A URI to specify Network Application Function(NAF) fully qualified domain
+ * name (FQDN) and the selected GBA mode. The authority of the URI must contain two parts
+ * delimited by "@" sign. The first part is the constant string "3GPP-bootstrapping" (GBA_ME),
+ * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest).
+ * The second part shall be the FQDN of the NAF. The scheme of the URI is not actually used
+ * for the authentication, which may be set the same as the resource that the application is
+ * going to access. For example, the nafId can be
+ * "https://3GPP-bootstrapping@naf1.operator.com",
+ * "https://3GPP-bootstrapping-uicc@naf1.operator.com",
+ * "https://3GPP-bootstrapping-digest@naf1.operator.com",
+ * "ftps://3GPP-bootstrapping-digest@naf1.operator.com".
* @param securityProtocol Security protocol identifier between UE and NAF. See
* 3GPP TS 33.220 Annex H. Application can use
* {@link UaSecurityProtocolIdentifier#createDefaultUaSpId},
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index a764229..ffe5399 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -18,6 +18,7 @@
package android.telephony.data;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -29,6 +30,7 @@
import android.telephony.data.ApnSetting.ProtocolType;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -812,11 +814,19 @@
/**
* Set pdu session id.
+ * <p/>
+ * The id must be between 1 and 15 when linked to a pdu session. If no pdu session
+ * exists for the current data call, the id must be set to {@link PDU_SESSION_ID_NOT_SET}.
*
* @param pduSessionId Pdu Session Id of the data call.
* @return The same instance of the builder.
*/
- public @NonNull Builder setPduSessionId(int pduSessionId) {
+ public @NonNull Builder setPduSessionId(
+ @IntRange(from = PDU_SESSION_ID_NOT_SET, to = 15) int pduSessionId) {
+ Preconditions.checkArgument(pduSessionId >= PDU_SESSION_ID_NOT_SET,
+ "pduSessionId must be greater than or equal to" + PDU_SESSION_ID_NOT_SET);
+ Preconditions.checkArgument(pduSessionId <= 15,
+ "pduSessionId must be less than or equal to 15.");
mPduSessionId = pduSessionId;
return this;
}
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index f5f29c6..048b329 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -41,6 +41,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Base class of data service. Services that extend DataService must register the service in
@@ -284,11 +285,11 @@
*
* Any resources being transferred cannot be released while a
* handover is underway.
- *
+ * <p/>
* If a handover was unsuccessful, then the framework calls
* {@link DataService#cancelHandover}. The target transport retains ownership over any of
* the resources being transferred.
- *
+ * <p/>
* If a handover was successful, the framework calls {@link DataService#deactivateDataCall}
* with reason {@link DataService.REQUEST_REASON_HANDOVER}. The target transport now owns
* the transferred resources and is responsible for releasing them.
@@ -299,21 +300,27 @@
* @hide
*/
public void startHandover(int cid, @NonNull DataServiceCallback callback) {
+ Objects.requireNonNull(callback, "callback cannot be null");
// The default implementation is to return unsupported.
- if (callback != null) {
- Log.d(TAG, "startHandover: " + cid);
- callback.onHandoverStarted(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
- } else {
- Log.e(TAG, "startHandover: " + cid + ", callback is null");
- }
+ Log.d(TAG, "startHandover: " + cid);
+ callback.onHandoverStarted(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
}
/**
* Indicates that a handover was cancelled after a call to
* {@link DataService#startHandover}. This is called on the source transport.
- *
+ * <p/>
* Since the handover was unsuccessful, the source transport retains ownership over any of
* the resources being transferred and is still responsible for releasing them.
+ * <p/>
+ * The handover can be cancelled up until either:
+ * <ul><li>
+ * The handover was successful after receiving a successful response from
+ * {@link DataService#setupDataCall} on the target transport.
+ * </li><li>
+ * The data call on the source transport was lost.
+ * </li>
+ * </ul>
*
* @param cid The identifier of the data call which is provided in {@link DataCallResponse}
* @param callback The result callback for this request.
@@ -321,13 +328,10 @@
* @hide
*/
public void cancelHandover(int cid, @NonNull DataServiceCallback callback) {
+ Objects.requireNonNull(callback, "callback cannot be null");
// The default implementation is to return unsupported.
- if (callback != null) {
- Log.d(TAG, "cancelHandover: " + cid);
- callback.onHandoverCancelled(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
- } else {
- Log.e(TAG, "cancelHandover: " + cid + ", callback is null");
- }
+ Log.d(TAG, "cancelHandover: " + cid);
+ callback.onHandoverCancelled(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
}
/**
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
index 041edc0..406c38b 100644
--- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -184,16 +184,6 @@
mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
}
- /**
- * Creates attributes based off of a parcel
- * @param in the parcel
- * @return the attributes
- */
- @NonNull
- public static EpsBearerQosSessionAttributes create(@NonNull final Parcel in) {
- return new EpsBearerQosSessionAttributes(in);
- }
-
@Override
public int describeContents() {
return 0;
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 9bb4db8..486f746 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -277,6 +277,10 @@
* server infrastructure to get the picture. It can be set via
* {@link #setCallExtra(String, String)}.
*
+ * Note that this URL is not intended to be parsed by the IMS stack -- it should be sent
+ * directly to the network for consumption by the called party or forwarded directly from the
+ * network to the platform for caching and download.
+ *
* Reference: RCC.20 Section 2.4.3.2
*/
public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
@@ -729,6 +733,10 @@
/**
* Set the call extra value (Parcelable), given the call extra name.
+ *
+ * Note that the {@link Parcelable} provided must be a class defined in the Android API surface,
+ * as opposed to a class defined by your app.
+ *
* @param name call extra name
* @param parcelable call extra value
*/
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 85cd81b..abc5606 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -1010,6 +1010,16 @@
}
}
+ @Override
+ public void onPreProvisioningReceived(byte[] configXml) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mLocalCallback.onPreProvisioningReceived(configXml));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private void setExecutor(Executor executor) {
mExecutor = executor;
}
@@ -1022,7 +1032,7 @@
* due to various triggers defined in GSMA RCC.14 for ACS(auto configuration
* server) or other operator defined triggers. If RCS provisioning is already
* completed at the time of callback registration, then this method shall be
- * invoked with the current configuration
+ * invoked with the current configuration.
* @param configXml The RCS configuration XML received by OTA. It is defined
* by GSMA RCC.07.
*/
@@ -1055,6 +1065,20 @@
*/
public void onRemoved() {}
+ /**
+ * Some carriers using ACS (auto configuration server) may send a carrier-specific
+ * pre-provisioning configuration XML if the user has not been provisioned for RCS
+ * services yet. When this provisioning XML is received, the framework will move
+ * into a "not provisioned" state for RCS. In order for provisioning to proceed,
+ * the application must parse this configuration XML and perform the carrier specific
+ * opt-in flow for RCS services. If the user accepts, {@link #triggerRcsReconfiguration}
+ * must be called in order for the device to move out of this state and try to fetch
+ * the RCS provisioning information.
+ *
+ * @param configXml the pre-provisioning config in carrier specified format.
+ */
+ public void onPreProvisioningReceived(@NonNull byte[] configXml) {}
+
/**@hide*/
public final IRcsConfigCallback getBinder() {
return mBinder;
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
index 5a8973e..d0853d1 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcsConfigCallback.aidl
@@ -25,5 +25,6 @@
void onAutoConfigurationErrorReceived(int errorCode, String errorString);
void onConfigurationReset();
void onRemoved();
+ void onPreProvisioningReceived(in byte[] config);
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 21aeb64..d75da90 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -552,11 +552,34 @@
}
mRcsCallbacks.broadcastAction(c -> {
try {
- //TODO compressed by default?
c.onAutoConfigurationErrorReceived(errorCode, errorString);
} catch (RemoteException e) {
Log.w(TAG, "dead binder in notifyAutoConfigurationErrorReceived, skipping.");
}
});
}
+
+ /**
+ * Notifies application that pre-provisioning config is received.
+ *
+ * <p>Some carriers using ACS (auto configuration server) may send a carrier-specific
+ * pre-provisioning configuration XML if the user has not been provisioned for RCS
+ * services yet. When such provisioning XML is received, ACS client must call this
+ * method to notify the application with the XML.
+ *
+ * @param configXml the pre-provisioning config in carrier specified format.
+ */
+ public final void notifyPreProvisioningReceived(@NonNull byte[] configXml) {
+ // can be null in testing
+ if (mRcsCallbacks == null) {
+ return;
+ }
+ mRcsCallbacks.broadcastAction(c -> {
+ try {
+ c.onPreProvisioningReceived(configXml);
+ } catch (RemoteException e) {
+ Log.w(TAG, "dead binder in notifyPreProvisioningReceived, skipping.");
+ }
+ });
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 571efce..9493c76 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -300,4 +300,6 @@
boolean canDisablePhysicalSubscription();
int setUiccApplicationsEnabled(boolean enabled, int subscriptionId);
+
+ int setDeviceToDeviceStatusSharing(int sharing, int subId);
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index b2719fb..896ec9a 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -11,6 +11,8 @@
<option name="force-skip-system-props" value="true" />
<!-- set WM tracing verbose level to all -->
<option name="run-command" value="cmd window tracing level all" />
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame" />
<!-- restart launcher to activate TAPL -->
<option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
</target_preparer>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index fbf18d4..c92d40c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,37 +16,12 @@
package com.android.server.wm.flicker.close
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
-import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
-import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
-import org.junit.Assume
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -59,110 +34,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppBackButtonTest(private val testSpec: FlickerTestParameter) {
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = SimpleAppHelper(instrumentation)
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- this.setRotation(testSpec.config.startRotation)
- testApp.launchViaIntent(wmHelper)
- }
- }
+class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
transitions {
device.pressBack()
wmHelper.waitForHomeActivityVisible()
}
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
}
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun launcherReplacesAppWindowAsTopWindow() =
- testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
-
- @Presubmit
- @Test
- fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible()
-
- @Presubmit
- @Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
- Surface.ROTATION_0)
-
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun navBarLayerRotatesAndScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun statusBarLayerRotatesScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun statusBarLayerRotatesScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest(bugId = 173684672)
- @Test
- fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest(bugId = 173684672)
- @Test
- fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 08d2b7c..1f880f6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,37 +16,12 @@
package com.android.server.wm.flicker.close
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
-import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
-import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.repetitions
-import com.android.server.wm.flicker.startRotation
-import org.junit.Assume
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -59,110 +34,15 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppHomeButtonTest(private val testSpec: FlickerTestParameter) {
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = SimpleAppHelper(instrumentation)
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
- eachRun {
- testApp.launchViaIntent(wmHelper)
- this.setRotation(testSpec.config.startRotation)
- }
- }
+class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
transitions {
device.pressHome()
wmHelper.waitForHomeActivityVisible()
}
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
}
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun launcherReplacesAppWindowAsTopWindow() =
- testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
-
- @Presubmit
- @Test
- fun wallpaperWindowBecomesVisible() = testSpec.wallpaperWindowBecomesVisible()
-
- @Presubmit
- @Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(
- testSpec.config.startRotation, Surface.ROTATION_0)
-
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun wallpaperLayerReplacesAppLayer() = testSpec.wallpaperLayerReplacesAppLayer(testApp)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun navBarLayerRotatesAndScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun statusBarLayerRotatesScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun statusBarLayerRotatesScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest(bugId = 173689015)
- @Test
- fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest(bugId = 173689015)
- @Test
- fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
new file mode 100644
index 0000000..fef49d9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.close
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
+import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
+import org.junit.Assume
+import org.junit.Test
+
+abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest
+ @Test
+ open fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @FlakyTest(bugId = 173689015)
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+
+ @FlakyTest(bugId = 173689015)
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ @Presubmit
+ @Test
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+ }
+
+ @Presubmit
+ @Test
+ open fun launcherReplacesAppWindowAsTopWindow() {
+ testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
+ }
+
+ @Presubmit
+ @Test
+ open fun wallpaperWindowBecomesVisible() {
+ testSpec.wallpaperWindowBecomesVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun wallpaperLayerReplacesAppLayer() {
+ testSpec.wallpaperLayerReplacesAppLayer(testApp)
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 47eaddf..17aa1d1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -89,40 +88,40 @@
}
}
- @Postsubmit
+ @Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
- @Postsubmit
+ @Presubmit
@Test
fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
- @Postsubmit
+ @Presubmit
@Test
fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
- @Postsubmit
+ @Presubmit
@Test
fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
- @Postsubmit
+ @Presubmit
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
- @Postsubmit
+ @Presubmit
@Test
fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 74f002d..56ed21b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,37 +16,14 @@
package com.android.server.wm.flicker.launch
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import org.junit.Assume
import org.junit.FixMethodOrder
-import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -59,114 +36,25 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppColdTest(private val testSpec: FlickerTestParameter) {
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = SimpleAppHelper(instrumentation)
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
+class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- }
eachRun {
this.setRotation(testSpec.config.startRotation)
}
}
- transitions {
- testApp.launchViaIntent(wmHelper)
- // wmHelper.waitForFullScreenApp(testApp.component)
- }
teardown {
eachRun {
- testApp.exit()
- wmHelper.waitForAppTransitionIdle()
- this.setRotation(Surface.ROTATION_0)
+ testApp.exit(wmHelper)
}
}
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
}
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- fun appWindowReplacesLauncherAsTopWindow() =
- testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
-
- @Presubmit
- @Test
- fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
-
- @Presubmit
- @Test
- // During testing the launcher is always in portrait mode
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
- Surface.ROTATION_0)
-
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun appLayerReplacesWallpaperLayer() =
- testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun navBarLayerRotatesAndScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun statusBarLayerRotatesScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun statusBarLayerRotatesScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
-
- @FlakyTest
- @Test
- fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 18fac6a..4a32a9e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,36 +16,19 @@
package com.android.server.wm.flicker.launch
-import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
-import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -61,18 +44,12 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromOverviewTest(private val testSpec: FlickerTestParameter) {
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = SimpleAppHelper(instrumentation)
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
+class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
setup {
test {
- device.wakeUpAndGoToHomeScreen()
testApp.launchViaIntent(wmHelper)
}
eachRun {
@@ -87,71 +64,50 @@
device.reopenAppFromOverview(wmHelper)
wmHelper.waitForFullScreenApp(testApp.component)
}
- teardown {
- test {
- testApp.exit()
- }
- }
}
+
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() =
+ super.appWindowReplacesLauncherAsTopWindow()
+
+ @Test
+ override fun wallpaperWindowBecomesInvisible() {
+ testSpec.wallpaperWindowBecomesInvisible()
}
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
-
- @Test
- fun appWindowReplacesLauncherAsTopWindow() =
- testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
-
- @Test
- fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
-
- @Presubmit
- @Test
- fun appLayerReplacesWallpaperLayer() =
- testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun statusBarLayerRotatesScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() {
+ override fun statusBarLayerIsAlwaysVisible() {
Assume.assumeTrue(testSpec.isRotated)
- testSpec.statusBarLayerIsAlwaysVisible()
+ super.statusBarLayerIsAlwaysVisible()
}
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() {
+ override fun navBarLayerIsAlwaysVisible() {
Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerIsAlwaysVisible()
+ super.navBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ fun statusBarLayerIsAlwaysVisible_Flaky() {
+ Assume.assumeFalse(testSpec.isRotated)
+ super.statusBarLayerIsAlwaysVisible()
+ }
+
+ @FlakyTest
+ @Test
+ fun navBarLayerIsAlwaysVisible_Flaky() {
+ Assume.assumeFalse(testSpec.isRotated)
+ super.navBarLayerIsAlwaysVisible()
}
@Presubmit
@Test
- fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
-
- @Presubmit
- @Test
- fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
Assume.assumeFalse(testSpec.isRotated)
- testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
}
@FlakyTest
@@ -163,9 +119,9 @@
@Presubmit
@Test
- fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
Assume.assumeFalse(testSpec.isRotated)
- testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
@FlakyTest
@@ -175,11 +131,6 @@
testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
}
- @Presubmit
- @Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(Surface.ROTATION_0,
- testSpec.config.endRotation)
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
new file mode 100644
index 0000000..e9f0534
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import org.junit.Assume
+import org.junit.Test
+
+abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
+ protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ protected val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+
+ protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(testSpec.config.startRotation)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ }
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ transition(testSpec.config)
+ }
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarWindowIsAlwaysVisible() {
+ testSpec.navBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerIsAlwaysVisible() {
+ testSpec.navBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun navBarLayerRotatesAndScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ open fun navBarLayerRotatesAndScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarWindowIsAlwaysVisible() {
+ testSpec.statusBarWindowIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerIsAlwaysVisible() {
+ testSpec.statusBarLayerIsAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ open fun statusBarLayerRotatesScales() {
+ Assume.assumeFalse(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @FlakyTest
+ @Test
+ open fun statusBarLayerRotatesScales_Flaky() {
+ Assume.assumeTrue(testSpec.isRotated)
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+
+ @FlakyTest
+ @Test
+ open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ @Presubmit
+ @Test
+ // During testing the launcher is always in portrait mode
+ open fun noUncoveredRegions() {
+ testSpec.noUncoveredRegions(Surface.ROTATION_0, testSpec.config.endRotation)
+ }
+
+ @Presubmit
+ @Test
+ open fun focusChanges() {
+ testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+
+ @Presubmit
+ @Test
+ open fun appLayerReplacesWallpaperLayer() {
+ testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
+ }
+
+ @Presubmit
+ @Test
+ open fun appWindowReplacesLauncherAsTopWindow() {
+ testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+ }
+
+ @Presubmit
+ @Test
+ open fun wallpaperWindowBecomesInvisible() {
+ testSpec.wallpaperWindowBecomesInvisible()
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index b61310a..a8b5ea1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,34 +16,14 @@
package com.android.server.wm.flicker.launch
-import android.app.Instrumentation
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
-import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,20 +38,13 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppWarmTest(private val testSpec: FlickerTestParameter) {
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp = SimpleAppHelper(instrumentation)
-
- @FlickerBuilderProvider
- fun buildFlicker(): FlickerBuilder {
- return FlickerBuilder(instrumentation).apply {
- withTestName { testSpec.name }
- repeat { testSpec.config.repetitions }
+class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
setup {
test {
- device.wakeUpAndGoToHomeScreen()
testApp.launchViaIntent(wmHelper)
- // wmHelper.waitForFullScreenApp(testApp.component)
}
eachRun {
device.pressHome()
@@ -79,93 +52,21 @@
this.setRotation(testSpec.config.startRotation)
}
}
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
transitions {
testApp.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(testApp.component)
}
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- test {
- testApp.exit()
- }
- }
}
- }
-
- @Presubmit
- @Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
@FlakyTest
@Test
- fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- testSpec.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
- @Presubmit
- @Test
- fun appWindowReplacesLauncherAsTopWindow() =
- testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
-
- @Presubmit
- @Test
- fun wallpaperWindowBecomesInvisible() = testSpec.wallpaperWindowBecomesInvisible()
-
- @Presubmit
- @Test
- // During testing the launcher is always in portrait mode
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
- Surface.ROTATION_0)
-
- @Presubmit
- @Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
-
- @Presubmit
- @Test
- fun appLayerReplacesWallpaperLayer() =
- testSpec.appLayerReplacesWallpaperLayer(testApp.`package`)
-
- @Presubmit
- @Test
- fun navBarLayerRotatesAndScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun navBarLayerRotatesAndScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun statusBarLayerRotatesScales() {
- Assume.assumeFalse(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @FlakyTest
- @Test
- fun statusBarLayerRotatesScales_Flaky() {
- Assume.assumeTrue(testSpec.isRotated)
- testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0)
- }
-
- @Presubmit
- @Test
- fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 335c8d0..eacf5b2 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -9,14 +9,17 @@
android_test {
name: "InputTests",
- srcs: ["src/**/*.kt"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
platform_apis: true,
certificate: "platform",
static_libs: [
- "androidx.test.ext.junit",
- "androidx.test.rules",
- "truth-prebuilt",
- "ub-uiautomator",
- ],
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "truth-prebuilt",
+ "ub-uiautomator",
+ ],
test_suites: ["device-tests"],
}
diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java
new file mode 100644
index 0000000..6350077
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class InputDeviceTest {
+ private static final float DELTA = 0.01f;
+ private static final int DEVICE_ID = 1000;
+
+ private void assertMotionRangeEquals(InputDevice.MotionRange range,
+ InputDevice.MotionRange outRange) {
+ assertEquals(range.getAxis(), outRange.getAxis());
+ assertEquals(range.getSource(), outRange.getSource());
+ assertEquals(range.getMin(), outRange.getMin(), DELTA);
+ assertEquals(range.getMax(), outRange.getMax(), DELTA);
+ assertEquals(range.getFlat(), outRange.getFlat(), DELTA);
+ assertEquals(range.getFuzz(), outRange.getFuzz(), DELTA);
+ assertEquals(range.getResolution(), outRange.getResolution(), DELTA);
+ }
+
+ private void assertDeviceEquals(InputDevice device, InputDevice outDevice) {
+ assertEquals(device.getId(), outDevice.getId());
+ assertEquals(device.getGeneration(), outDevice.getGeneration());
+ assertEquals(device.getControllerNumber(), outDevice.getControllerNumber());
+ assertEquals(device.getName(), outDevice.getName());
+ assertEquals(device.getVendorId(), outDevice.getVendorId());
+ assertEquals(device.getProductId(), outDevice.getProductId());
+ assertEquals(device.getDescriptor(), outDevice.getDescriptor());
+ assertEquals(device.isExternal(), outDevice.isExternal());
+ assertEquals(device.getSources(), outDevice.getSources());
+ assertEquals(device.getKeyboardType(), outDevice.getKeyboardType());
+ assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size());
+
+ KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap();
+ KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap();
+ assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap));
+
+ for (int j = 0; j < device.getMotionRanges().size(); j++) {
+ assertMotionRangeEquals(device.getMotionRanges().get(j),
+ outDevice.getMotionRanges().get(j));
+ }
+ }
+
+ private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) {
+ final InputDevice device =
+ new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name",
+ 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
+ 0 /* sources */, 0 /* keyboardType */, keyCharacterMap,
+ false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */,
+ true /* hasSensor */, false /* hasBattery */);
+
+ Parcel parcel = Parcel.obtain();
+ device.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ InputDevice outDevice = InputDevice.CREATOR.createFromParcel(parcel);
+ assertDeviceEquals(device, outDevice);
+ }
+
+ @Test
+ public void testParcelUnparcelInputDevice_VirtualCharacterMap() {
+ final KeyCharacterMap keyCharacterMap =
+ KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ assertInputDeviceParcelUnparcel(keyCharacterMap);
+ }
+
+ @Test
+ public void testParcelUnparcelInputDevice_EmptyCharacterMap() {
+ final KeyCharacterMap keyCharacterMap = KeyCharacterMap.obtainEmptyMap(DEVICE_ID);
+ assertInputDeviceParcelUnparcel(keyCharacterMap);
+ }
+}
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index d6846fa..e121b68 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -94,17 +94,16 @@
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
- uiAutomation.adoptShellPermissionIdentity(
- Manifest.permission.LOG_COMPAT_CHANGE,
- Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ adoptShellPermissions(uiAutomation);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
packageName);
try {
+ uiAutomation.dropShellPermissionIdentity();
mTestStatement.evaluate();
} finally {
+ adoptShellPermissions(uiAutomation);
platformCompat.clearOverridesForTest(packageName);
}
} catch (RemoteException e) {
@@ -114,5 +113,12 @@
Compatibility.clearOverrides();
}
}
+
+ private static void adoptShellPermissions(UiAutomation uiAutomation) {
+ uiAutomation.adoptShellPermissionIdentity(
+ Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG);
+ }
}
}
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
index 2f62af1..8fa0510 100644
--- a/tests/RollbackTest/MultiUserRollbackTest.xml
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -20,6 +20,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml
index 2ab907a..13f6031 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest.xml
+++ b/tests/RollbackTest/NetworkStagedRollbackTest.xml
@@ -24,6 +24,8 @@
<option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package "com.google.android.gms.platformconfigurator" --es user '\\*' --esa flags "ModuleConfig__versioned_immediate_commit_packages" --esa types "bytes" --esa values "Cm5vdGFwYWNrYWdlOgA=" com.google.android.gms" />
<option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package "com.google.android.gms.platformconfigurator" --es user '\*' --esa flag "ModuleConfig__immediate_commit_packages" com.google.android.gms" />
<option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package "com.google.android.gms.platformconfigurator" --es user '\*' --esa flag "ModuleConfig__versioned_immediate_commit_packages" com.google.android.gms" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" />
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index 7b85cc8..fbb6e46 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -27,6 +27,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.tests.rollback" />
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
index 83fef8e..0ca4daf 100644
--- a/tests/RollbackTest/StagedRollbackTest.xml
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -24,6 +24,8 @@
<option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
<option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="run-command" value="setprop persist.rollback.is_test 1" />
+ <option name="teardown-command" value="setprop persist.rollback.is_test 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 7f0318a..e1a424f 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -79,6 +79,7 @@
"android.test.runner",
"android.test.base",
"android.test.mock",
+ "ServiceConnectivityResources",
],
jni_libs: [
"libservice-connectivity",
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index e84b992..0dfec75 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -28,6 +28,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
@@ -44,6 +45,10 @@
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
import static android.os.Process.INVALID_UID;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
+import static com.android.testutils.MiscAsserts.assertEmpty;
+import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
@@ -67,7 +72,6 @@
import androidx.test.runner.AndroidJUnit4;
-import com.android.modules.utils.build.SdkLevel;
import com.android.testutils.CompatUtil;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -85,6 +89,9 @@
public class NetworkCapabilitiesTest {
private static final String TEST_SSID = "TEST_SSID";
private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+ private static final int TEST_SUBID1 = 1;
+ private static final int TEST_SUBID2 = 2;
+ private static final int TEST_SUBID3 = 3;
@Rule
public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
@@ -92,14 +99,6 @@
private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class);
private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
- private boolean isAtLeastR() {
- return SdkLevel.isAtLeastR();
- }
-
- private boolean isAtLeastS() {
- return SdkLevel.isAtLeastS();
- }
-
@Test
public void testMaybeMarkCapabilitiesRestricted() {
// verify EIMS is restricted
@@ -305,7 +304,9 @@
.setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
- if (isAtLeastR()) {
+ if (isAtLeastS()) {
+ netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ } else if (isAtLeastR()) {
netCap.setOwnerUid(123);
netCap.setAdministratorUids(new int[] {5, 11});
}
@@ -380,7 +381,7 @@
private void testParcelSane(NetworkCapabilities cap) {
if (isAtLeastS()) {
- assertParcelSane(cap, 16);
+ assertParcelSane(cap, 17);
} else if (isAtLeastR()) {
assertParcelSane(cap, 15);
} else {
@@ -614,6 +615,20 @@
assertFalse(nc2.appliesToUid(12));
assertTrue(nc1.appliesToUid(22));
assertTrue(nc2.appliesToUid(22));
+
+ // Verify the subscription id list can be combined only when they are equal.
+ if (isAtLeastS()) {
+ nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
+ nc2.setSubIds(Set.of(TEST_SUBID2));
+ assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+ nc2.setSubIds(Set.of());
+ assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
+
+ nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.combineCapabilities(nc1);
+ assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubIds());
+ }
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
@@ -762,6 +777,24 @@
nc1.setUids(uidRange(10, 13));
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
assertEquals(nc1, nc2);
+
+ if (isAtLeastS()) {
+ assertThrows(NullPointerException.class, () -> nc1.setSubIds(null));
+ nc1.setSubIds(Set.of());
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc1.setSubIds(Set.of(TEST_SUBID1));
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc2.setSubIds(Set.of(TEST_SUBID2, TEST_SUBID1));
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+
+ nc2.setSubIds(Set.of(TEST_SUBID3, TEST_SUBID2));
+ assertNotEquals(nc1, nc2);
+ }
}
@Test
@@ -842,6 +875,50 @@
} catch (NullPointerException expected) { }
}
+ private static NetworkCapabilities capsWithSubIds(Integer ... subIds) {
+ // Since the NetworkRequest would put NOT_VCN_MANAGED capabilities in general, for
+ // every NetworkCapabilities that simulates networks needs to add it too in order to
+ // satisfy these requests.
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .setSubIds(new ArraySet<>(subIds)).build();
+ assertEquals(new ArraySet<>(subIds), nc.getSubIds());
+ return nc;
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testSubIds() throws Exception {
+ final NetworkCapabilities ncWithoutId = capsWithSubIds();
+ final NetworkCapabilities ncWithId = capsWithSubIds(TEST_SUBID1);
+ final NetworkCapabilities ncWithOtherIds = capsWithSubIds(TEST_SUBID1, TEST_SUBID3);
+ final NetworkCapabilities ncWithoutRequestedIds = capsWithSubIds(TEST_SUBID3);
+
+ final NetworkRequest requestWithoutId = new NetworkRequest.Builder().build();
+ assertEmpty(requestWithoutId.networkCapabilities.getSubIds());
+ final NetworkRequest requestWithIds = new NetworkRequest.Builder()
+ .setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build();
+ assertEquals(Set.of(TEST_SUBID1, TEST_SUBID2),
+ requestWithIds.networkCapabilities.getSubIds());
+
+ assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutId));
+ assertTrue(requestWithIds.canBeSatisfiedBy(ncWithOtherIds));
+ assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutRequestedIds));
+ assertTrue(requestWithIds.canBeSatisfiedBy(ncWithId));
+ assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithoutId));
+ assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithId));
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testEqualsSubIds() throws Exception {
+ assertEquals(capsWithSubIds(), capsWithSubIds());
+ assertNotEquals(capsWithSubIds(), capsWithSubIds(TEST_SUBID1));
+ assertEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID1));
+ assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2));
+ assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+ assertEquals(capsWithSubIds(TEST_SUBID1, TEST_SUBID2),
+ capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
+ }
+
@Test
public void testLinkBandwidthKbps() {
final NetworkCapabilities nc = new NetworkCapabilities();
@@ -1022,5 +1099,11 @@
fail("Should not set null into NetworkCapabilities.Builder");
} catch (NullPointerException expected) { }
assertEquals(nc, new NetworkCapabilities.Builder(nc).build());
+
+ if (isAtLeastS()) {
+ final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
+ .setSubIds(Set.of(TEST_SUBID1)).build();
+ assertEquals(Set.of(TEST_SUBID1), nc2.getSubIds());
+ }
}
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 6a09b02..6fc605e 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -220,7 +220,7 @@
// register callback
when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(request);
+ anyInt(), any(), nullable(String.class))).thenReturn(request);
manager.requestNetwork(request, callback, handler);
// callback triggers
@@ -248,7 +248,7 @@
// register callback
when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(req1);
+ anyInt(), any(), nullable(String.class))).thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
// callback triggers
@@ -266,7 +266,7 @@
// callback can be registered again
when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- any(), nullable(String.class))).thenReturn(req2);
+ anyInt(), any(), nullable(String.class))).thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
// callback triggers
@@ -289,8 +289,8 @@
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), any(),
- nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(),
+ any(), nullable(String.class))).thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
manager.requestNetwork(request, callback, handler);
@@ -358,34 +358,34 @@
manager.requestNetwork(request, callback);
verify(mService).requestNetwork(eq(request.networkCapabilities),
- eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
manager.registerNetworkCallback(request, callback);
- verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
+ verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(),
anyInt(), any(), any());
- verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
+ verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerDefaultNetworkCallback(callback);
verify(mService).requestNetwork(eq(null),
- eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
-
- manager.requestBackgroundNetwork(request, null, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
- eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ manager.requestBackgroundNetwork(request, handler, callback);
+ verify(mService).requestNetwork(eq(request.networkCapabilities),
+ eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
+ eq(testPkgName), eq(testAttributionTag));
+ reset(mService);
+
manager.registerSystemDefaultNetworkCallback(callback, handler);
verify(mService).requestNetwork(eq(null),
- eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 3102b99..fadd1ea 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -275,6 +275,7 @@
import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
import com.android.server.connectivity.ConnectivityConstants;
+import com.android.server.connectivity.ConnectivityResources;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
@@ -444,6 +445,7 @@
@Mock NetworkPolicyManager mNetworkPolicyManager;
@Mock VpnProfileStore mVpnProfileStore;
@Mock SystemConfigManager mSystemConfigManager;
+ @Mock Resources mResources;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -471,7 +473,7 @@
private class MockContext extends BroadcastInterceptingContext {
private final MockContentResolver mContentResolver;
- @Spy private Resources mResources;
+ @Spy private Resources mInternalResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
// Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
@@ -480,21 +482,15 @@
MockContext(Context base, ContentProvider settingsProvider) {
super(base);
- mResources = spy(base.getResources());
- when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)).
- thenReturn(new String[] {
+ mInternalResources = spy(base.getResources());
+ when(mInternalResources.getStringArray(com.android.internal.R.array.networkAttributes))
+ .thenReturn(new String[] {
"wifi,1,1,1,-1,true",
"mobile,0,0,0,-1,true",
"mobile_mms,2,0,2,60000,true",
"mobile_supl,3,0,2,60000,true",
});
- when(mResources.getStringArray(
- com.android.internal.R.array.config_wakeonlan_supported_interfaces))
- .thenReturn(new String[]{
- WIFI_WOL_IFNAME,
- });
-
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@@ -559,7 +555,7 @@
@Override
public Resources getResources() {
- return mResources;
+ return mInternalResources;
}
@Override
@@ -1454,6 +1450,8 @@
applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
+ when(mPackageManager.getTargetSdkVersion(anyString()))
+ .thenReturn(applicationInfo.targetSdkVersion);
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
@@ -1532,6 +1530,17 @@
}).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
doReturn(true).when(deps).getCellular464XlatEnabled();
+ doReturn(60000).when(mResources).getInteger(
+ com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
+ doReturn("").when(mResources).getString(
+ com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
+ doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray(
+ com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces);
+ final com.android.server.connectivity.ConnectivityResources connRes = mock(
+ ConnectivityResources.class);
+ doReturn(mResources).when(connRes).get();
+ doReturn(connRes).when(deps).getResources(any());
+
return deps;
}
@@ -3749,8 +3758,8 @@
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
- null, 0, null, ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
- getAttributionTag());
+ null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
+ mContext.getPackageName(), getAttributionTag());
});
class NonParcelableSpecifier extends NetworkSpecifier {
@@ -4027,7 +4036,8 @@
grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build(), null, cellBgCallback);
+ .addTransportType(TRANSPORT_CELLULAR).build(),
+ mCsHandlerThread.getThreadHandler(), cellBgCallback);
// Make callbacks for monitoring.
final NetworkRequest request = new NetworkRequest.Builder().build();
@@ -8755,6 +8765,7 @@
applicationInfo.targetSdkVersion = targetSdk;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
+ when(mPackageManager.getTargetSdkVersion(any())).thenReturn(targetSdk);
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
@@ -8769,102 +8780,183 @@
}
}
- private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
+ private int getOwnerUidNetCapsPermission(int ownerUid, int callerUid,
+ boolean includeLocationSensitiveInfo) {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid();
+ netCap, includeLocationSensitiveInfo, callerUid,
+ mContext.getPackageName(), getAttributionTag())
+ .getOwnerUid();
}
- private void verifyWifiInfoCopyNetCapsForCallerPermission(
- int callerUid, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+ private void verifyWifiInfoCopyNetCapsPermission(
+ int callerUid, boolean includeLocationSensitiveInfo,
+ boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
final WifiInfo wifiInfo = mock(WifiInfo.class);
when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName(), getAttributionTag());
+ netCap, includeLocationSensitiveInfo, callerUid,
+ mContext.getPackageName(), getAttributionTag());
verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
}
+ private void verifyOwnerUidAndWifiInfoNetCapsPermission(
+ boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
+ boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
+ boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag,
+ boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) {
+ final int myUid = Process.myUid();
+
+ final int expectedOwnerUidWithoutIncludeFlag =
+ shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
+ ? Process.myUid() : INVALID_UID;
+ assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
+ myUid, myUid, false /* includeLocationSensitiveInfo */));
+
+ final int expectedOwnerUidWithIncludeFlag =
+ shouldInclLocationSensitiveOwnerUidWithIncludeFlag ? myUid : INVALID_UID;
+ assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
+ myUid, myUid, true /* includeLocationSensitiveInfo */));
+
+ verifyWifiInfoCopyNetCapsPermission(myUid,
+ false, /* includeLocationSensitiveInfo */
+ shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag);
+
+ verifyWifiInfoCopyNetCapsPermission(myUid,
+ true, /* includeLocationSensitiveInfo */
+ shouldInclLocationSensitiveWifiInfoWithIncludeFlag);
+
+ }
+
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithFineLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we include owner uid even if the request asks to remove it since the
+ // app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationPreQ()
+ public void testCreateWithLocationInfoSanitizedWithFineLocationPreSWithAndWithoutCallbackFlag()
+ throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we include owner uid even if the request asks to remove it since the
+ // app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
+ }
+
+ @Test
+ public void
+ testCreateWithLocationInfoSanitizedWithFineLocationAfterSWithAndWithoutCallbackFlag()
+ throws Exception {
+ setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we owner UID if the request asks us to remove it even if the app
+ // has necessary permissions since targetSdk >= S.
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
+ }
+
+ @Test
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationPreQ()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ // Ensure that we owner UID if the request asks us to remove it even if the app
+ // has necessary permissions since targetSdk >= S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ // Ensure that we remove location info if the request asks to remove it even if the
+ // app has necessary permissions.
+ true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedLocationOff() throws Exception {
+ public void testCreateWithLocationInfoSanitizedLocationOff() throws Exception {
// Test that even with fine location permission, and UIDs matching, the UID is sanitized.
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWrongUid() throws Exception {
+ public void testCreateWithLocationInfoSanitizedWrongUid() throws Exception {
// Test that even with fine location permission, not being the owner leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ assertEquals(Process.INVALID_UID,
+ getOwnerUidNetCapsPermission(myUid + 1, myUid,
+ true /* includeLocationSensitiveInfo */));
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterQ()
throws Exception {
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
@Test
- public void testCreateForCallerWithLocationInfoSanitizedWithoutLocationPermission()
+ public void testCreateWithLocationInfoSanitizedWithoutLocationPermission()
throws Exception {
+ // Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
- // Test that without the location permission, the owner field is sanitized.
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
-
- verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
- false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
+ verifyOwnerUidAndWifiInfoNetCapsPermission(
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ );
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -9455,8 +9547,8 @@
assertThrows("Expect throws for invalid request type " + reqTypeInt,
IllegalArgumentException.class,
() -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
- ConnectivityManager.TYPE_NONE, mContext.getPackageName(),
- getAttributionTag())
+ ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
+ mContext.getPackageName(), getAttributionTag())
);
}
}
@@ -11026,4 +11118,12 @@
verifyNoNetwork();
mCm.unregisterNetworkCallback(cellCb);
}
-}
\ No newline at end of file
+
+ @Test
+ public void testRegisterBestMatchingNetworkCallback() throws Exception {
+ final NetworkRequest request = new NetworkRequest.Builder().build();
+ assertThrows(UnsupportedOperationException.class,
+ () -> mCm.registerBestMatchingNetworkCallback(request, new NetworkCallback(),
+ mCsHandlerThread.getThreadHandler()));
+ }
+}
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index f97eabf..6232423 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
@@ -47,6 +48,7 @@
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
+import android.util.Range;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -647,9 +649,9 @@
@Test
public void testReserveNetId() {
- int start = mIpSecService.TUN_INTF_NETID_START;
- for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) {
- assertEquals(start + i, mIpSecService.reserveNetId());
+ final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange();
+ for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) {
+ assertEquals(netId, mIpSecService.reserveNetId());
}
// Check that resource exhaustion triggers an exception
@@ -661,7 +663,7 @@
// Now release one and try again
int releasedNetId =
- mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2;
+ netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2;
mIpSecService.releaseNetId(releasedNetId);
assertEquals(releasedNetId, mIpSecService.reserveNetId());
}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index e4e24b4..fec5ef3 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -48,18 +48,22 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.net.INetd;
import android.net.UidRange;
+import android.net.Uri;
import android.os.Build;
import android.os.SystemConfigManager;
import android.os.UserHandle;
@@ -70,12 +74,11 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.LocalServices;
-import com.android.server.pm.PackageList;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@@ -112,7 +115,6 @@
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
@Mock private INetd mNetdService;
- @Mock private PackageManagerInternal mMockPmi;
@Mock private UserManager mUserManager;
@Mock private PermissionMonitor.Dependencies mDeps;
@Mock private SystemConfigManager mSystemConfigManager;
@@ -131,16 +133,14 @@
when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
.thenReturn(mSystemConfigManager);
when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
+ final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
+ doReturn(UserHandle.ALL).when(asUserCtx).getUser();
+ when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, mMockPmi);
- when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
- /* observer */ null));
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
mPermissionMonitor.startMonitoring();
- verify(mMockPmi).getPackageList(mPermissionMonitor);
}
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
@@ -770,4 +770,32 @@
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
new int[]{ MOCK_UID2 });
}
+
+ @Test
+ public void testIntentReceiver() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
+ final BroadcastReceiver receiver = receiverCaptor.getValue();
+
+ // Verify receiving PACKAGE_ADDED intent.
+ final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
+ Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+ addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+ setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
+ new String[] { INTERNET, UPDATE_DEVICE_STATS });
+ receiver.onReceive(mContext, addedIntent);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 });
+
+ // Verify receiving PACKAGE_REMOVED intent.
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
+ final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
+ Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
+ removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
+ receiver.onReceive(mContext, removedIntent);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
+ }
+
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 11498de..a0200275 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -593,6 +593,16 @@
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
+ @Test(expected = SecurityException.class)
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+ doThrow(new SecurityException())
+ .when(mMockContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
@Test
public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);