Merge "Logging cleanup" into main
diff --git a/apct-tests/perftests/protolog/Android.bp b/apct-tests/perftests/tracing/Android.bp
similarity index 100%
rename from apct-tests/perftests/protolog/Android.bp
rename to apct-tests/perftests/tracing/Android.bp
diff --git a/apct-tests/perftests/protolog/AndroidManifest.xml b/apct-tests/perftests/tracing/AndroidManifest.xml
similarity index 100%
rename from apct-tests/perftests/protolog/AndroidManifest.xml
rename to apct-tests/perftests/tracing/AndroidManifest.xml
diff --git a/apct-tests/perftests/protolog/AndroidTest.xml b/apct-tests/perftests/tracing/AndroidTest.xml
similarity index 100%
rename from apct-tests/perftests/protolog/AndroidTest.xml
rename to apct-tests/perftests/tracing/AndroidTest.xml
diff --git a/apct-tests/perftests/protolog/OWNERS b/apct-tests/perftests/tracing/OWNERS
similarity index 100%
rename from apct-tests/perftests/protolog/OWNERS
rename to apct-tests/perftests/tracing/OWNERS
diff --git a/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtoLogPerfTest.java b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
similarity index 60%
rename from apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtoLogPerfTest.java
rename to apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
index 92dd9be..f4759b8 100644
--- a/apct-tests/perftests/protolog/src/com/android/internal/protolog/ProtoLogPerfTest.java
+++ b/apct-tests/perftests/tracing/src/com/android/internal/protolog/ProtoLogPerfTest.java
@@ -15,43 +15,54 @@
*/
package com.android.internal.protolog;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
+import android.app.Activity;
+import android.os.Bundle;
+import android.perftests.utils.Stats;
+
+import androidx.test.InstrumentationRegistry;
import com.android.internal.protolog.common.IProtoLogGroup;
import com.android.internal.protolog.common.LogLevel;
import org.junit.Before;
import org.junit.BeforeClass;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collection;
@RunWith(Parameterized.class)
public class ProtoLogPerfTest {
- @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
- @Parameters(name="logToProto_{0}_logToLogcat_{1}")
- public static Collection<Object[]> params() {
- return Arrays.asList(new Object[][] {
- { true, true },
- { true, false },
- { false, true },
- { false, false }
- });
- }
-
private final boolean mLogToProto;
private final boolean mLogToLogcat;
- public ProtoLogPerfTest(boolean logToProto, boolean logToLogcat) {
- mLogToProto = logToProto;
- mLogToLogcat = logToLogcat;
+ /**
+ * Generates the parameters used for this test class
+ */
+ @Parameters(name = "LOG_TO_{0}")
+ public static Collection<Object[]> params() {
+ var params = new ArrayList<Object[]>();
+
+ for (LogTo logTo : LogTo.values()) {
+ params.add(new Object[] { logTo });
+ }
+
+ return params;
+ }
+
+ public ProtoLogPerfTest(LogTo logTo) {
+ mLogToProto = switch (logTo) {
+ case ALL, PROTO_ONLY -> true;
+ case LOGCAT_ONLY, NONE -> false;
+ };
+
+ mLogToLogcat = switch (logTo) {
+ case ALL, LOGCAT_ONLY -> true;
+ case PROTO_ONLY, NONE -> false;
+ };
}
@BeforeClass
@@ -66,11 +77,11 @@
}
@Test
- public void logProcessedProtoLogMessageWithoutArgs() {
+ public void log_Processed_NoArgs() {
final var protoLog = ProtoLog.getSingleInstance();
+ final var perfMonitor = new PerfMonitor();
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
+ while (perfMonitor.keepRunning()) {
protoLog.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 123,
0, (Object[]) null);
@@ -78,11 +89,11 @@
}
@Test
- public void logProcessedProtoLogMessageWithArgs() {
+ public void log_Processed_WithArgs() {
final var protoLog = ProtoLog.getSingleInstance();
+ final var perfMonitor = new PerfMonitor();
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
+ while (perfMonitor.keepRunning()) {
protoLog.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 123,
0b1110101001010100,
@@ -91,18 +102,58 @@
}
@Test
- public void logNonProcessedProtoLogMessageWithNoArgs() {
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
+ public void log_Unprocessed_NoArgs() {
+ final var perfMonitor = new PerfMonitor();
+
+ while (perfMonitor.keepRunning()) {
ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test message");
}
}
@Test
- public void logNonProcessedProtoLogMessageWithArgs() {
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test messag %s, %d, %b", "arg1", 2, true);
+ public void log_Unprocessed_WithArgs() {
+ final var perfMonitor = new PerfMonitor();
+
+ while (perfMonitor.keepRunning()) {
+ ProtoLog.d(TestProtoLogGroup.TEST_GROUP, "Test message %s, %d, %b", "arg1", 2, true);
+ }
+ }
+
+ private class PerfMonitor {
+ private int mIteration = 0;
+
+ private static final int WARM_UP_ITERATIONS = 10;
+ private static final int ITERATIONS = 1000;
+
+ private final ArrayList<Long> mResults = new ArrayList<>();
+
+ private long mStartTimeNs;
+
+ public boolean keepRunning() {
+ final long currentTime = System.nanoTime();
+
+ mIteration++;
+
+ if (mIteration > ITERATIONS) {
+ reportResults();
+ return false;
+ }
+
+ if (mIteration > WARM_UP_ITERATIONS) {
+ mResults.add(currentTime - mStartTimeNs);
+ }
+
+ mStartTimeNs = System.nanoTime();
+ return true;
+ }
+
+ public void reportResults() {
+ final var stats = new Stats(mResults);
+
+ Bundle status = new Bundle();
+ status.putLong("protologging_time_mean_ns", (long) stats.getMean());
+ status.putLong("protologging_time_median_ns", (long) stats.getMedian());
+ InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
}
}
@@ -168,4 +219,11 @@
return ordinal();
}
}
+
+ private enum LogTo {
+ PROTO_ONLY,
+ LOGCAT_ONLY,
+ ALL,
+ NONE,
+ }
}
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
index 613b784..e5389b4 100644
--- a/apex/jobscheduler/service/aconfig/job.aconfig
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -65,3 +65,13 @@
description: "Remove started user if user will be stopped due to user switch"
bug: "321598070"
}
+
+flag {
+ name: "use_correct_process_state_for_logging"
+ namespace: "backstage_power"
+ description: "Use correct process state for statsd logging"
+ bug: "361308212"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index d65a66c..be8e304 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -473,6 +473,14 @@
mInitialDownloadedBytesFromCalling = TrafficStats.getUidRxBytes(job.getUid());
mInitialUploadedBytesFromCalling = TrafficStats.getUidTxBytes(job.getUid());
+ int procState = mService.getUidProcState(job.getUid());
+ if (Flags.useCorrectProcessStateForLogging()
+ && procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ // Try to get the latest proc state from AMS, there might be some delay
+ // for the proc states worse than TRANSIENT_BACKGROUND.
+ procState = mActivityManagerInternal.getUidProcessState(job.getUid());
+ }
+
FrameworkStatsLog.write(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
job.isProxyJob() ? new int[]{sourceUid, job.getUid()} : new int[]{sourceUid},
// Given that the source tag is set by the calling app, it should be connected
@@ -517,7 +525,7 @@
job.getEstimatedNetworkDownloadBytes(),
job.getEstimatedNetworkUploadBytes(),
job.getWorkCount(),
- ActivityManager.processStateAmToProto(mService.getUidProcState(job.getUid())),
+ ActivityManager.processStateAmToProto(procState),
job.getNamespaceHash(),
/* system_measured_source_download_bytes */ 0,
/* system_measured_source_upload_bytes */ 0,
@@ -1528,6 +1536,13 @@
mJobPackageTracker.noteInactive(completedJob,
loggingInternalStopReason, loggingDebugReason);
final int sourceUid = completedJob.getSourceUid();
+ int procState = mService.getUidProcState(completedJob.getUid());
+ if (Flags.useCorrectProcessStateForLogging()
+ && procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ // Try to get the latest proc state from AMS, there might be some delay
+ // for the proc states worse than TRANSIENT_BACKGROUND.
+ procState = mActivityManagerInternal.getUidProcessState(completedJob.getUid());
+ }
FrameworkStatsLog.write(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
completedJob.isProxyJob()
? new int[]{sourceUid, completedJob.getUid()} : new int[]{sourceUid},
@@ -1573,7 +1588,7 @@
completedJob.getEstimatedNetworkUploadBytes(),
completedJob.getWorkCount(),
ActivityManager
- .processStateAmToProto(mService.getUidProcState(completedJob.getUid())),
+ .processStateAmToProto(procState),
completedJob.getNamespaceHash(),
TrafficStats.getUidRxBytes(completedJob.getSourceUid())
- mInitialDownloadedBytesFromSource,
diff --git a/api/Android.bp b/api/Android.bp
index 341be3d53..533f9f6 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -87,6 +87,7 @@
"framework-permission",
"framework-permission-s",
"framework-profiling",
+ "framework-photopicker",
"framework-scheduling",
"framework-sdkextensions",
"framework-statsd",
diff --git a/core/api/current.txt b/core/api/current.txt
index ed8ab06..ddfd364 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7964,13 +7964,13 @@
field public static final String LOCK_TASK_POLICY = "lockTask";
field public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
field public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
- field @FlaggedApi("android.app.admin.flags.policy_engine_migration_v2_enabled") public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
+ field public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
field public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
field public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY = "persistentPreferredActivity";
field public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
field public static final String SECURITY_LOGGING_POLICY = "securityLogging";
field public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
- field @FlaggedApi("android.app.admin.flags.policy_engine_migration_v2_enabled") public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
+ field public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
field public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY = "userControlDisabledPackages";
}
@@ -8756,6 +8756,8 @@
method public int getResultCode();
method @NonNull public android.app.appsearch.GenericDocument getResultDocument();
method public boolean isSuccess();
+ method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newFailure(int, @Nullable String, @Nullable android.os.Bundle);
+ method @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") @NonNull public static android.app.appfunctions.ExecuteAppFunctionResponse newSuccess(@NonNull android.app.appsearch.GenericDocument, @Nullable android.os.Bundle);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.appfunctions.ExecuteAppFunctionResponse> CREATOR;
field public static final String PROPERTY_RETURN_VALUE = "returnValue";
@@ -8767,13 +8769,6 @@
field public static final int RESULT_TIMED_OUT = 5; // 0x5
}
- @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final class ExecuteAppFunctionResponse.Builder {
- ctor public ExecuteAppFunctionResponse.Builder(@NonNull android.app.appsearch.GenericDocument);
- ctor public ExecuteAppFunctionResponse.Builder(int, @NonNull String);
- method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse build();
- method @NonNull public android.app.appfunctions.ExecuteAppFunctionResponse.Builder setExtras(@NonNull android.os.Bundle);
- }
-
}
package android.app.assist {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f26522b..3637ca7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6746,6 +6746,14 @@
field public static final int STATUS_OK = 0; // 0x0
}
+ @FlaggedApi("android.media.soundtrigger.generic_model_api") public static final class SoundTrigger.GenericSoundModel extends android.hardware.soundtrigger.SoundTrigger.SoundModel implements android.os.Parcelable {
+ ctor public SoundTrigger.GenericSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], int);
+ ctor public SoundTrigger.GenericSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[]);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.GenericSoundModel> CREATOR;
+ }
+
public static final class SoundTrigger.Keyphrase implements android.os.Parcelable {
ctor public SoundTrigger.Keyphrase(int, int, @NonNull java.util.Locale, @NonNull String, @Nullable int[]);
method public int describeContents();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 009d082..a1aa679 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -597,19 +597,19 @@
method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int);
method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs();
- method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_internal_bug_fix_enabled") @RequiresPermission("android.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT") public void forceSetMaxPolicyStorageLimit(int);
+ method @RequiresPermission("android.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT") public void forceSetMaxPolicyStorageLimit(int);
method public void forceUpdateUserSetupComplete(int);
method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
method @Deprecated public int getDeviceOwnerType(@NonNull android.content.ComponentName);
method @Nullable public String getDevicePolicyManagementRoleHolderUpdaterPackage();
method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
- method @FlaggedApi("android.app.admin.flags.headless_device_owner_provisioning_fix_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int getHeadlessDeviceOwnerMode();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int getHeadlessDeviceOwnerMode();
method public long getLastBugReportRequestTime();
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.Manifest.permission.MANAGE_DEVICE_ADMINS) public java.util.Set<java.lang.String> getPolicyExemptApps();
- method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_internal_bug_fix_enabled") @RequiresPermission("android.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT") public int getPolicySizeForAdmin(@NonNull android.app.admin.EnforcingAdmin);
+ method @RequiresPermission("android.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT") public int getPolicySizeForAdmin(@NonNull android.app.admin.EnforcingAdmin);
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isNewUserDisclaimerAcknowledged();
@@ -680,7 +680,7 @@
}
public final class EnforcingAdmin implements android.os.Parcelable {
- ctor @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_internal_bug_fix_enabled") public EnforcingAdmin(@NonNull String, @NonNull android.app.admin.Authority, @NonNull android.os.UserHandle, @Nullable android.content.ComponentName);
+ ctor public EnforcingAdmin(@NonNull String, @NonNull android.app.admin.Authority, @NonNull android.os.UserHandle, @Nullable android.content.ComponentName);
}
public final class FlagUnion extends android.app.admin.ResolutionMechanism<java.lang.Integer> {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 8b3ee24..e44e776 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -31,6 +31,7 @@
import android.app.ambientcontext.AmbientContextManager;
import android.app.ambientcontext.IAmbientContextManager;
import android.app.appfunctions.AppFunctionManager;
+import android.app.appfunctions.AppFunctionManagerConfiguration;
import android.app.appfunctions.IAppFunctionManager;
import android.app.appsearch.AppSearchManagerFrameworkInitializer;
import android.app.blob.BlobStoreManagerFrameworkInitializer;
@@ -937,8 +938,10 @@
@Override
public AppFunctionManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
+ if (!AppFunctionManagerConfiguration.isSupported(ctx)) {
+ return null;
+ }
IAppFunctionManager service;
- //TODO(b/357551503): If the feature not present avoid look up every time
service = IAppFunctionManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.APP_FUNCTION_SERVICE));
return new AppFunctionManager(service, ctx.getOuterContext());
diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java
index 02e492b..515c1c6 100644
--- a/core/java/android/app/admin/AccountTypePolicyKey.java
+++ b/core/java/android/app/admin/AccountTypePolicyKey.java
@@ -24,7 +24,6 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.admin.flags.Flags;
import android.os.Bundle;
import android.os.Parcel;
@@ -54,9 +53,7 @@
@TestApi
public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {
super(key);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxStringLength(accountType, "accountType");
- }
+ PolicySizeVerifier.enforceMaxStringLength(accountType, "accountType");
mAccountType = Objects.requireNonNull((accountType));
}
diff --git a/core/java/android/app/admin/BundlePolicyValue.java b/core/java/android/app/admin/BundlePolicyValue.java
index c993671..00e67e6 100644
--- a/core/java/android/app/admin/BundlePolicyValue.java
+++ b/core/java/android/app/admin/BundlePolicyValue.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.flags.Flags;
import android.os.Bundle;
import android.os.Parcel;
@@ -31,9 +30,7 @@
public BundlePolicyValue(Bundle value) {
super(value);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxBundleFieldsLength(value);
- }
+ PolicySizeVerifier.enforceMaxBundleFieldsLength(value);
}
private BundlePolicyValue(Parcel source) {
diff --git a/core/java/android/app/admin/ComponentNamePolicyValue.java b/core/java/android/app/admin/ComponentNamePolicyValue.java
index a7a2f7d..f092b7b 100644
--- a/core/java/android/app/admin/ComponentNamePolicyValue.java
+++ b/core/java/android/app/admin/ComponentNamePolicyValue.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.flags.Flags;
import android.content.ComponentName;
import android.os.Parcel;
@@ -31,9 +30,7 @@
public ComponentNamePolicyValue(@NonNull ComponentName value) {
super(value);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxComponentNameLength(value);
- }
+ PolicySizeVerifier.enforceMaxComponentNameLength(value);
}
private ComponentNamePolicyValue(Parcel source) {
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
index 156512a..c0e435c 100644
--- a/core/java/android/app/admin/DevicePolicyIdentifiers.java
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -16,8 +16,6 @@
package android.app.admin;
-import static android.app.admin.flags.Flags.FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED;
-
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
@@ -185,13 +183,11 @@
/**
* String identifier for {@link DevicePolicyManager#setUsbDataSignalingEnabled}.
*/
- @FlaggedApi(FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
public static final String USB_DATA_SIGNALING_POLICY = "usbDataSignaling";
/**
* String identifier for {@link DevicePolicyManager#setRequiredPasswordComplexity}.
*/
- @FlaggedApi(FLAG_POLICY_ENGINE_MIGRATION_V2_ENABLED)
public static final String PASSWORD_COMPLEXITY_POLICY = "passwordComplexity";
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d31d8f2..0f54cb7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -54,10 +54,8 @@
import static android.Manifest.permission.SET_TIME;
import static android.Manifest.permission.SET_TIME_ZONE;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
-import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
-import static android.app.admin.flags.Flags.FLAG_HEADLESS_DEVICE_OWNER_PROVISIONING_FIX_ENABLED;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
import static android.app.admin.flags.Flags.onboardingConsentlessBugreports;
import static android.app.admin.flags.Flags.FLAG_IS_MTE_POLICY_ENFORCED;
@@ -10478,10 +10476,6 @@
@WorkerThread
public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName,
Bundle settings) {
- if (!Flags.dmrhSetAppRestrictions()) {
- throwIfParentInstance("setApplicationRestrictions");
- }
-
if (mService != null) {
try {
mService.setApplicationRestrictions(admin, mContext.getPackageName(), packageName,
@@ -11886,9 +11880,6 @@
@WorkerThread
public @NonNull Bundle getApplicationRestrictions(
@Nullable ComponentName admin, String packageName) {
- if (!Flags.dmrhSetAppRestrictions()) {
- throwIfParentInstance("getApplicationRestrictions");
- }
if (mService != null) {
try {
@@ -14233,21 +14224,11 @@
*/
public @NonNull DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) {
throwIfParentInstance("getParentProfileInstance");
- try {
- if (Flags.dmrhSetAppRestrictions()) {
- UserManager um = mContext.getSystemService(UserManager.class);
- if (!um.isManagedProfile()) {
- throw new SecurityException("The current user does not have a parent profile.");
- }
- } else {
- if (!mService.isManagedProfile(admin)) {
- throw new SecurityException("The current user does not have a parent profile.");
- }
- }
- return new DevicePolicyManager(mContext, mService, true);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ UserManager um = mContext.getSystemService(UserManager.class);
+ if (!um.isManagedProfile()) {
+ throw new SecurityException("The current user does not have a parent profile.");
}
+ return new DevicePolicyManager(mContext, mService, true);
}
/**
@@ -17809,7 +17790,6 @@
*/
@TestApi
@RequiresPermission(permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT)
- @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED)
public void forceSetMaxPolicyStorageLimit(int storageLimit) {
if (mService != null) {
try {
@@ -17827,7 +17807,6 @@
*/
@TestApi
@RequiresPermission(permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT)
- @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED)
public int getPolicySizeForAdmin(@NonNull EnforcingAdmin admin) {
if (mService != null) {
try {
@@ -17846,13 +17825,9 @@
* @hide
*/
@TestApi
- @FlaggedApi(FLAG_HEADLESS_DEVICE_OWNER_PROVISIONING_FIX_ENABLED)
@RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
@DeviceAdminInfo.HeadlessDeviceOwnerMode
public int getHeadlessDeviceOwnerMode() {
- if (!Flags.headlessDeviceOwnerProvisioningFixEnabled()) {
- return HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
- }
if (mService != null) {
try {
return mService.getHeadlessDeviceOwnerMode(mContext.getPackageName());
diff --git a/core/java/android/app/admin/EnforcingAdmin.java b/core/java/android/app/admin/EnforcingAdmin.java
index f70a53f..5f9bb9c 100644
--- a/core/java/android/app/admin/EnforcingAdmin.java
+++ b/core/java/android/app/admin/EnforcingAdmin.java
@@ -16,9 +16,6 @@
package android.app.admin;
-import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED;
-
-import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -64,7 +61,6 @@
*
* @hide
*/
- @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED)
@TestApi
public EnforcingAdmin(
@NonNull String packageName, @NonNull Authority authority,
diff --git a/core/java/android/app/admin/LockTaskPolicy.java b/core/java/android/app/admin/LockTaskPolicy.java
index 68b4ad8..ab32d46 100644
--- a/core/java/android/app/admin/LockTaskPolicy.java
+++ b/core/java/android/app/admin/LockTaskPolicy.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.app.admin.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -135,10 +134,8 @@
}
private void setPackagesInternal(Set<String> packages) {
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- for (String p : packages) {
- PolicySizeVerifier.enforceMaxPackageNameLength(p);
- }
+ for (String p : packages) {
+ PolicySizeVerifier.enforceMaxPackageNameLength(p);
}
mPackages = new HashSet<>(packages);
}
diff --git a/core/java/android/app/admin/PackagePermissionPolicyKey.java b/core/java/android/app/admin/PackagePermissionPolicyKey.java
index 1a04f6c..226c576 100644
--- a/core/java/android/app/admin/PackagePermissionPolicyKey.java
+++ b/core/java/android/app/admin/PackagePermissionPolicyKey.java
@@ -25,7 +25,6 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.admin.flags.Flags;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -59,10 +58,8 @@
public PackagePermissionPolicyKey(@NonNull String identifier, @NonNull String packageName,
@NonNull String permissionName) {
super(identifier);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
- PolicySizeVerifier.enforceMaxStringLength(permissionName, "permissionName");
- }
+ PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
+ PolicySizeVerifier.enforceMaxStringLength(permissionName, "permissionName");
mPackageName = Objects.requireNonNull((packageName));
mPermissionName = Objects.requireNonNull((permissionName));
}
diff --git a/core/java/android/app/admin/PackagePolicyKey.java b/core/java/android/app/admin/PackagePolicyKey.java
index 9e31a23..8fa21db 100644
--- a/core/java/android/app/admin/PackagePolicyKey.java
+++ b/core/java/android/app/admin/PackagePolicyKey.java
@@ -24,7 +24,6 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.admin.flags.Flags;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -55,9 +54,7 @@
@TestApi
public PackagePolicyKey(@NonNull String key, @NonNull String packageName) {
super(key);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
- }
+ PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
mPackageName = Objects.requireNonNull((packageName));
}
diff --git a/core/java/android/app/admin/PackageSetPolicyValue.java b/core/java/android/app/admin/PackageSetPolicyValue.java
index 8b253a2..24c50b0 100644
--- a/core/java/android/app/admin/PackageSetPolicyValue.java
+++ b/core/java/android/app/admin/PackageSetPolicyValue.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.flags.Flags;
import android.os.Parcel;
import java.util.HashSet;
@@ -32,10 +31,8 @@
public PackageSetPolicyValue(@NonNull Set<String> value) {
super(value);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- for (String packageName : value) {
- PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
- }
+ for (String packageName : value) {
+ PolicySizeVerifier.enforceMaxPackageNameLength(packageName);
}
}
diff --git a/core/java/android/app/admin/StringPolicyValue.java b/core/java/android/app/admin/StringPolicyValue.java
index 6efe9ad..bb07c23 100644
--- a/core/java/android/app/admin/StringPolicyValue.java
+++ b/core/java/android/app/admin/StringPolicyValue.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.admin.flags.Flags;
import android.os.Parcel;
import java.util.Objects;
@@ -30,9 +29,7 @@
public StringPolicyValue(@NonNull String value) {
super(value);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxStringLength(value, "policyValue");
- }
+ PolicySizeVerifier.enforceMaxStringLength(value, "policyValue");
}
private StringPolicyValue(Parcel source) {
diff --git a/core/java/android/app/admin/UserRestrictionPolicyKey.java b/core/java/android/app/admin/UserRestrictionPolicyKey.java
index 9054287..16cfba4 100644
--- a/core/java/android/app/admin/UserRestrictionPolicyKey.java
+++ b/core/java/android/app/admin/UserRestrictionPolicyKey.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.admin.flags.Flags;
import android.os.Bundle;
import android.os.Parcel;
@@ -45,9 +44,7 @@
@TestApi
public UserRestrictionPolicyKey(@NonNull String identifier, @NonNull String restriction) {
super(identifier);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxStringLength(restriction, "restriction");
- }
+ PolicySizeVerifier.enforceMaxStringLength(restriction, "restriction");
mRestriction = Objects.requireNonNull(restriction);
}
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 29a5048..0319c75 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -4,6 +4,7 @@
package: "android.app.admin.flags"
container: "system"
+# Fully rolled out and must not be used.
flag {
name: "policy_engine_migration_v2_enabled"
is_exported: true
@@ -28,16 +29,6 @@
}
flag {
- name: "device_policy_size_tracking_internal_bug_fix_enabled"
- namespace: "enterprise"
- description: "Bug fix for tracking the total policy size and have a max threshold"
- bug: "281543351"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "onboarding_bugreport_v2_enabled"
is_exported: true
namespace: "enterprise"
@@ -77,13 +68,6 @@
}
flag {
- name: "permission_migration_for_zero_trust_impl_enabled"
- namespace: "enterprise"
- description: "(Implementation) Migrate existing APIs to permission based, and enable DMRH to call them to collect Zero Trust signals."
- bug: "289520697"
-}
-
-flag {
name: "device_theft_api_enabled"
is_exported: true
namespace: "enterprise"
@@ -220,33 +204,6 @@
}
flag {
- name: "headless_device_owner_provisioning_fix_enabled"
- namespace: "enterprise"
- description: "Fix provisioning for single-user headless DO"
- bug: "289515470"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- name: "dmrh_set_app_restrictions"
- namespace: "enterprise"
- description: "Allow DMRH to set application restrictions (both on the profile and the parent)"
- bug: "328758346"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- name: "allow_screen_brightness_control_on_cope"
- namespace: "enterprise"
- description: "Allow COPE admin to control screen brightness and timeout."
- bug: "323894620"
-}
-
-flag {
name: "always_persist_do"
namespace: "enterprise"
description: "Always write device_owners2.xml so that migration flags aren't lost"
@@ -264,16 +221,6 @@
}
flag {
- name: "headless_device_owner_delegate_security_logging_bug_fix"
- namespace: "enterprise"
- description: "Fix delegate security logging for single user headless DO."
- bug: "289515470"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "headless_single_user_bad_device_admin_state_fix"
namespace: "enterprise"
description: "Fix the bad state in DPMS caused by an earlier bug related to the headless single user change"
@@ -294,16 +241,6 @@
}
flag {
- name: "delete_private_space_under_restriction"
- namespace: "enterprise"
- description: "Delete private space if user restriction is set"
- bug: "328758346"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "unmanaged_mode_migration"
namespace: "enterprise"
description: "Migrate APIs for unmanaged mode"
@@ -314,16 +251,6 @@
}
flag {
- name: "headless_single_user_fixes"
- namespace: "enterprise"
- description: "Various fixes for headless single user mode"
- bug: "289515470"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "backup_connected_apps_settings"
namespace: "enterprise"
description: "backup and restore connected work and personal apps user settings across devices"
diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java
index b6240a7..0ee9026 100644
--- a/core/java/android/app/appfunctions/AppFunctionManager.java
+++ b/core/java/android/app/appfunctions/AppFunctionManager.java
@@ -50,8 +50,7 @@
* Creates an instance.
*
* @param mService An interface to the backing service.
- * @param context A {@link Context}.
- *
+ * @param context A {@link Context}.
* @hide
*/
public AppFunctionManager(IAppFunctionManager service, Context context) {
@@ -108,8 +107,8 @@
} catch (RuntimeException e) {
// Ideally shouldn't happen since errors are wrapped into the
// response, but we catch it here for additional safety.
- callback.accept(new ExecuteAppFunctionResponse.Builder(
- getResultCode(e), e.getMessage()).build());
+ callback.accept(ExecuteAppFunctionResponse.newFailure(
+ getResultCode(e), e.getMessage(), /*extras=*/ null));
}
}
});
diff --git a/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java b/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
new file mode 100644
index 0000000..e4784b4
--- /dev/null
+++ b/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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.app.appfunctions;
+
+import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * Represents the system configuration of support for the {@code AppFunctionManager} and
+ * associated systems.
+ *
+ * @hide
+ */
+public class AppFunctionManagerConfiguration {
+ private final Context mContext;
+
+ /**
+ * Constructs a new instance of {@code AppFunctionManagerConfiguration}.
+ * @param context context
+ */
+ public AppFunctionManagerConfiguration(@NonNull final Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Indicates whether the current target is intended to support {@code AppFunctionManager}.
+ * @return {@code true} if supported; otherwise {@code false}
+ */
+ public boolean isSupported() {
+ return enableAppFunctionManager() && !isWatch();
+
+ }
+
+ /**
+ * Indicates whether the current target is intended to support {@code AppFunctionManager}.
+ * @param context context
+ * @return {@code true} if supported; otherwise {@code false}
+ */
+ public static boolean isSupported(@NonNull final Context context) {
+ return new AppFunctionManagerConfiguration(context).isSupported();
+ }
+
+ private boolean isWatch() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+}
diff --git a/core/java/android/app/appfunctions/AppFunctionManagerHelper.java b/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
new file mode 100644
index 0000000..3169f0e
--- /dev/null
+++ b/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2024 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.app.appfunctions;
+
+import static android.app.appfunctions.AppFunctionRuntimeMetadata.PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID;
+import static android.app.appfunctions.AppFunctionRuntimeMetadata.PROPERTY_ENABLED;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_INDEXER_PACKAGE;
+import static android.app.appfunctions.AppFunctionStaticMetadataHelper.STATIC_PROPERTY_ENABLED_BY_DEFAULT;
+import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.GlobalSearchSession;
+import android.app.appsearch.JoinSpec;
+import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchResults;
+import android.app.appsearch.SearchSpec;
+import android.os.OutcomeReceiver;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Helper class containing utilities for {@link AppFunctionManager}.
+ *
+ * @hide
+ */
+@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+public class AppFunctionManagerHelper {
+
+ /**
+ * Returns (through a callback) a boolean indicating whether the app function is enabled.
+ * <p>
+ * This method can only check app functions that are owned by the caller owned by packages
+ * visible to the caller.
+ * <p>
+ * If operation fails, the callback's {@link OutcomeReceiver#onError} is called with errors:
+ * <ul>
+ * <li>{@link IllegalArgumentException}, if the function is not found</li>
+ * <li>{@link SecurityException}, if the caller does not have permission to query the
+ * target package
+ * </li>
+ * </ul>
+ *
+ * @param functionIdentifier the identifier of the app function to check (unique within the
+ * target package) and in most cases, these are automatically
+ * generated by the AppFunctions SDK
+ * @param targetPackage the package name of the app function's owner
+ * @param appSearchExecutor the executor to run the metadata search mechanism through AppSearch
+ * @param callbackExecutor the executor to run the callback
+ * @param callback the callback to receive the function enabled check result
+ * @hide
+ */
+ public static void isAppFunctionEnabled(
+ @NonNull String functionIdentifier,
+ @NonNull String targetPackage,
+ @NonNull AppSearchManager appSearchManager,
+ @NonNull Executor appSearchExecutor,
+ @NonNull @CallbackExecutor Executor callbackExecutor,
+ @NonNull OutcomeReceiver<Boolean, Exception> callback
+ ) {
+ Objects.requireNonNull(functionIdentifier);
+ Objects.requireNonNull(targetPackage);
+ Objects.requireNonNull(appSearchManager);
+ Objects.requireNonNull(appSearchExecutor);
+ Objects.requireNonNull(callbackExecutor);
+ Objects.requireNonNull(callback);
+
+ appSearchManager.createGlobalSearchSession(appSearchExecutor,
+ (searchSessionResult) -> {
+ if (!searchSessionResult.isSuccess()) {
+ callbackExecutor.execute(() ->
+ callback.onError(failedResultToException(searchSessionResult)));
+ return;
+ }
+ try (GlobalSearchSession searchSession = searchSessionResult.getResultValue()) {
+ SearchResults results = searchJoinedStaticWithRuntimeAppFunctions(
+ searchSession, targetPackage, functionIdentifier);
+ results.getNextPage(appSearchExecutor,
+ listAppSearchResult -> callbackExecutor.execute(() -> {
+ if (listAppSearchResult.isSuccess()) {
+ callback.onResult(getEnabledStateFromSearchResults(
+ Objects.requireNonNull(
+ listAppSearchResult.getResultValue())));
+ } else {
+ callback.onError(
+ failedResultToException(listAppSearchResult));
+ }
+ }));
+ } catch (Exception e) {
+ callbackExecutor.execute(() -> callback.onError(e));
+ }
+ });
+ }
+
+ /**
+ * Searches joined app function static and runtime metadata using the function Id and the
+ * package.
+ *
+ * @hide
+ */
+ private static @NonNull SearchResults searchJoinedStaticWithRuntimeAppFunctions(
+ @NonNull GlobalSearchSession session,
+ @NonNull String targetPackage,
+ @NonNull String functionIdentifier) {
+ SearchSpec runtimeSearchSpec = getAppFunctionRuntimeMetadataSearchSpecByFunctionId(
+ targetPackage);
+ JoinSpec joinSpec = new JoinSpec.Builder(
+ PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+ .setNestedSearch(
+ functionIdentifier,
+ runtimeSearchSpec).build();
+ SearchSpec joinedStaticWithRuntimeSearchSpec = new SearchSpec.Builder()
+ .setJoinSpec(joinSpec)
+ .addFilterPackageNames(APP_FUNCTION_INDEXER_PACKAGE)
+ .addFilterSchemas(
+ AppFunctionStaticMetadataHelper.getStaticSchemaNameForPackage(
+ targetPackage))
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
+ return session.search(functionIdentifier, joinedStaticWithRuntimeSearchSpec);
+ }
+
+ /**
+ * Finds whether the function is enabled or not from the search results returned by
+ * {@link #searchJoinedStaticWithRuntimeAppFunctions}.
+ *
+ * @throws IllegalArgumentException if the function is not found in the results
+ * @hide
+ */
+ private static boolean getEnabledStateFromSearchResults(
+ @NonNull List<SearchResult> joinedStaticRuntimeResults) {
+ if (joinedStaticRuntimeResults.isEmpty()) {
+ // Function not found.
+ throw new IllegalArgumentException("App function not found.");
+ } else {
+ List<SearchResult> runtimeMetadataResults =
+ joinedStaticRuntimeResults.getFirst().getJoinedResults();
+ if (!runtimeMetadataResults.isEmpty()) {
+ Boolean result = (Boolean) runtimeMetadataResults
+ .getFirst().getGenericDocument()
+ .getProperty(PROPERTY_ENABLED);
+ if (result != null) {
+ return result;
+ }
+ }
+ // Runtime metadata not found. Using the default value in the static metadata.
+ return joinedStaticRuntimeResults.getFirst().getGenericDocument()
+ .getPropertyBoolean(STATIC_PROPERTY_ENABLED_BY_DEFAULT);
+ }
+ }
+
+ /**
+ * Returns search spec that queries app function metadata for a specific package name by its
+ * function identifier.
+ *
+ * @hide
+ */
+ public static @NonNull SearchSpec getAppFunctionRuntimeMetadataSearchSpecByFunctionId(
+ @NonNull String targetPackage) {
+ return new SearchSpec.Builder()
+ .addFilterPackageNames(APP_FUNCTION_INDEXER_PACKAGE)
+ .addFilterSchemas(
+ AppFunctionRuntimeMetadata.getRuntimeSchemaNameForPackage(
+ targetPackage))
+ .addFilterProperties(
+ AppFunctionRuntimeMetadata.getRuntimeSchemaNameForPackage(
+ targetPackage),
+ List.of(AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID))
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
+ }
+
+ /**
+ * Converts a failed app search result codes into an exception.
+ *
+ * @hide
+ */
+ public static @NonNull Exception failedResultToException(
+ @NonNull AppSearchResult appSearchResult) {
+ return switch (appSearchResult.getResultCode()) {
+ case AppSearchResult.RESULT_INVALID_ARGUMENT -> new IllegalArgumentException(
+ appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_IO_ERROR -> new IOException(
+ appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_SECURITY_ERROR -> new SecurityException(
+ appSearchResult.getErrorMessage());
+ default -> new IllegalStateException(appSearchResult.getErrorMessage());
+ };
+ }
+}
diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
new file mode 100644
index 0000000..fdd12b0
--- /dev/null
+++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2024 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.app.appfunctions;
+
+import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.GenericDocument;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * Represents runtime function metadata of an app function.
+ *
+ * <p>This is a temporary solution for app function indexing, as later we would like to index the
+ * actual function signature entity class shape instead of just the schema info.
+ *
+ * @hide
+ */
+// TODO(b/357551503): Link to canonical docs rather than duplicating once they
+// are available.
+@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+public class AppFunctionRuntimeMetadata extends GenericDocument {
+ public static final String RUNTIME_SCHEMA_TYPE = "AppFunctionRuntimeMetadata";
+ public static final String APP_FUNCTION_INDEXER_PACKAGE = "android";
+ public static final String APP_FUNCTION_RUNTIME_METADATA_DB = "appfunctions-db";
+ public static final String APP_FUNCTION_RUNTIME_NAMESPACE = "app_functions_runtime";
+ public static final String PROPERTY_FUNCTION_ID = "functionId";
+ public static final String PROPERTY_PACKAGE_NAME = "packageName";
+ public static final String PROPERTY_ENABLED = "enabled";
+ public static final String PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID =
+ "appFunctionStaticMetadataQualifiedId";
+ private static final String TAG = "AppSearchAppFunction";
+ private static final String RUNTIME_SCHEMA_TYPE_SEPARATOR = "-";
+
+ public AppFunctionRuntimeMetadata(@NonNull GenericDocument genericDocument) {
+ super(genericDocument);
+ }
+
+ /**
+ * Returns a per-app runtime metadata schema name, to store all functions for that package.
+ */
+ public static String getRuntimeSchemaNameForPackage(@NonNull String pkg) {
+ return RUNTIME_SCHEMA_TYPE + RUNTIME_SCHEMA_TYPE_SEPARATOR + Objects.requireNonNull(pkg);
+ }
+
+ /**
+ * Returns the document id for an app function's runtime metadata.
+ */
+ public static String getDocumentIdForAppFunction(
+ @NonNull String pkg, @NonNull String functionId) {
+ return pkg + "/" + functionId;
+ }
+
+ /**
+ * Different packages have different visibility requirements. To allow for different visibility,
+ * we need to have per-package app function schemas.
+ * <p>This schema should be set visible to callers from the package owner itself and for callers
+ * with {@link android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@link
+ * android.permission.EXECUTE_APP_FUNCTIONS} permissions.
+ *
+ * @param packageName The package name to create a schema for.
+ */
+ @NonNull
+ public static AppSearchSchema createAppFunctionRuntimeSchema(@NonNull String packageName) {
+ return new AppSearchSchema.Builder(getRuntimeSchemaNameForPackage(packageName))
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder(PROPERTY_FUNCTION_ID)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig
+ .INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_VERBATIM)
+ .build())
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder(PROPERTY_PACKAGE_NAME)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig
+ .INDEXING_TYPE_EXACT_TERMS)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_VERBATIM)
+ .build())
+ .addProperty(
+ new AppSearchSchema.BooleanPropertyConfig.Builder(PROPERTY_ENABLED)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .build())
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder(
+ PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setJoinableValueType(
+ AppSearchSchema.StringPropertyConfig
+ .JOINABLE_VALUE_TYPE_QUALIFIED_ID)
+ .build())
+ .addParentType(RUNTIME_SCHEMA_TYPE)
+ .build();
+ }
+
+ /**
+ * Returns the function id. This might look like "com.example.message#send_message".
+ */
+ @NonNull
+ public String getFunctionId() {
+ return Objects.requireNonNull(getPropertyString(PROPERTY_FUNCTION_ID));
+ }
+
+ /**
+ * Returns the package name of the package that owns this function.
+ */
+ @NonNull
+ public String getPackageName() {
+ return Objects.requireNonNull(getPropertyString(PROPERTY_PACKAGE_NAME));
+ }
+
+ /**
+ * Returns if the function is set to be enabled or not. If not set, the {@link
+ * AppFunctionStaticMetadataHelper#STATIC_PROPERTY_ENABLED_BY_DEFAULT} value would be used.
+ */
+ @Nullable
+ public Boolean getEnabled() {
+ return (Boolean) getProperty(PROPERTY_ENABLED);
+ }
+
+ /**
+ * Returns the qualified id linking to the static metadata of the app function.
+ */
+ @Nullable
+ @VisibleForTesting
+ public String getAppFunctionStaticMetadataQualifiedId() {
+ return getPropertyString(PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID);
+ }
+
+ public static final class Builder extends GenericDocument.Builder<Builder> {
+ /**
+ * Creates a Builder for a {@link AppFunctionRuntimeMetadata}.
+ *
+ * @param packageName the name of the package that owns the function.
+ * @param functionId the id of the function.
+ * @param staticMetadataQualifiedId the qualified static metadata id that this runtime
+ * metadata refers to.
+ */
+ public Builder(
+ @NonNull String packageName,
+ @NonNull String functionId,
+ @NonNull String staticMetadataQualifiedId) {
+ super(
+ APP_FUNCTION_RUNTIME_NAMESPACE,
+ getDocumentIdForAppFunction(
+ Objects.requireNonNull(packageName),
+ Objects.requireNonNull(functionId)),
+ getRuntimeSchemaNameForPackage(packageName));
+ setPropertyString(PROPERTY_PACKAGE_NAME, packageName);
+ setPropertyString(PROPERTY_FUNCTION_ID, functionId);
+
+ // Set qualified id automatically
+ setPropertyString(
+ PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID,
+ staticMetadataQualifiedId);
+ }
+
+
+ /**
+ * Sets an indicator specifying if the function is enabled or not. This would override the
+ * default enabled state in the static metadata ({@link
+ * AppFunctionStaticMetadataHelper#STATIC_PROPERTY_ENABLED_BY_DEFAULT}).
+ */
+ @NonNull
+ public Builder setEnabled(boolean enabled) {
+ setPropertyBoolean(PROPERTY_ENABLED, enabled);
+ return this;
+ }
+
+ /**
+ * Creates the {@link AppFunctionRuntimeMetadata} GenericDocument.
+ */
+ @NonNull
+ public AppFunctionRuntimeMetadata build() {
+ return new AppFunctionRuntimeMetadata(super.build());
+ }
+ }
+}
diff --git a/core/java/android/app/appfunctions/AppFunctionService.java b/core/java/android/app/appfunctions/AppFunctionService.java
index 6259d16..22bc908 100644
--- a/core/java/android/app/appfunctions/AppFunctionService.java
+++ b/core/java/android/app/appfunctions/AppFunctionService.java
@@ -81,8 +81,9 @@
// Apps should handle exceptions. But if they don't, report the error on
// behalf of them.
safeCallback.onResult(
- new ExecuteAppFunctionResponse.Builder(
- getResultCode(ex), getExceptionMessage(ex)).build());
+ ExecuteAppFunctionResponse.newFailure(
+ getResultCode(ex),
+ ex.getMessage(), /*extras=*/ null));
}
}
};
@@ -117,8 +118,4 @@
public abstract void onExecuteFunction(
@NonNull ExecuteAppFunctionRequest request,
@NonNull Consumer<ExecuteAppFunctionResponse> callback);
-
- private String getExceptionMessage(Exception exception) {
- return exception.getMessage() == null ? "" : exception.getMessage();
- }
}
diff --git a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
new file mode 100644
index 0000000..6d4172a
--- /dev/null
+++ b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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.app.appfunctions;
+
+import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.app.appsearch.util.DocumentIdUtil;
+
+import java.util.Objects;
+
+/**
+ * Contains constants and helper related to static metadata represented with {@code
+ * com.android.server.appsearch.appsindexer.appsearchtypes.AppFunctionStaticMetadata}.
+ * <p>
+ * The constants listed here **must not change** and be kept consistent with the canonical
+ * static metadata class.
+ *
+ * @hide
+ */
+@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+public class AppFunctionStaticMetadataHelper {
+ public static final String STATIC_SCHEMA_TYPE = "AppFunctionStaticMetadata";
+ public static final String STATIC_PROPERTY_ENABLED_BY_DEFAULT = "enabledByDefault";
+
+ public static final String APP_FUNCTION_STATIC_NAMESPACE = "app_functions";
+
+ // These are constants that has to be kept the same with {@code
+ // com.android.server.appsearch.appsindexer.appsearchtypes.AppSearchHelper}.
+ public static final String APP_FUNCTION_STATIC_METADATA_DB = "apps-db";
+ public static final String APP_FUNCTION_INDEXER_PACKAGE = "android";
+
+ /**
+ * Returns a per-app static metadata schema name, to store all functions for that package.
+ */
+ public static String getStaticSchemaNameForPackage(@NonNull String pkg) {
+ return STATIC_SCHEMA_TYPE + "-" + Objects.requireNonNull(pkg);
+ }
+
+ /** Returns the document id for an app function's static metadata. */
+ public static String getDocumentIdForAppFunction(
+ @NonNull String pkg, @NonNull String functionId) {
+ return pkg + "/" + functionId;
+ }
+
+ /**
+ * Returns the fully qualified Id used in AppSearch for the given package and function id
+ * app function static metadata.
+ */
+ public static String getStaticMetadataQualifiedId(String packageName, String functionId) {
+ return DocumentIdUtil.createQualifiedId(
+ APP_FUNCTION_INDEXER_PACKAGE,
+ APP_FUNCTION_STATIC_METADATA_DB,
+ APP_FUNCTION_STATIC_NAMESPACE,
+ getDocumentIdForAppFunction(packageName, functionId));
+ }
+}
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
index 9fb3375..58d4088 100644
--- a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
@@ -162,6 +162,55 @@
}
/**
+ * Returns a successful response.
+ *
+ * @param resultDocument The return value of the executed function.
+ * @param extras The additional metadata data relevant to this function execution
+ * response.
+ */
+ @NonNull
+ @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+ public static ExecuteAppFunctionResponse newSuccess(@NonNull GenericDocument resultDocument,
+ @Nullable Bundle extras) {
+ Objects.requireNonNull(resultDocument);
+ Bundle actualExtras = getActualExtras(extras);
+ GenericDocumentWrapper resultDocumentWrapper = new GenericDocumentWrapper(resultDocument);
+
+ return new ExecuteAppFunctionResponse(
+ resultDocumentWrapper, actualExtras, RESULT_OK, /*errorMessage=*/null);
+ }
+
+ /**
+ * Returns a failure response.
+ *
+ * @param resultCode The result code of the app function execution.
+ * @param extras The additional metadata data relevant to this function execution
+ * response.
+ * @param errorMessage The error message associated with the result, if any.
+ */
+ @NonNull
+ @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+ public static ExecuteAppFunctionResponse newFailure(@ResultCode int resultCode,
+ @Nullable String errorMessage,
+ @Nullable Bundle extras) {
+ if (resultCode == RESULT_OK) {
+ throw new IllegalArgumentException("resultCode must not be RESULT_OK");
+ }
+ Bundle actualExtras = getActualExtras(extras);
+ GenericDocumentWrapper emptyWrapper = new GenericDocumentWrapper(
+ new GenericDocument.Builder<>("", "", "").build());
+ return new ExecuteAppFunctionResponse(
+ emptyWrapper, actualExtras, resultCode, errorMessage);
+ }
+
+ private static Bundle getActualExtras(@Nullable Bundle extras) {
+ if (extras == null) {
+ return Bundle.EMPTY;
+ }
+ return extras;
+ }
+
+ /**
* Returns a generic document containing the return value of the executed function.
*
* <p>The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value.</p>
@@ -250,64 +299,4 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ResultCode {
}
-
- /**
- * The builder for creating {@link ExecuteAppFunctionResponse} instances.
- */
- @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
- public static final class Builder {
- @NonNull
- private GenericDocument mResultDocument =
- new GenericDocument.Builder<>("", "", "").build();
- @NonNull
- private Bundle mExtras = Bundle.EMPTY;
- private int mResultCode;
- @Nullable
- private String mErrorMessage;
-
- /**
- * Creates a new builder for {@link ExecuteAppFunctionResponse}.
- */
- private Builder() {
- }
-
- /**
- * Creates a new builder for {@link ExecuteAppFunctionResponse} to build a success response
- * with a result code of {@link #RESULT_OK} and a resultDocument.
- */
- public Builder(@NonNull GenericDocument resultDocument) {
- Objects.requireNonNull(resultDocument);
- mResultDocument = resultDocument;
- mResultCode = RESULT_OK;
- }
-
- /**
- * Creates a new builder for {@link ExecuteAppFunctionResponse} to build an error response
- * with a result code and an error message.
- */
- public Builder(@ResultCode int resultCode,
- @NonNull String errorMessage) {
- mResultCode = resultCode;
- mErrorMessage = Objects.requireNonNull(errorMessage);
- }
-
- /**
- * Sets the extras of the app function execution.
- */
- @NonNull
- public Builder setExtras(@NonNull Bundle extras) {
- mExtras = Objects.requireNonNull(extras);
- return this;
- }
-
- /**
- * Builds the {@link ExecuteAppFunctionResponse} instance.
- */
- @NonNull
- public ExecuteAppFunctionResponse build() {
- return new ExecuteAppFunctionResponse(
- new GenericDocumentWrapper(mResultDocument),
- mExtras, mResultCode, mErrorMessage);
- }
- }
}
diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig
index ee9114f..93d62cf 100644
--- a/core/java/android/companion/flags.aconfig
+++ b/core/java/android/companion/flags.aconfig
@@ -10,13 +10,6 @@
}
flag {
- name: "companion_transport_apis"
- namespace: "companion"
- description: "Grants access to the companion transport apis."
- bug: "288297505"
-}
-
-flag {
name: "association_tag"
is_exported: true
namespace: "companion"
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index d7a517a..ffed536 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -629,11 +629,10 @@
* A builder for {@link AttributionSource}
*/
public static final class Builder {
+ private boolean mHasBeenUsed;
private @NonNull final AttributionSourceState mAttributionSourceState =
new AttributionSourceState();
- private long mBuilderFieldsSet = 0L;
-
/**
* Creates a new Builder.
*
@@ -642,8 +641,17 @@
*/
public Builder(int uid) {
mAttributionSourceState.uid = uid;
+ mAttributionSourceState.pid = Process.INVALID_PID;
+ mAttributionSourceState.deviceId = Context.DEVICE_ID_DEFAULT;
+ mAttributionSourceState.token = sDefaultToken;
}
+ /**
+ * Creates a builder that is ready to build a new {@link AttributionSource} where
+ * all fields (primitive, immutable data, pointers) are copied from the given
+ * {@link AttributionSource}. Builder methods can still be used to mutate fields further.
+ * @param current The source to copy fields from.
+ */
public Builder(@NonNull AttributionSource current) {
if (current == null) {
throw new IllegalArgumentException("current AttributionSource can not be null");
@@ -652,10 +660,11 @@
mAttributionSourceState.pid = current.getPid();
mAttributionSourceState.packageName = current.getPackageName();
mAttributionSourceState.attributionTag = current.getAttributionTag();
- mAttributionSourceState.token = current.getToken();
mAttributionSourceState.renouncedPermissions =
current.mAttributionSourceState.renouncedPermissions;
- mBuilderFieldsSet |= 0x2 | 0x4 | 0x8 | 0x10;
+ mAttributionSourceState.deviceId = current.getDeviceId();
+ mAttributionSourceState.next = current.mAttributionSourceState.next;
+ mAttributionSourceState.token = current.getToken();
}
/**
@@ -667,7 +676,6 @@
*/
public @NonNull Builder setPid(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x2;
mAttributionSourceState.pid = value;
return this;
}
@@ -677,7 +685,6 @@
*/
public @NonNull Builder setPackageName(@Nullable String value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x4;
mAttributionSourceState.packageName = value;
return this;
}
@@ -687,7 +694,6 @@
*/
public @NonNull Builder setAttributionTag(@Nullable String value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x8;
mAttributionSourceState.attributionTag = value;
return this;
}
@@ -718,11 +724,11 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
- public @NonNull Builder setRenouncedPermissions(@Nullable Set<String> value) {
+ public @NonNull Builder setRenouncedPermissions(
+ @Nullable Set<String> renouncedPermissions) {
checkNotUsed();
- mBuilderFieldsSet |= 0x10;
- mAttributionSourceState.renouncedPermissions = (value != null)
- ? value.toArray(new String[0]) : null;
+ mAttributionSourceState.renouncedPermissions = (renouncedPermissions != null)
+ ? renouncedPermissions.toArray(new String[0]) : null;
return this;
}
@@ -735,7 +741,6 @@
@FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
public @NonNull Builder setDeviceId(int deviceId) {
checkNotUsed();
- mBuilderFieldsSet |= 0x20;
mAttributionSourceState.deviceId = deviceId;
return this;
}
@@ -745,7 +750,6 @@
*/
public @NonNull Builder setNext(@Nullable AttributionSource value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x40;
mAttributionSourceState.next = (value != null) ? new AttributionSourceState[]
{value.mAttributionSourceState} : mAttributionSourceState.next;
return this;
@@ -760,7 +764,6 @@
if (value == null) {
throw new IllegalArgumentException("Null AttributionSource not permitted.");
}
- mBuilderFieldsSet |= 0x40;
mAttributionSourceState.next =
new AttributionSourceState[]{value.mAttributionSourceState};
return this;
@@ -769,28 +772,7 @@
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull AttributionSource build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x80; // Mark builder used
-
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mAttributionSourceState.pid = Process.INVALID_PID;
- }
- if ((mBuilderFieldsSet & 0x4) == 0) {
- mAttributionSourceState.packageName = null;
- }
- if ((mBuilderFieldsSet & 0x8) == 0) {
- mAttributionSourceState.attributionTag = null;
- }
- if ((mBuilderFieldsSet & 0x10) == 0) {
- mAttributionSourceState.renouncedPermissions = null;
- }
- if ((mBuilderFieldsSet & 0x20) == 0) {
- mAttributionSourceState.deviceId = Context.DEVICE_ID_DEFAULT;
- }
- if ((mBuilderFieldsSet & 0x40) == 0) {
- mAttributionSourceState.next = null;
- }
-
- mAttributionSourceState.token = sDefaultToken;
+ mHasBeenUsed = true;
if (mAttributionSourceState.next == null) {
// The NDK aidl backend doesn't support null parcelable arrays.
@@ -800,7 +782,7 @@
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x80) != 0) {
+ if (mHasBeenUsed) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
diff --git a/core/java/android/hardware/display/BrightnessInfo.java b/core/java/android/hardware/display/BrightnessInfo.java
index 109b0a8..6a96a54 100644
--- a/core/java/android/hardware/display/BrightnessInfo.java
+++ b/core/java/android/hardware/display/BrightnessInfo.java
@@ -158,6 +158,8 @@
return "thermal";
case BRIGHTNESS_MAX_REASON_POWER_IC:
return "power IC";
+ case BRIGHTNESS_MAX_REASON_WEAR_BEDTIME_MODE:
+ return "wear bedtime";
}
return "invalid";
}
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 03cf7c5..2a36238 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -567,7 +567,7 @@
Objects.requireNonNull(listener, "listener must not be null");
synchronized (mOnTabletModeChangedListeners) {
- if (mOnTabletModeChangedListeners == null) {
+ if (mOnTabletModeChangedListeners.isEmpty()) {
initializeTabletModeListenerLocked();
}
int idx = findOnTabletModeChangedListenerLocked(listener);
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index bfff4db..9f3e3ad 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -29,6 +29,7 @@
import static java.util.Objects.requireNonNull;
import android.annotation.ElapsedRealtimeLong;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -874,10 +875,9 @@
/*****************************************************************************
* A GenericSoundModel is a specialized {@link SoundModel} for non-voice sound
* patterns.
- *
- * @hide
****************************************************************************/
- public static class GenericSoundModel extends SoundModel implements Parcelable {
+ @FlaggedApi(android.media.soundtrigger.Flags.FLAG_GENERIC_MODEL_API)
+ public static final class GenericSoundModel extends SoundModel implements Parcelable {
public static final @android.annotation.NonNull Parcelable.Creator<GenericSoundModel> CREATOR
= new Parcelable.Creator<GenericSoundModel>() {
@@ -890,11 +890,26 @@
}
};
+ /**
+ * Constructor for {@link GenericSoundModel} with version.
+ *
+ * @param uuid Unique identifier for this sound model.
+ * @param vendorUuid Unique vendor identifier for this sound model.
+ * @param data Opaque data for this sound model.
+ * @param version Vendor-specific version number of this sound model.
+ */
public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
@Nullable byte[] data, int version) {
super(uuid, vendorUuid, TYPE_GENERIC_SOUND, data, version);
}
+ /**
+ * Constructor for {@link GenericSoundModel} without version. The version is set to -1.
+ *
+ * @param uuid Unique identifier for this sound model.
+ * @param vendorUuid Unique vendor identifier for this sound model.
+ * @param data Opaque data for this sound model.
+ */
@UnsupportedAppUsage
public GenericSoundModel(@NonNull UUID uuid, @NonNull UUID vendorUuid,
@Nullable byte[] data) {
@@ -919,7 +934,7 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(getUuid().toString());
if (getVendorUuid() == null) {
dest.writeInt(-1);
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 92b630f..80f39bf 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -46,13 +46,13 @@
* a {@link Message} object containing a bundle of data that will be
* processed by the Handler's {@link #handleMessage} method (requiring that
* you implement a subclass of Handler).
- *
+ *
* <p>When posting or sending to a Handler, you can either
* allow the item to be processed as soon as the message queue is ready
* to do so, or specify a delay before it gets processed or absolute time for
* it to be processed. The latter two allow you to implement timeouts,
* ticks, and other timing-based behavior.
- *
+ *
* <p>When a
* process is created for your application, its main thread is dedicated to
* running a message queue that takes care of managing the top-level
@@ -85,13 +85,13 @@
*/
boolean handleMessage(@NonNull Message msg);
}
-
+
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
-
+
/**
* Handle system messages here.
*/
@@ -343,8 +343,8 @@
* The default implementation will either return the class name of the
* message callback if any, or the hexadecimal representation of the
* message "what" field.
- *
- * @param message The message whose name is being queried
+ *
+ * @param message The message whose name is being queried
*/
@NonNull
public String getMessageName(@NonNull Message message) {
@@ -367,7 +367,7 @@
/**
* Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
- *
+ *
* @param what Value to assign to the returned Message.what field.
* @return A Message from the global message pool.
*/
@@ -376,12 +376,12 @@
{
return Message.obtain(this, what);
}
-
+
/**
- *
- * Same as {@link #obtainMessage()}, except that it also sets the what and obj members
+ *
+ * Same as {@link #obtainMessage()}, except that it also sets the what and obj members
* of the returned Message.
- *
+ *
* @param what Value to assign to the returned Message.what field.
* @param obj Value to assign to the returned Message.obj field.
* @return A Message from the global message pool.
@@ -392,7 +392,7 @@
}
/**
- *
+ *
* Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned
* Message.
* @param what Value to assign to the returned Message.what field.
@@ -405,10 +405,10 @@
{
return Message.obtain(this, what, arg1, arg2);
}
-
+
/**
- *
- * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the
+ *
+ * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the
* returned Message.
* @param what Value to assign to the returned Message.what field.
* @param arg1 Value to assign to the returned Message.arg1 field.
@@ -423,19 +423,19 @@
/**
* Causes the Runnable r to be added to the message queue.
- * The runnable will be run on the thread to which this handler is
- * attached.
- *
+ * The runnable will be run on the thread to which this handler is
+ * attached.
+ *
* @param r The Runnable that will be executed.
- *
- * @return Returns true if the Runnable was successfully placed in to the
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
-
+
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
@@ -446,8 +446,8 @@
* @param r The Runnable that will be executed.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
- *
- * @return Returns true if the Runnable was successfully placed in to the
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
@@ -457,7 +457,7 @@
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
-
+
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
@@ -470,21 +470,21 @@
* {@link #removeCallbacksAndMessages}.
* @param uptimeMillis The absolute time at which the callback should run,
* using the {@link android.os.SystemClock#uptimeMillis} time-base.
- *
- * @return Returns true if the Runnable was successfully placed in to the
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
- *
+ *
* @see android.os.SystemClock#uptimeMillis
*/
public final boolean postAtTime(
@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
-
+
/**
* Causes the Runnable r to be added to the message queue, to be run
* after the specified amount of time elapses.
@@ -492,12 +492,12 @@
* is attached.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
- *
+ *
* @param r The Runnable that will be executed.
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
- *
- * @return Returns true if the Runnable was successfully placed in to the
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
@@ -507,7 +507,7 @@
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
-
+
/** @hide */
public final boolean postDelayed(Runnable r, int what, long delayMillis) {
return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
@@ -547,10 +547,10 @@
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
- *
+ *
* @param r The Runnable that will be executed.
- *
- * @return Returns true if the message was successfully placed in to the
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
@@ -635,8 +635,8 @@
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
- *
- * @return Returns true if the message was successfully placed in to the
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
@@ -646,8 +646,8 @@
/**
* Sends a Message containing only the what value.
- *
- * @return Returns true if the message was successfully placed in to the
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
@@ -659,9 +659,9 @@
/**
* Sends a Message containing only the what value, to be delivered
* after the specified amount of time elapses.
- * @see #sendMessageDelayed(android.os.Message, long)
- *
- * @return Returns true if the message was successfully placed in to the
+ * @see #sendMessageDelayed(android.os.Message, long)
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
@@ -672,11 +672,11 @@
}
/**
- * Sends a Message containing only the what value, to be delivered
+ * Sends a Message containing only the what value, to be delivered
* at a specific time.
* @see #sendMessageAtTime(android.os.Message, long)
- *
- * @return Returns true if the message was successfully placed in to the
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
@@ -691,8 +691,8 @@
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
- *
- * @return Returns true if the message was successfully placed in to the
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
@@ -713,12 +713,12 @@
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
- *
+ *
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
- *
- * @return Returns true if the message was successfully placed in to the
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
@@ -743,8 +743,8 @@
* <b>This method is only for use in very special circumstances -- it
* can easily starve the message queue, cause ordering problems, or have
* other unexpected side-effects.</b>
- *
- * @return Returns true if the message was successfully placed in to the
+ *
+ * @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
@@ -798,6 +798,12 @@
/**
* Remove any pending posts of messages with code 'what' that are in the
* message queue.
+ *
+ * Note that `Message#what` is 0 unless otherwise set.
+ * When calling `postMessage(Runnable)` or `postAtTime(Runnable, long)`,
+ * the `Runnable` is internally wrapped with a `Message` whose `what` is 0.
+ * Calling `removeMessages(0)` will remove all messages without a `what`,
+ * including posted `Runnable`s.
*/
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
@@ -889,7 +895,7 @@
}
// if we can get rid of this method, the handler need not remember its loop
- // we could instead export a getMessageQueue() method...
+ // we could instead export a getMessageQueue() method...
@NonNull
public final Looper getLooper() {
return mLooper;
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index a1db9be..702fdc2 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -41,6 +41,9 @@
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
+ *
+ * If not specified, this value is 0.
+ * Use values other than 0 to indicate custom message codes.
*/
public int what;
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index c801fabf..46ae9d8 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -379,6 +379,14 @@
private int mReferenceCount;
private MemoryRegistration(int size) {
+ // Round up to the nearest page size
+ final int PAGE_SIZE = OsConstants._SC_PAGE_SIZE;
+ if (PAGE_SIZE > 0) {
+ final int remainder = size % PAGE_SIZE;
+ if (remainder != 0) {
+ size += PAGE_SIZE - remainder;
+ }
+ }
mSize = size;
mReferenceCount = 1;
VMRuntime.getRuntime().registerNativeAllocation(mSize);
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java
index fe536a6..22583ac 100644
--- a/core/java/android/util/Half.java
+++ b/core/java/android/util/Half.java
@@ -19,6 +19,7 @@
import android.annotation.HalfFloat;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import libcore.util.FP16;
@@ -92,6 +93,7 @@
* <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
*/
@SuppressWarnings("SimplifiableIfStatement")
+@RavenwoodKeepWholeClass
public final class Half extends Number implements Comparable<Half> {
/**
* The number of bits used to represent a half-precision float value.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 7c8cd93..7392751 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1307,7 +1307,10 @@
WindowInsetsAnimationControlListener listener,
boolean fromIme, long durationMs, @Nullable Interpolator interpolator,
@AnimationType int animationType, boolean fromPredictiveBack) {
- if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0) {
+ if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0
+ || (fromPredictiveBack && ((mRequestedVisibleTypes & ime()) == 0))) {
+ // abort if insets are uncontrollable or if control request is from predictive back but
+ // there is already a hide anim in progress
listener.onCancelled(null);
return;
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index a4cea33..ab29df3 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1051,6 +1051,52 @@
}
/**
+ * Registers callback for when user initialization has completed.
+ * Does nothing if the same callback is already registered.
+ *
+ * @param callback The callback to be registered
+ * @hide
+ */
+ public void registerUserInitializationCompleteCallback(
+ @NonNull IUserInitializationCompleteCallback callback) {
+ IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.registerUserInitializationCompleteCallback(callback);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while registering userInitializationCompleteCallback. ", re);
+ }
+ }
+
+ /**
+ * Unregisters callback for when user initialization has completed.
+ *
+ * @param callback The callback to be unregistered
+ * @hide
+ */
+ public void unregisterUserInitializationCompleteCallback(
+ @NonNull IUserInitializationCompleteCallback callback) {
+ IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.unregisterUserInitializationCompleteCallback(callback);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG,
+ "Error while unregistering userInitializationCompleteCallback. ", re);
+ }
+ }
+
+ /**
* Whether the current accessibility request comes from an
* {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool}
* property set to true.
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 72a1fe4..bf79a2c 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -29,6 +29,7 @@
import android.view.accessibility.IAccessibilityManagerClient;
import android.view.accessibility.AccessibilityWindowAttributes;
import android.view.accessibility.IMagnificationConnection;
+import android.view.accessibility.IUserInitializationCompleteCallback;
import android.view.InputEvent;
import android.view.IWindow;
import android.view.MagnificationSpec;
@@ -192,4 +193,10 @@
@EnforcePermission("MANAGE_ACCESSIBILITY")
Bundle getA11yFeatureToTileMap(int userId);
+
+ @RequiresNoPermission
+ void registerUserInitializationCompleteCallback(IUserInitializationCompleteCallback callback);
+
+ @RequiresNoPermission
+ void unregisterUserInitializationCompleteCallback(IUserInitializationCompleteCallback callback);
}
diff --git a/core/java/android/view/accessibility/IUserInitializationCompleteCallback.aidl b/core/java/android/view/accessibility/IUserInitializationCompleteCallback.aidl
new file mode 100644
index 0000000..fe6c8e2
--- /dev/null
+++ b/core/java/android/view/accessibility/IUserInitializationCompleteCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.accessibility;
+
+/**
+ * A callback for when a new user finishes initializing
+ * NOTE: Must remain a oneway interface, as it is called from system_server while holding a lock.
+ * oneway allows it to return immediately and not hold the lock for longer than is necessary.
+ * @hide
+ */
+
+oneway interface IUserInitializationCompleteCallback {
+
+ /**
+ * Called when a user initialization completes.
+ *
+ * @param userId the id of the initialized user
+ */
+ @RequiresNoPermission
+ void onUserInitializationComplete(int userId);
+}
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
index 58b5757..b8a11cf0 100644
--- a/core/java/android/window/ITaskFragmentOrganizerController.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -47,6 +47,19 @@
void unregisterOrganizer(in ITaskFragmentOrganizer organizer);
/**
+ * Registers remote animations per transition type for the organizer. It will override the
+ * animations if the transition only contains windows that belong to the organized
+ * TaskFragments in the given Task.
+ */
+ void registerRemoteAnimations(in ITaskFragmentOrganizer organizer,
+ in RemoteAnimationDefinition definition);
+
+ /**
+ * Unregisters remote animations per transition type for the organizer.
+ */
+ void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer);
+
+ /**
* Saves the state in the system, where the state can be restored if the process of
* the TaskFragmentOrganizer is restarted.
*/
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 027d323..4cc0d8a 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -34,6 +34,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
import com.android.window.flags.Flags;
@@ -225,6 +226,34 @@
}
/**
+ * Registers remote animations per transition type for the organizer. It will override the
+ * animations if the transition only contains windows that belong to the organized
+ * TaskFragments, and at least one of the transition window is embedded (not filling the Task).
+ * @hide
+ */
+ @CallSuper
+ public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
+ try {
+ getController().registerRemoteAnimations(mInterface, definition);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters remote animations per transition type for the organizer.
+ * @hide
+ */
+ @CallSuper
+ public void unregisterRemoteAnimations() {
+ try {
+ getController().unregisterRemoteAnimations(mInterface);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Saves the state in the system, where the state can be restored if the process of
* the TaskFragmentOrganizer is restarted.
*
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index e14249c..e0529b3 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -3333,6 +3333,7 @@
Bundle args = new Bundle();
args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, event.getDeviceId());
args.putLong(Intent.EXTRA_TIME, event.getEventTime());
+ args.putBoolean(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD, true);
((SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE))
.launchAssist(args);
return true;
diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java
index f8a1436..1938cdb 100644
--- a/core/java/com/android/internal/statusbar/StatusBarIcon.java
+++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java
@@ -51,6 +51,19 @@
ResourceIcon
}
+ public enum Shape {
+ /**
+ * Icon view should use WRAP_CONTENT -- so that the horizontal space occupied depends on the
+ * icon's shape (skinny/fat icons take less/more). Most icons will want to use this option
+ * for a nicer-looking overall spacing in the status bar, as long as the icon is "known"
+ * (i.e. not coming from a 3P package).
+ */
+ WRAP_CONTENT,
+
+ /** Icon should always be displayed in a space as wide as the status bar is tall. */
+ FIXED_SPACE,
+ }
+
public UserHandle user;
public String pkg;
public Icon icon;
@@ -59,6 +72,7 @@
public int number;
public CharSequence contentDescription;
public Type type;
+ public Shape shape;
/**
* Optional {@link Drawable} corresponding to {@link #icon}. This field is not parcelable, so
@@ -68,7 +82,7 @@
@Nullable public Drawable preloadedIcon;
public StatusBarIcon(UserHandle user, String resPackage, Icon icon, int iconLevel, int number,
- CharSequence contentDescription, Type type) {
+ CharSequence contentDescription, Type type, Shape shape) {
if (icon.getType() == Icon.TYPE_RESOURCE
&& TextUtils.isEmpty(icon.getResPackage())) {
// This is an odd situation where someone's managed to hand us an icon without a
@@ -83,6 +97,13 @@
this.number = number;
this.contentDescription = contentDescription;
this.type = type;
+ this.shape = shape;
+ }
+
+ public StatusBarIcon(UserHandle user, String resPackage, Icon icon, int iconLevel, int number,
+ CharSequence contentDescription, Type type) {
+ this(user, resPackage, icon, iconLevel, number, contentDescription, type,
+ Shape.WRAP_CONTENT);
}
public StatusBarIcon(String iconPackage, UserHandle user,
@@ -107,7 +128,7 @@
@Override
public StatusBarIcon clone() {
StatusBarIcon that = new StatusBarIcon(this.user, this.pkg, this.icon,
- this.iconLevel, this.number, this.contentDescription, this.type);
+ this.iconLevel, this.number, this.contentDescription, this.type, this.shape);
that.visible = this.visible;
that.preloadedIcon = this.preloadedIcon;
return that;
@@ -129,6 +150,7 @@
this.number = in.readInt();
this.contentDescription = in.readCharSequence();
this.type = Type.valueOf(in.readString());
+ this.shape = Shape.valueOf(in.readString());
}
public void writeToParcel(Parcel out, int flags) {
@@ -140,6 +162,7 @@
out.writeInt(this.number);
out.writeCharSequence(this.contentDescription);
out.writeString(this.type.name());
+ out.writeString(this.shape.name());
}
public int describeContents() {
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
index 94bde68..127dbfd 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BATTERY_STATS"/>
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
@@ -31,7 +32,8 @@
<activity android:name=".BatteryConsumerPickerActivity"
android:label="Battery Stats"
android:launchMode="singleTop"
- android:exported="true">
+ android:exported="true"
+ android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -41,5 +43,25 @@
<activity android:name=".BatteryStatsViewerActivity"
android:label="Battery Stats"
android:parentActivityName=".BatteryConsumerPickerActivity"/>
+
+ <activity android:name=".TrampolineActivity"
+ android:exported="true"
+ android:theme="@android:style/Theme.NoDisplay">
+ <intent-filter>
+ <action android:name="com.android.settings.action.IA_SETTINGS"/>
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+
+ <meta-data android:name="com.android.settings.category"
+ android:value="com.android.settings.category.ia.development" />
+ <meta-data android:name="com.android.settings.title"
+ android:resource="@string/settings_title" />
+ <meta-data android:name="com.android.settings.summary"
+ android:resource="@string/settings_summary" />
+ <meta-data android:name="com.android.settings.group_key"
+ android:value="debug_debugging_category" />
+ <meta-data android:name="com.android.settings.order"
+ android:value="2" />
+ </activity>
</application>
</manifest>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/values/strings.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/values/strings.xml
new file mode 100644
index 0000000..c23c148
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/values/strings.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright (C) 2024 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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settings_title">Launch Battery Stats Viewer</string>
+ <string name="settings_summary">The Battery Stats Viewer will be visible in the Launcher after it is opened once.</string>
+</resources>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/TrampolineActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/TrampolineActivity.java
new file mode 100644
index 0000000..b016488
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/TrampolineActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.frameworks.core.batterystatsviewer;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+public class TrampolineActivity extends Activity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ showLauncherIcon();
+ launchMainActivity();
+ }
+
+ private void showLauncherIcon() {
+ PackageManager pm = getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName(this, BatteryConsumerPickerActivity.class),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP);
+ }
+
+ private void launchMainActivity() {
+ startActivity(new Intent(this, BatteryConsumerPickerActivity.class));
+ }
+}
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index ecd2f76..8685326 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -16,8 +16,11 @@
package android.os.storage;
+import android.content.res.ObbInfo;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ProxyFileDescriptorCallback;
+import android.os.ServiceManager;
import android.system.ErrnoException;
import androidx.test.filters.LargeTest;
@@ -104,7 +107,14 @@
public void testMountBadPackageNameObb() throws Exception {
final File file = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename);
String filePath = file.getAbsolutePath();
- mountObb(filePath, OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+ try {
+ mountObb(filePath, OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+ fail("mountObb should have thrown a exception as package name is incorrect");
+ } catch (Exception ex) {
+ assertEquals("Path " + filePath
+ + " does not contain package name " + mContext.getPackageName(),
+ ex.getMessage());
+ }
}
/**
@@ -154,6 +164,48 @@
}
}
+ @LargeTest
+ public void testObbInfo_withValidObbInfo_success() throws Exception {
+ final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String filePath = file.getAbsolutePath();
+ try {
+ mountObb(filePath);
+ unmountObb(filePath, DONT_FORCE);
+ } catch (Exception ex) {
+ fail("No exception expected, got " + ex.getMessage());
+ }
+ }
+
+ @LargeTest
+ public void testObbInfo_withInvalidObbInfo_exception() throws Exception {
+ final File file = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+ String rawPath = file.getAbsolutePath();
+ String canonicalPath = file.getCanonicalPath();
+
+ ObbInfo obbInfo = ObbInfo.CREATOR.createFromParcel(Parcel.obtain());
+ obbInfo.packageName = "com.android.obbcrash";
+ obbInfo.version = 1;
+ obbInfo.filename = canonicalPath;
+
+ try {
+ IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount")).mountObb(
+ rawPath, canonicalPath, new ObbActionListener(), 0, obbInfo);
+ fail("mountObb should have thrown a exception as package name is incorrect");
+ } catch (SecurityException ex) {
+ assertEquals("Path " + canonicalPath
+ + " does not contain package name " + mContext.getPackageName(),
+ ex.getMessage());
+ }
+ }
+
+ private static class ObbActionListener extends IObbActionListener.Stub {
+ @SuppressWarnings("hiding")
+ @Override
+ public void onObbResult(String filename, int nonce, int status) {
+
+ }
+ }
+
private static class MyThreadFactory implements ThreadFactory {
Thread thread = null;
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index ce7e858..22499ae 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -1131,6 +1131,37 @@
});
}
+ @Test
+ public void testPredictiveBackControlRequestCancelledDuringImeHideAnim() {
+ prepareControls();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // show ime as initial state
+ if (!Flags.refactorInsetsController()) {
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
+ } else {
+ mController.show(ime(), false /* fromIme */, ImeTracker.Token.empty());
+ }
+ mController.cancelExistingAnimations(); // fast forward show animation
+ mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
+ assertTrue(mController.getState().peekSource(ID_IME).isVisible());
+
+ // start IME hide animation
+ mController.hide(ime(), true /* fromIme */, null /* statsToken */);
+ assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime()));
+
+ // start control request (for predictive back animation)
+ WindowInsetsAnimationControlListener listener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mController.controlWindowInsetsAnimation(ime(), /*cancellationSignal*/ null,
+ listener, /*fromIme*/ false, /*duration*/ -1, /*interpolator*/ null,
+ ANIMATION_TYPE_USER, /*fromPredictiveBack*/ true);
+
+ // verify that control request is cancelled and animation type remains HIDE
+ verify(listener).onCancelled(any());
+ assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ime()));
+ });
+ }
+
private void waitUntilNextFrame() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java b/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java
index b183ecb..149e132 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java
@@ -20,6 +20,7 @@
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.UserHandle;
@@ -69,22 +70,22 @@
assertThat(copy.preloadedIcon).isEqualTo(original.preloadedIcon);
}
-
private static StatusBarIcon newStatusBarIcon() {
final UserHandle dummyUserHandle = UserHandle.of(100);
final String dummyIconPackageName = "com.android.internal.statusbar.test";
- final int dummyIconId = 123;
+ final Icon dummyIcon = Icon.createWithResource(dummyIconPackageName, 123);
final int dummyIconLevel = 1;
final int dummyIconNumber = 2;
final CharSequence dummyIconContentDescription = "dummyIcon";
return new StatusBarIcon(
- dummyIconPackageName,
dummyUserHandle,
- dummyIconId,
+ dummyIconPackageName,
+ dummyIcon,
dummyIconLevel,
dummyIconNumber,
dummyIconContentDescription,
- StatusBarIcon.Type.SystemIcon);
+ StatusBarIcon.Type.SystemIcon,
+ StatusBarIcon.Shape.FIXED_SPACE);
}
private static void assertSerializableFieldsEqual(StatusBarIcon copy, StatusBarIcon original) {
@@ -96,6 +97,7 @@
assertThat(copy.number).isEqualTo(original.number);
assertThat(copy.contentDescription).isEqualTo(original.contentDescription);
assertThat(copy.type).isEqualTo(original.type);
+ assertThat(copy.shape).isEqualTo(original.shape);
}
private static StatusBarIcon parcelAndUnparcel(StatusBarIcon original) {
diff --git a/data/keyboards/Vendor_0957_Product_0033.idc b/data/keyboards/Vendor_0957_Product_0033.idc
new file mode 100644
index 0000000..7dfbe2c
--- /dev/null
+++ b/data/keyboards/Vendor_0957_Product_0033.idc
@@ -0,0 +1,23 @@
+# Copyright 2024 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.
+#
+
+# Input Device Configuration file for Google Reference RCU Remote.
+# PID 0033 is for new G20 with start button.
+
+# Basic Parameters
+keyboard.layout = Vendor_0957_Product_0031
+# The reason why we set is follow https://docs.partner.android.com/tv/build/gtv/boot-resume
+keyboard.doNotWakeByDefault = 1
+audio.mic = 1
diff --git a/graphics/java/android/graphics/Matrix44.java b/graphics/java/android/graphics/Matrix44.java
index a99e201..683f614 100644
--- a/graphics/java/android/graphics/Matrix44.java
+++ b/graphics/java/android/graphics/Matrix44.java
@@ -19,6 +19,7 @@
import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import com.android.graphics.hwui.flags.Flags;
@@ -30,6 +31,7 @@
* in row-major order. The values and operations are treated as column vectors.
*/
@FlaggedApi(Flags.FLAG_MATRIX_44)
+@RavenwoodKeepWholeClass
public class Matrix44 {
final float[] mBackingArray;
/**
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 618e6dc..c7b8941 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.drawable.Drawable;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -35,6 +36,7 @@
* @see android.view.View#setOutlineProvider(android.view.ViewOutlineProvider)
* @see Drawable#getOutline(Outline)
*/
+@RavenwoodKeepWholeClass
public final class Outline {
private static final float RADIUS_UNDEFINED = Float.NEGATIVE_INFINITY;
diff --git a/graphics/java/android/graphics/ParcelableColorSpace.java b/graphics/java/android/graphics/ParcelableColorSpace.java
index 748d66c..76c17154 100644
--- a/graphics/java/android/graphics/ParcelableColorSpace.java
+++ b/graphics/java/android/graphics/ParcelableColorSpace.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
/**
* A {@link Parcelable} wrapper for a {@link ColorSpace}. In order to enable parceling, the
@@ -27,6 +28,7 @@
* {@link ColorSpace.Rgb} instance that has an ICC parametric transfer function as returned by
* {@link ColorSpace.Rgb#getTransferParameters()}.
*/
+@RavenwoodKeepWholeClass
public final class ParcelableColorSpace implements Parcelable {
private final ColorSpace mColorSpace;
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 3ec5b9c..a872e03 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -17,10 +17,12 @@
package android.graphics;
import android.annotation.IntDef;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+@RavenwoodKeepWholeClass
public class PixelFormat {
/** @hide */
@IntDef({UNKNOWN, TRANSLUCENT, TRANSPARENT, OPAQUE})
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index 1eb95c1..9ea2943 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -70,6 +70,10 @@
@NonNull
private final TaskFragmentCallback mCallback;
+ @VisibleForTesting
+ @Nullable
+ TaskFragmentAnimationController mAnimationController;
+
/**
* Callback that notifies the controller about changes to task fragments.
*/
@@ -87,6 +91,25 @@
mCallback = callback;
}
+ @Override
+ public void unregisterOrganizer() {
+ if (mAnimationController != null) {
+ mAnimationController.unregisterRemoteAnimations();
+ mAnimationController = null;
+ }
+ super.unregisterOrganizer();
+ }
+
+ /**
+ * Overrides the animation for transitions of embedded activities organized by this organizer.
+ */
+ void overrideSplitAnimation() {
+ if (mAnimationController == null) {
+ mAnimationController = new TaskFragmentAnimationController(this);
+ }
+ mAnimationController.registerRemoteAnimations();
+ }
+
/**
* Starts a new Activity and puts it into split with an existing Activity side-by-side.
* @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 24b56ae..5657647 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -116,6 +116,7 @@
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
ActivityEmbeddingComponent, DividerPresenter.DragEventCallback {
static final String TAG = "SplitController";
+ static final boolean ENABLE_SHELL_TRANSITIONS = true;
// TODO(b/243518738): Move to WM Extensions if we have requirement of overlay without
// association. It's not set in WM Extensions nor Wm Jetpack library currently.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 5637320..abc7b29 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -175,6 +175,11 @@
registerOrganizer();
}
mBackupHelper = new BackupHelper(controller, outSavedState);
+ if (!SplitController.ENABLE_SHELL_TRANSITIONS) {
+ // TODO(b/207070762): cleanup with legacy app transition
+ // Animation will be handled by WM Shell when Shell transition is enabled.
+ overrideSplitAnimation();
+ }
}
void scheduleBackup() {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
new file mode 100644
index 0000000..33220c4
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -0,0 +1,224 @@
+/*
+ * 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 androidx.window.extensions.embedding;
+
+import static android.graphics.Matrix.MTRANS_X;
+import static android.graphics.Matrix.MTRANS_Y;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.Choreographer;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Wrapper to handle the TaskFragment animation update in one {@link SurfaceControl.Transaction}.
+ *
+ * The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
+ */
+class TaskFragmentAnimationAdapter {
+
+ /**
+ * If {@link #mOverrideLayer} is set to this value, we don't want to override the surface layer.
+ */
+ private static final int LAYER_NO_OVERRIDE = -1;
+
+ @NonNull
+ final Animation mAnimation;
+ @NonNull
+ final RemoteAnimationTarget mTarget;
+ @NonNull
+ final SurfaceControl mLeash;
+ /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
+ @NonNull
+ private final Rect mWholeAnimationBounds = new Rect();
+ /**
+ * Area in absolute coordinate that should represent all the content to show for this window.
+ * This should be the end bounds for opening window, and start bounds for closing window in case
+ * the window is resizing during the open/close transition.
+ */
+ @NonNull
+ private final Rect mContentBounds = new Rect();
+ /** Offset relative to the window parent surface for {@link #mContentBounds}. */
+ @NonNull
+ private final Point mContentRelOffset = new Point();
+
+ @NonNull
+ final Transformation mTransformation = new Transformation();
+ @NonNull
+ final float[] mMatrix = new float[9];
+ @NonNull
+ final float[] mVecs = new float[4];
+ @NonNull
+ final Rect mRect = new Rect();
+ private boolean mIsFirstFrame = true;
+ private int mOverrideLayer = LAYER_NO_OVERRIDE;
+
+ TaskFragmentAnimationAdapter(@NonNull Animation animation,
+ @NonNull RemoteAnimationTarget target) {
+ this(animation, target, target.leash, target.screenSpaceBounds);
+ }
+
+ /**
+ * @param leash the surface to animate.
+ * @param wholeAnimationBounds area in absolute coordinate that the animation surface shouldn't
+ * go beyond.
+ */
+ TaskFragmentAnimationAdapter(@NonNull Animation animation,
+ @NonNull RemoteAnimationTarget target, @NonNull SurfaceControl leash,
+ @NonNull Rect wholeAnimationBounds) {
+ mAnimation = animation;
+ mTarget = target;
+ mLeash = leash;
+ mWholeAnimationBounds.set(wholeAnimationBounds);
+ if (target.mode == MODE_CLOSING) {
+ // When it is closing, we want to show the content at the start position in case the
+ // window is resizing as well. For example, when the activities is changing from split
+ // to stack, the bottom TaskFragment will be resized to fullscreen when hiding.
+ final Rect startBounds = target.startBounds;
+ final Rect endBounds = target.screenSpaceBounds;
+ mContentBounds.set(startBounds);
+ mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
+ mContentRelOffset.offset(
+ startBounds.left - endBounds.left,
+ startBounds.top - endBounds.top);
+ } else {
+ mContentBounds.set(target.screenSpaceBounds);
+ mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
+ }
+ }
+
+ /**
+ * Surface layer to be set at the first frame of the animation. We will not set the layer if it
+ * is set to {@link #LAYER_NO_OVERRIDE}.
+ */
+ final void overrideLayer(int layer) {
+ mOverrideLayer = layer;
+ }
+
+ /** Called on frame update. */
+ final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
+ if (mIsFirstFrame) {
+ t.show(mLeash);
+ if (mOverrideLayer != LAYER_NO_OVERRIDE) {
+ t.setLayer(mLeash, mOverrideLayer);
+ }
+ mIsFirstFrame = false;
+ }
+
+ // Extract the transformation to the current time.
+ mAnimation.getTransformation(Math.min(currentPlayTime, mAnimation.getDuration()),
+ mTransformation);
+ t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ onAnimationUpdateInner(t);
+ }
+
+ /** To be overridden by subclasses to adjust the animation surface change. */
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ // Update the surface position and alpha.
+ mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+
+ // Get current surface bounds in absolute coordinate.
+ // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
+ final int positionX = Math.round(mMatrix[MTRANS_X]);
+ final int positionY = Math.round(mMatrix[MTRANS_Y]);
+ final Rect cropRect = new Rect(mContentBounds);
+ cropRect.offset(positionX - mContentRelOffset.x, positionY - mContentRelOffset.y);
+
+ // Store the current offset of the surface top left from (0,0) in absolute coordinate.
+ final int offsetX = cropRect.left;
+ final int offsetY = cropRect.top;
+
+ // Intersect to make sure the animation happens within the whole animation bounds.
+ if (!cropRect.intersect(mWholeAnimationBounds)) {
+ // Hide the surface when it is outside of the animation area.
+ t.setAlpha(mLeash, 0);
+ }
+
+ // cropRect is in absolute coordinate, so we need to translate it to surface top left.
+ cropRect.offset(-offsetX, -offsetY);
+ t.setCrop(mLeash, cropRect);
+ }
+
+ /** Called after animation finished. */
+ final void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
+ onAnimationUpdate(t, mAnimation.getDuration());
+ }
+
+ final long getDurationHint() {
+ return mAnimation.computeDurationHint();
+ }
+
+ /**
+ * Should be used for the animation of the snapshot of a {@link RemoteAnimationTarget} that has
+ * size change.
+ */
+ static class SnapshotAdapter extends TaskFragmentAnimationAdapter {
+
+ SnapshotAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
+ // Start leash is the snapshot of the starting surface.
+ super(animation, target, target.startLeash, target.screenSpaceBounds);
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ // Snapshot should always be placed at the top left of the animation leash.
+ mTransformation.getMatrix().postTranslate(0, 0);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+ }
+ }
+
+ /**
+ * Should be used for the animation of the {@link RemoteAnimationTarget} that has size change.
+ */
+ static class BoundsChangeAdapter extends TaskFragmentAnimationAdapter {
+
+ BoundsChangeAdapter(@NonNull Animation animation, @NonNull RemoteAnimationTarget target) {
+ super(animation, target);
+ }
+
+ @Override
+ void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
+ mTransformation.getMatrix().postTranslate(
+ mTarget.localBounds.left, mTarget.localBounds.top);
+ t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
+ t.setAlpha(mLeash, mTransformation.getAlpha());
+
+ // The following applies an inverse scale to the clip-rect so that it crops "after" the
+ // scale instead of before.
+ mVecs[1] = mVecs[2] = 0;
+ mVecs[0] = mVecs[3] = 1;
+ mTransformation.getMatrix().mapVectors(mVecs);
+ mVecs[0] = 1.f / mVecs[0];
+ mVecs[3] = 1.f / mVecs[3];
+ final Rect clipRect = mTransformation.getClipRect();
+ mRect.left = (int) (clipRect.left * mVecs[0] + 0.5f);
+ mRect.right = (int) (clipRect.right * mVecs[0] + 0.5f);
+ mRect.top = (int) (clipRect.top * mVecs[3] + 0.5f);
+ mRect.bottom = (int) (clipRect.bottom * mVecs[3] + 0.5f);
+ t.setWindowCrop(mLeash, mRect);
+ }
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
new file mode 100644
index 0000000..d7eb9a0
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java
@@ -0,0 +1,79 @@
+/*
+ * 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 androidx.window.extensions.embedding;
+
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+
+import android.util.Log;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.window.TaskFragmentOrganizer;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/** Controls the TaskFragment remote animations. */
+class TaskFragmentAnimationController {
+
+ private static final String TAG = "TaskFragAnimationCtrl";
+ static final boolean DEBUG = false;
+
+ private final TaskFragmentOrganizer mOrganizer;
+ private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
+ @VisibleForTesting
+ final RemoteAnimationDefinition mDefinition;
+ private boolean mIsRegistered;
+
+ TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) {
+ mOrganizer = organizer;
+ mDefinition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter animationAdapter =
+ new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */);
+ mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter);
+ mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
+ mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter);
+ mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
+ mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
+ }
+
+ void registerRemoteAnimations() {
+ if (DEBUG) {
+ Log.v(TAG, "registerRemoteAnimations");
+ }
+ if (mIsRegistered) {
+ return;
+ }
+ mOrganizer.registerRemoteAnimations(mDefinition);
+ mIsRegistered = true;
+ }
+
+ void unregisterRemoteAnimations() {
+ if (DEBUG) {
+ Log.v(TAG, "unregisterRemoteAnimations");
+ }
+ if (!mIsRegistered) {
+ return;
+ }
+ mOrganizer.unregisterRemoteAnimations();
+ mIsRegistered = false;
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
new file mode 100644
index 0000000..d9b73a8
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -0,0 +1,309 @@
+/*
+ * 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 androidx.window.extensions.embedding;
+
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.view.RemoteAnimationTarget.MODE_CHANGING;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiFunction;
+
+/** To run the TaskFragment animations. */
+class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
+
+ private static final String TAG = "TaskFragAnimationRunner";
+ private final Handler mHandler;
+ private final TaskFragmentAnimationSpec mAnimationSpec;
+
+ TaskFragmentAnimationRunner() {
+ HandlerThread animationThread = new HandlerThread(
+ "androidx.window.extensions.embedding", THREAD_PRIORITY_DISPLAY);
+ animationThread.start();
+ mHandler = animationThread.getThreadHandler();
+ mAnimationSpec = new TaskFragmentAnimationSpec(mHandler);
+ }
+
+ @Nullable
+ private Animator mAnimator;
+
+ @Override
+ public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+ @NonNull RemoteAnimationTarget[] apps,
+ @NonNull RemoteAnimationTarget[] wallpapers,
+ @NonNull RemoteAnimationTarget[] nonApps,
+ @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
+ if (wallpapers.length != 0 || nonApps.length != 0) {
+ throw new IllegalArgumentException("TaskFragment shouldn't handle animation with"
+ + "wallpaper or non-app windows.");
+ }
+ if (TaskFragmentAnimationController.DEBUG) {
+ Log.v(TAG, "onAnimationStart transit=" + transit);
+ }
+ mHandler.post(() -> startAnimation(transit, apps, finishedCallback));
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ mHandler.post(this::cancelAnimation);
+ }
+
+ /** Creates and starts animation. */
+ private void startAnimation(@WindowManager.TransitionOldType int transit,
+ @NonNull RemoteAnimationTarget[] targets,
+ @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
+ if (mAnimator != null) {
+ Log.w(TAG, "start new animation when the previous one is not finished yet.");
+ mAnimator.cancel();
+ }
+ mAnimator = createAnimator(transit, targets, finishedCallback);
+ mAnimator.start();
+ }
+
+ /** Cancels animation. */
+ private void cancelAnimation() {
+ if (mAnimator == null) {
+ return;
+ }
+ mAnimator.cancel();
+ mAnimator = null;
+ }
+
+ /** Creates the animator given the transition type and windows. */
+ @NonNull
+ private Animator createAnimator(@WindowManager.TransitionOldType int transit,
+ @NonNull RemoteAnimationTarget[] targets,
+ @NonNull IRemoteAnimationFinishedCallback finishedCallback) {
+ final List<TaskFragmentAnimationAdapter> adapters =
+ createAnimationAdapters(transit, targets);
+ long duration = 0;
+ for (TaskFragmentAnimationAdapter adapter : adapters) {
+ duration = Math.max(duration, adapter.getDurationHint());
+ }
+ final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+ animator.setDuration(duration);
+ animator.addUpdateListener((anim) -> {
+ // Update all adapters in the same transaction.
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (TaskFragmentAnimationAdapter adapter : adapters) {
+ adapter.onAnimationUpdate(t, animator.getCurrentPlayTime());
+ }
+ t.apply();
+ });
+ animator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (TaskFragmentAnimationAdapter adapter : adapters) {
+ adapter.onAnimationEnd(t);
+ }
+ t.apply();
+
+ try {
+ finishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ mAnimator = null;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {}
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {}
+ });
+ return animator;
+ }
+
+ /** List of {@link TaskFragmentAnimationAdapter} to handle animations on all window targets. */
+ @NonNull
+ private List<TaskFragmentAnimationAdapter> createAnimationAdapters(
+ @WindowManager.TransitionOldType int transit,
+ @NonNull RemoteAnimationTarget[] targets) {
+ switch (transit) {
+ case TRANSIT_OLD_ACTIVITY_OPEN:
+ case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
+ return createOpenAnimationAdapters(targets);
+ case TRANSIT_OLD_ACTIVITY_CLOSE:
+ case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
+ return createCloseAnimationAdapters(targets);
+ case TRANSIT_OLD_TASK_FRAGMENT_CHANGE:
+ return createChangeAnimationAdapters(targets);
+ default:
+ throw new IllegalArgumentException("Unhandled transit type=" + transit);
+ }
+ }
+
+ @NonNull
+ private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
+ @NonNull RemoteAnimationTarget[] targets) {
+ return createOpenCloseAnimationAdapters(targets, true /* isOpening */,
+ mAnimationSpec::loadOpenAnimation);
+ }
+
+ @NonNull
+ private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
+ @NonNull RemoteAnimationTarget[] targets) {
+ return createOpenCloseAnimationAdapters(targets, false /* isOpening */,
+ mAnimationSpec::loadCloseAnimation);
+ }
+
+ /**
+ * Creates {@link TaskFragmentAnimationAdapter} for OPEN and CLOSE types of transition.
+ * @param isOpening {@code true} for OPEN type, {@code false} for CLOSE type.
+ */
+ @NonNull
+ private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
+ @NonNull RemoteAnimationTarget[] targets, boolean isOpening,
+ @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
+ // We need to know if the target window is only a partial of the whole animation screen.
+ // If so, we will need to adjust it to make the whole animation screen looks like one.
+ final List<RemoteAnimationTarget> openingTargets = new ArrayList<>();
+ final List<RemoteAnimationTarget> closingTargets = new ArrayList<>();
+ final Rect openingWholeScreenBounds = new Rect();
+ final Rect closingWholeScreenBounds = new Rect();
+ for (RemoteAnimationTarget target : targets) {
+ if (target.mode != MODE_CLOSING) {
+ openingTargets.add(target);
+ openingWholeScreenBounds.union(target.screenSpaceBounds);
+ } else {
+ closingTargets.add(target);
+ closingWholeScreenBounds.union(target.screenSpaceBounds);
+ // Union the start bounds since this may be the ClosingChanging animation.
+ closingWholeScreenBounds.union(target.startBounds);
+ }
+ }
+
+ // For OPEN transition, open windows should be above close windows.
+ // For CLOSE transition, open windows should be below close windows.
+ int offsetLayer = TYPE_LAYER_OFFSET;
+ final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
+ for (RemoteAnimationTarget target : openingTargets) {
+ final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+ animationProvider, openingWholeScreenBounds);
+ if (isOpening) {
+ adapter.overrideLayer(offsetLayer++);
+ }
+ adapters.add(adapter);
+ }
+ for (RemoteAnimationTarget target : closingTargets) {
+ final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+ animationProvider, closingWholeScreenBounds);
+ if (!isOpening) {
+ adapter.overrideLayer(offsetLayer++);
+ }
+ adapters.add(adapter);
+ }
+ return adapters;
+ }
+
+ @NonNull
+ private TaskFragmentAnimationAdapter createOpenCloseAnimationAdapter(
+ @NonNull RemoteAnimationTarget target,
+ @NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider,
+ @NonNull Rect wholeAnimationBounds) {
+ final Animation animation = animationProvider.apply(target, wholeAnimationBounds);
+ return new TaskFragmentAnimationAdapter(animation, target, target.leash,
+ wholeAnimationBounds);
+ }
+
+ @NonNull
+ private List<TaskFragmentAnimationAdapter> createChangeAnimationAdapters(
+ @NonNull RemoteAnimationTarget[] targets) {
+ if (shouldUseJumpCutForChangeAnimation(targets)) {
+ return new ArrayList<>();
+ }
+
+ final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
+ for (RemoteAnimationTarget target : targets) {
+ if (target.mode == MODE_CHANGING) {
+ // This is the target with bounds change.
+ final Animation[] animations =
+ mAnimationSpec.createChangeBoundsChangeAnimations(target);
+ // Adapter for the starting snapshot leash.
+ adapters.add(new TaskFragmentAnimationAdapter.SnapshotAdapter(
+ animations[0], target));
+ // Adapter for the ending bounds changed leash.
+ adapters.add(new TaskFragmentAnimationAdapter.BoundsChangeAdapter(
+ animations[1], target));
+ continue;
+ }
+
+ // These are the other targets that don't have bounds change in the same transition.
+ final Animation animation;
+ if (target.hasAnimatingParent) {
+ // No-op if it will be covered by the changing parent window.
+ animation = TaskFragmentAnimationSpec.createNoopAnimation(target);
+ } else if (target.mode == MODE_CLOSING) {
+ animation = mAnimationSpec.createChangeBoundsCloseAnimation(target);
+ } else {
+ animation = mAnimationSpec.createChangeBoundsOpenAnimation(target);
+ }
+ adapters.add(new TaskFragmentAnimationAdapter(animation, target));
+ }
+ return adapters;
+ }
+
+ /**
+ * Whether we should use jump cut for the change transition.
+ * This normally happens when opening a new secondary with the existing primary using a
+ * different split layout. This can be complicated, like from horizontal to vertical split with
+ * new split pairs.
+ * Uses a jump cut animation to simplify.
+ */
+ private boolean shouldUseJumpCutForChangeAnimation(@NonNull RemoteAnimationTarget[] targets) {
+ boolean hasOpeningWindow = false;
+ boolean hasClosingWindow = false;
+ for (RemoteAnimationTarget target : targets) {
+ if (target.hasAnimatingParent) {
+ continue;
+ }
+ hasOpeningWindow |= target.mode == MODE_OPENING;
+ hasClosingWindow |= target.mode == MODE_CLOSING;
+ }
+ return hasOpeningWindow && hasClosingWindow;
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
new file mode 100644
index 0000000..1f866c3
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -0,0 +1,267 @@
+/*
+ * 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 androidx.window.extensions.embedding;
+
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+
+import android.app.ActivityThread;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.provider.Settings;
+import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.AnimationUtils;
+import android.view.animation.ClipRectAnimation;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.ScaleAnimation;
+import android.view.animation.TranslateAnimation;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.internal.policy.AttributeCache;
+import com.android.internal.policy.TransitionAnimation;
+
+/** Animation spec for TaskFragment transition. */
+// TODO(b/206557124): provide an easier way to customize animation
+class TaskFragmentAnimationSpec {
+
+ private static final String TAG = "TaskFragAnimationSpec";
+ private static final int CHANGE_ANIMATION_DURATION = 517;
+ private static final int CHANGE_ANIMATION_FADE_DURATION = 80;
+ private static final int CHANGE_ANIMATION_FADE_OFFSET = 30;
+
+ private final Context mContext;
+ private final TransitionAnimation mTransitionAnimation;
+ private final Interpolator mFastOutExtraSlowInInterpolator;
+ private final LinearInterpolator mLinearInterpolator;
+ private float mTransitionAnimationScaleSetting;
+
+ TaskFragmentAnimationSpec(@NonNull Handler handler) {
+ mContext = ActivityThread.currentActivityThread().getApplication();
+ mTransitionAnimation = new TransitionAnimation(mContext, false /* debug */, TAG);
+ // Initialize the AttributeCache for the TransitionAnimation.
+ AttributeCache.init(mContext);
+ mFastOutExtraSlowInInterpolator = AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.fast_out_extra_slow_in);
+ mLinearInterpolator = new LinearInterpolator();
+
+ // The transition animation should be adjusted based on the developer option.
+ final ContentResolver resolver = mContext.getContentResolver();
+ mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
+ resolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE), false,
+ new SettingsObserver(handler));
+ }
+
+ /** For target that doesn't need to be animated. */
+ @NonNull
+ static Animation createNoopAnimation(@NonNull RemoteAnimationTarget target) {
+ // Noop but just keep the target showing/hiding.
+ final float alpha = target.mode == MODE_CLOSING ? 0f : 1f;
+ return new AlphaAnimation(alpha, alpha);
+ }
+
+ /** Animation for target that is opening in a change transition. */
+ @NonNull
+ Animation createChangeBoundsOpenAnimation(@NonNull RemoteAnimationTarget target) {
+ final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
+ final Rect bounds = target.screenSpaceBounds;
+ final int startLeft;
+ final int startTop;
+ if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
+ // The window will be animated in from left or right depending on its position.
+ startTop = 0;
+ startLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
+ } else {
+ // The window will be animated in from top or bottom depending on its position.
+ startTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
+ startLeft = 0;
+ }
+
+ // The position should be 0-based as we will post translate in
+ // TaskFragmentAnimationAdapter#onAnimationUpdate
+ final Animation animation = new TranslateAnimation(startLeft, 0, startTop, 0);
+ animation.setInterpolator(mFastOutExtraSlowInInterpolator);
+ animation.setDuration(CHANGE_ANIMATION_DURATION);
+ animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
+ }
+
+ /** Animation for target that is closing in a change transition. */
+ @NonNull
+ Animation createChangeBoundsCloseAnimation(@NonNull RemoteAnimationTarget target) {
+ final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
+ // Use startBounds if the window is closing in case it may also resize.
+ final Rect bounds = target.startBounds;
+ final int endTop;
+ final int endLeft;
+ if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
+ // The window will be animated out to left or right depending on its position.
+ endTop = 0;
+ endLeft = parentBounds.left == bounds.left ? -bounds.width() : bounds.width();
+ } else {
+ // The window will be animated out to top or bottom depending on its position.
+ endTop = parentBounds.top == bounds.top ? -bounds.height() : bounds.height();
+ endLeft = 0;
+ }
+
+ // The position should be 0-based as we will post translate in
+ // TaskFragmentAnimationAdapter#onAnimationUpdate
+ final Animation animation = new TranslateAnimation(0, endLeft, 0, endTop);
+ animation.setInterpolator(mFastOutExtraSlowInInterpolator);
+ animation.setDuration(CHANGE_ANIMATION_DURATION);
+ animation.initialize(bounds.width(), bounds.height(), bounds.width(), bounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
+ }
+
+ /**
+ * Animation for target that is changing (bounds change) in a change transition.
+ * @return the return array always has two elements. The first one is for the start leash, and
+ * the second one is for the end leash.
+ */
+ @NonNull
+ Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) {
+ // Both start bounds and end bounds are in screen coordinates. We will post translate
+ // to the local coordinates in TaskFragmentAnimationAdapter#onAnimationUpdate
+ final Rect startBounds = target.startBounds;
+ final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
+ final Rect endBounds = target.screenSpaceBounds;
+ float scaleX = ((float) startBounds.width()) / endBounds.width();
+ float scaleY = ((float) startBounds.height()) / endBounds.height();
+ // Start leash is a child of the end leash. Reverse the scale so that the start leash won't
+ // be scaled up with its parent.
+ float startScaleX = 1.f / scaleX;
+ float startScaleY = 1.f / scaleY;
+
+ // The start leash will be fade out.
+ final AnimationSet startSet = new AnimationSet(false /* shareInterpolator */);
+ final Animation startAlpha = new AlphaAnimation(1f, 0f);
+ startAlpha.setInterpolator(mLinearInterpolator);
+ startAlpha.setDuration(CHANGE_ANIMATION_FADE_DURATION);
+ startAlpha.setStartOffset(CHANGE_ANIMATION_FADE_OFFSET);
+ startSet.addAnimation(startAlpha);
+ final Animation startScale = new ScaleAnimation(startScaleX, startScaleX, startScaleY,
+ startScaleY);
+ startScale.setInterpolator(mFastOutExtraSlowInInterpolator);
+ startScale.setDuration(CHANGE_ANIMATION_DURATION);
+ startSet.addAnimation(startScale);
+ startSet.initialize(startBounds.width(), startBounds.height(), endBounds.width(),
+ endBounds.height());
+ startSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+
+ // The end leash will be moved into the end position while scaling.
+ final AnimationSet endSet = new AnimationSet(true /* shareInterpolator */);
+ endSet.setInterpolator(mFastOutExtraSlowInInterpolator);
+ final Animation endScale = new ScaleAnimation(scaleX, 1, scaleY, 1);
+ endScale.setDuration(CHANGE_ANIMATION_DURATION);
+ endSet.addAnimation(endScale);
+ // The position should be 0-based as we will post translate in
+ // TaskFragmentAnimationAdapter#onAnimationUpdate
+ final Animation endTranslate = new TranslateAnimation(startBounds.left - endBounds.left, 0,
+ startBounds.top - endBounds.top, 0);
+ endTranslate.setDuration(CHANGE_ANIMATION_DURATION);
+ endSet.addAnimation(endTranslate);
+ // The end leash is resizing, we should update the window crop based on the clip rect.
+ final Rect startClip = new Rect(startBounds);
+ final Rect endClip = new Rect(endBounds);
+ startClip.offsetTo(0, 0);
+ endClip.offsetTo(0, 0);
+ final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
+ clipAnim.setDuration(CHANGE_ANIMATION_DURATION);
+ endSet.addAnimation(clipAnim);
+ endSet.initialize(startBounds.width(), startBounds.height(), parentBounds.width(),
+ parentBounds.height());
+ endSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+
+ return new Animation[]{startSet, endSet};
+ }
+
+ @NonNull
+ Animation loadOpenAnimation(@NonNull RemoteAnimationTarget target,
+ @NonNull Rect wholeAnimationBounds) {
+ final boolean isEnter = target.mode != MODE_CLOSING;
+ final Animation animation;
+ // Background color on TaskDisplayArea has already been set earlier in
+ // WindowContainer#getAnimationAdapter.
+ if (target.showBackdrop) {
+ animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+ ? com.android.internal.R.anim.task_fragment_clear_top_open_enter
+ : com.android.internal.R.anim.task_fragment_clear_top_open_exit);
+ } else {
+ animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+ ? com.android.internal.R.anim.task_fragment_open_enter
+ : com.android.internal.R.anim.task_fragment_open_exit);
+ }
+ // Use the whole animation bounds instead of the change bounds, so that when multiple change
+ // targets are opening at the same time, the animation applied to each will be the same.
+ // Otherwise, we may see gap between the activities that are launching together.
+ animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
+ wholeAnimationBounds.width(), wholeAnimationBounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
+ }
+
+ @NonNull
+ Animation loadCloseAnimation(@NonNull RemoteAnimationTarget target,
+ @NonNull Rect wholeAnimationBounds) {
+ final boolean isEnter = target.mode != MODE_CLOSING;
+ final Animation animation;
+ if (target.showBackdrop) {
+ animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+ ? com.android.internal.R.anim.task_fragment_clear_top_close_enter
+ : com.android.internal.R.anim.task_fragment_clear_top_close_exit);
+ } else {
+ animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+ ? com.android.internal.R.anim.task_fragment_close_enter
+ : com.android.internal.R.anim.task_fragment_close_exit);
+ }
+ // Use the whole animation bounds instead of the change bounds, so that when multiple change
+ // targets are closing at the same time, the animation applied to each will be the same.
+ // Otherwise, we may see gap between the activities that are finishing together.
+ animation.initialize(wholeAnimationBounds.width(), wholeAnimationBounds.height(),
+ wholeAnimationBounds.width(), wholeAnimationBounds.height());
+ animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+ return animation;
+ }
+
+ private float getTransitionAnimationScaleSetting() {
+ return WindowManager.fixScale(Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE, mContext.getResources().getFloat(
+ R.dimen.config_appTransitionAnimationDurationScaleDefault)));
+ }
+
+ private class SettingsObserver extends ContentObserver {
+ SettingsObserver(@NonNull Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mTransitionAnimationScaleSetting = getTransitionAnimationScaleSetting();
+ }
+ }
+}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index 8911d18..ac004c3 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -23,6 +23,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -84,6 +86,24 @@
}
@Test
+ public void testUnregisterOrganizer() {
+ mOrganizer.overrideSplitAnimation();
+ mOrganizer.unregisterOrganizer();
+
+ verify(mOrganizer).unregisterRemoteAnimations();
+ }
+
+ @Test
+ public void testOverrideSplitAnimation() {
+ assertNull(mOrganizer.mAnimationController);
+
+ mOrganizer.overrideSplitAnimation();
+
+ assertNotNull(mOrganizer.mAnimationController);
+ verify(mOrganizer).registerRemoteAnimations(mOrganizer.mAnimationController.mDefinition);
+ }
+
+ @Test
public void testExpandTaskFragment() {
final TaskContainer taskContainer = createTestTaskContainer();
doReturn(taskContainer).when(mSplitController).getTaskContainer(anyInt());
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
new file mode 100644
index 0000000..a1e9f08
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 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 androidx.window.extensions.embedding;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.mockito.Mockito.never;
+
+import android.platform.test.annotations.Presubmit;
+import android.window.TaskFragmentOrganizer;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/**
+ * Test class for {@link TaskFragmentAnimationController}.
+ *
+ * Build/Install/Run:
+ * atest WMJetpackUnitTests:TaskFragmentAnimationControllerTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaskFragmentAnimationControllerTest {
+ @Rule
+ public MockitoRule rule = MockitoJUnit.rule();
+
+ @Mock
+ private TaskFragmentOrganizer mOrganizer;
+ private TaskFragmentAnimationController mAnimationController;
+
+ @Before
+ public void setup() {
+ mAnimationController = new TaskFragmentAnimationController(mOrganizer);
+ }
+
+ @Test
+ public void testRegisterRemoteAnimations() {
+ mAnimationController.registerRemoteAnimations();
+
+ verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
+
+ mAnimationController.registerRemoteAnimations();
+
+ // No extra call if it has been registered.
+ verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition);
+ }
+
+ @Test
+ public void testUnregisterRemoteAnimations() {
+ mAnimationController.unregisterRemoteAnimations();
+
+ // No call if it is not registered.
+ verify(mOrganizer, never()).unregisterRemoteAnimations();
+
+ mAnimationController.registerRemoteAnimations();
+ mAnimationController.unregisterRemoteAnimations();
+
+ verify(mOrganizer).unregisterRemoteAnimations();
+
+ mAnimationController.unregisterRemoteAnimations();
+
+ // No extra call if it has been unregistered.
+ verify(mOrganizer).unregisterRemoteAnimations();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DesktopScenarioCustomAppTestBase.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DesktopScenarioCustomAppTestBase.kt
new file mode 100644
index 0000000..5a69b27
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DesktopScenarioCustomAppTestBase.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 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.scenarios
+
+import android.app.Instrumentation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.Ignore
+
+/** Base test class for desktop CUJ with customizable test app. */
+@Ignore("Base Test Class")
+abstract class DesktopScenarioCustomAppTestBase(
+ isResizeable: Boolean = true,
+ isLandscapeApp: Boolean = true
+) {
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+ // TODO(b/363181411): Consolidate in LetterboxAppHelper.
+ val testApp = when {
+ isResizeable && isLandscapeApp -> SimpleAppHelper(instrumentation)
+ isResizeable && !isLandscapeApp -> SimpleAppHelper(
+ instrumentation,
+ launcherName = ActivityOptions.PortraitOnlyActivity.LABEL,
+ component = ActivityOptions.PortraitOnlyActivity.COMPONENT.toFlickerComponent()
+ )
+ // NonResizeablAppHelper has no fixed orientation.
+ !isResizeable && isLandscapeApp -> NonResizeableAppHelper(instrumentation)
+ // Opens NonResizeablePortraitActivity.
+ else -> LetterboxAppHelper(instrumentation)
+ }.let { DesktopModeAppHelper(it) }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
index 0f0d2df..5f759e8 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
@@ -17,15 +17,8 @@
package com.android.wm.shell.scenarios
import android.platform.test.annotations.Postsubmit
-import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
-import android.tools.traces.parsers.WindowManagerStateHelper
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
-import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.window.flags.Flags
import com.android.wm.shell.Utils
import org.junit.After
@@ -40,13 +33,11 @@
@Postsubmit
open class EnterDesktopWithDrag
@JvmOverloads
-constructor(val rotation: Rotation = Rotation.ROTATION_0) {
-
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val tapl = LauncherInstrumentation()
- private val wmHelper = WindowManagerStateHelper(instrumentation)
- private val device = UiDevice.getInstance(instrumentation)
- private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+constructor(
+ val rotation: Rotation = Rotation.ROTATION_0,
+ isResizeable: Boolean = true,
+ isLandscapeApp: Boolean = true
+) : DesktopScenarioCustomAppTestBase(isResizeable, isLandscapeApp) {
@Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
index 533be88..b616e53 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
@@ -17,15 +17,8 @@
package com.android.wm.shell.scenarios
import android.platform.test.annotations.Postsubmit
-import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
-import android.tools.traces.parsers.WindowManagerStateHelper
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.uiautomator.UiDevice
-import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
-import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.window.flags.Flags
import com.android.wm.shell.Utils
import org.junit.After
@@ -40,13 +33,11 @@
@Postsubmit
open class ExitDesktopWithDragToTopDragZone
@JvmOverloads
-constructor(val rotation: Rotation = Rotation.ROTATION_0) {
-
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- private val tapl = LauncherInstrumentation()
- private val wmHelper = WindowManagerStateHelper(instrumentation)
- private val device = UiDevice.getInstance(instrumentation)
- private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+constructor(
+ val rotation: Rotation = Rotation.ROTATION_0,
+ isResizeable: Boolean = true,
+ isLandscapeApp: Boolean = true
+) : DesktopScenarioCustomAppTestBase(isResizeable, isLandscapeApp) {
@Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
index 70be58f..5b7521a 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
@@ -22,6 +22,7 @@
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.FlakyTest
import com.android.wm.shell.flicker.pip.common.PipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -45,6 +46,22 @@
flicker.assertLayersEnd { this.visibleRegion(pipApp).isSameAspectRatio(1, 2) }
}
+ @FlakyTest(bugId = 358278071)
+ override fun hasAtMostOnePipDismissOverlayWindow() =
+ super.hasAtMostOnePipDismissOverlayWindow()
+
+ @FlakyTest(bugId = 358278071)
+ override fun statusBarLayerPositionAtStartAndEnd() =
+ super.statusBarLayerPositionAtStartAndEnd()
+
+ @FlakyTest(bugId = 358278071)
+ override fun taskBarWindowIsAlwaysVisible() =
+ super.taskBarWindowIsAlwaysVisible()
+
+ @FlakyTest(bugId = 358278071)
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index 90b9798..cbd4a52 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -181,6 +181,13 @@
super.taskBarWindowIsAlwaysVisible()
}
+ // Overridden to remove @Postsubmit annotation
+ @Test
+ @FlakyTest(bugId = 294993100)
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ // No rounded corners as we go back to fullscreen in new orientation.
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index ed2a0a7..578a9b5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -147,6 +147,12 @@
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
+ @Postsubmit
+ @Test
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ flicker.assertLayersEnd { hasNoRoundedCorners(pipApp) }
+ }
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
index 8cb81b4..f57335c 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
@@ -70,6 +70,11 @@
}
}
+ @Test
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ // PiP might have completely faded out by this point, so corner radii not applicable.
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
index 0742cf9..ce84eb6 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip.common
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.Rotation
import android.tools.flicker.legacy.LegacyFlickerTest
@@ -123,6 +124,12 @@
}
}
+ @Postsubmit
+ @Test
+ override fun pipLayerHasCorrectCornersAtEnd() {
+ flicker.assertLayersEnd { hasNoRoundedCorners(pipApp) }
+ }
+
/** {@inheritDoc} */
@Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index 99c1ad2..bc2bfdb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -18,6 +18,7 @@
import android.app.Instrumentation
import android.content.Intent
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.tools.Rotation
import android.tools.flicker.legacy.FlickerBuilder
@@ -105,4 +106,10 @@
.doesNotContain(false)
}
}
+
+ @Postsubmit
+ @Test
+ open fun pipLayerHasCorrectCornersAtEnd() {
+ flicker.assertLayersEnd { hasRoundedCorners(pipApp) }
+ }
}
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 6c0f933..e2ec952 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -62,7 +62,7 @@
void dispatch(in Tag tag);
- void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
+ void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras, String pkg);
void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
@@ -100,7 +100,7 @@
void unregisterWlcStateListener(in INfcWlcStateListener listener);
WlcListenerDeviceInfo getWlcListenerDeviceInfo();
- void updateDiscoveryTechnology(IBinder b, int pollFlags, int listenFlags);
+ void updateDiscoveryTechnology(IBinder b, int pollFlags, int listenFlags, String pkg);
void notifyPollingLoop(in PollingFrame frame);
void notifyHceDeactivated();
diff --git a/nfc/java/android/nfc/NfcActivityManager.java b/nfc/java/android/nfc/NfcActivityManager.java
index 0eb846d..909eca7 100644
--- a/nfc/java/android/nfc/NfcActivityManager.java
+++ b/nfc/java/android/nfc/NfcActivityManager.java
@@ -236,7 +236,8 @@
public void setReaderMode(Binder token, int flags, Bundle extras) {
if (DBG) Log.d(TAG, "Setting reader mode");
- NfcAdapter.callService(() -> NfcAdapter.sService.setReaderMode(token, this, flags, extras));
+ NfcAdapter.callService(() -> NfcAdapter.sService.setReaderMode(
+ token, this, flags, extras, mAdapter.getContext().getPackageName()));
}
/**
@@ -395,7 +396,8 @@
private void changeDiscoveryTech(Binder token, int pollTech, int listenTech) {
NfcAdapter.callService(
- () -> NfcAdapter.sService.updateDiscoveryTechnology(token, pollTech, listenTech));
+ () -> NfcAdapter.sService.updateDiscoveryTechnology(
+ token, pollTech, listenTech, mAdapter.getContext().getPackageName()));
}
}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 525e2c5..22ae612 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -1731,7 +1731,8 @@
}
Binder token = new Binder();
int flags = enable ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
- callService(() -> sService.setReaderMode(token, null, flags, null));
+ callService(() -> sService.setReaderMode(
+ token, null, flags, null, mContext.getPackageName()));
}
/**
@@ -1804,7 +1805,8 @@
|| (listenTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {
Binder token = new Binder();
callService( () ->
- sService.updateDiscoveryTechnology(token, pollTechnology, listenTechnology));
+ sService.updateDiscoveryTechnology(
+ token, pollTechnology, listenTechnology, mContext.getPackageName()));
} else {
mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology);
}
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
index 8a25726..0d4ef3c 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml
@@ -20,7 +20,7 @@
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="28"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
<corners
android:topLeftRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="0dp"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml
index 7e626e5..3072772 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml
@@ -20,7 +20,7 @@
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="28"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
<corners
android:topLeftRadius="0dp"
android:topRightRadius="?android:attr/dialogCornerRadius"
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml
index 9f4980b..f1790f9 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml
@@ -20,7 +20,7 @@
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="28"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
<corners
android:radius="?android:attr/dialogCornerRadius"
/>
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml
index 67b5107..f0da7b4 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml
@@ -18,7 +18,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
<corners
android:radius="0dp"
/>
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenIconLoader.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenIconLoader.java
index fe0f98a..43c6c50 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenIconLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenIconLoader.java
@@ -31,7 +31,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.ListenableFuture;
@@ -53,25 +52,22 @@
private final LruCache<ZenIcon.Key, Drawable> mCache;
private final ListeningExecutorService mBackgroundExecutor;
+ /** Obtains the singleton {@link ZenIconLoader}. */
public static ZenIconLoader getInstance() {
if (sInstance == null) {
- sInstance = new ZenIconLoader();
+ sInstance = new ZenIconLoader(Executors.newFixedThreadPool(4));
}
return sInstance;
}
- /** Replaces the singleton instance of {@link ZenIconLoader} by the provided one. */
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- public static void setInstance(@Nullable ZenIconLoader instance) {
- sInstance = instance;
- }
-
- private ZenIconLoader() {
- this(Executors.newFixedThreadPool(4));
- }
-
- @VisibleForTesting
- public ZenIconLoader(ExecutorService backgroundExecutor) {
+ /**
+ * Constructs a ZenIconLoader with the specified {@code backgroundExecutor}.
+ *
+ * <p>ZenIconLoader <em>should be a singleton</em>, so this should only be used to instantiate
+ * and provide the singleton instance in a module. If the app doesn't support dependency
+ * injection, use {@link #getInstance} instead.
+ */
+ public ZenIconLoader(@NonNull ExecutorService backgroundExecutor) {
mCache = new LruCache<>(50);
mBackgroundExecutor =
MoreExecutors.listeningDecorator(backgroundExecutor);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c1bb55c..d26a906 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -949,36 +949,37 @@
strict_mode: false,
}
-// Disable for now. TODO(b/356666754) Re-enable it
-// android_ravenwood_test {
-// name: "SystemUiRavenTests",
-// srcs: [
-// ":SystemUI-tests-utils",
-// ":SystemUI-tests-multivalent",
-// // TODO(b/294256649): pivot to using {.aapt.jar} and re-enable
-// // use_resource_processor: true when better supported by soong
-// ":SystemUIRobo-stub{.aapt.srcjar}",
-// ],
-// static_libs: [
-// "SystemUI-core",
-// "SystemUI-res",
-// "SystemUI-tests-base",
-// "androidx.test.uiautomator_uiautomator",
-// "androidx.core_core-animation-testing",
-// "androidx.test.ext.junit",
-// "kosmos",
-// "mockito-kotlin-nodeps",
-// ],
-// libs: [
-// "android.test.runner",
-// "android.test.base",
-// "android.test.mock",
-// ],
-// auto_gen_config: true,
-// plugins: [
-// "dagger2-compiler",
-// ],
-// }
+android_ravenwood_test {
+ name: "SystemUiRavenTests",
+ srcs: [
+ ":SystemUI-tests-utils",
+ ":SystemUI-tests-multivalent",
+ // TODO(b/294256649): pivot to using {.aapt.jar} and re-enable
+ // use_resource_processor: true when better supported by soong
+ ":SystemUIRobo-stub{.aapt.srcjar}",
+ ],
+ static_libs: [
+ "SystemUI-core",
+ "SystemUI-res",
+ "SystemUI-tests-base",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.core_core-animation-testing",
+ "androidx.test.ext.junit",
+ "kosmos",
+ "kotlin-test",
+ "mockito-kotlin-nodeps",
+ "androidx.compose.runtime_runtime",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ auto_gen_config: true,
+ plugins: [
+ "dagger2-compiler",
+ ],
+}
// Opt-out config for optimizing the SystemUI target using R8.
// Disabled via `export SYSTEMUI_OPTIMIZE_JAVA=false`, or explicitly in Make via
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index df4b51a..97206de 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -363,6 +363,13 @@
}
flag {
+ name: "status_bar_signal_policy_refactor"
+ namespace: "systemui"
+ description: "Use a settings observer for airplane mode and make StatusBarSignalPolicy startable"
+ bug: "264539100"
+}
+
+flag {
name: "status_bar_swipe_over_chip"
namespace: "systemui"
description: "Allow users to swipe over the status bar chip to open the shade"
@@ -373,6 +380,17 @@
}
flag {
+ name: "status_bar_always_check_underlying_networks"
+ namespace: "systemui"
+ description: "For status bar connectivity UI, always check underlying networks for wifi and "
+ "carrier merged information, regardless of the sepcified transport type"
+ bug: "352162710"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "status_bar_stop_updating_window_height"
namespace: "systemui"
description: "Don't have PhoneStatusBarView manually trigger an update of the height in "
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeOverlayModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeOverlayModule.kt
new file mode 100644
index 0000000..e55520a
--- /dev/null
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeOverlayModule.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.scene
+
+import com.android.systemui.notifications.ui.composable.NotificationsShadeOverlay
+import com.android.systemui.scene.ui.composable.Overlay
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+
+@Module
+interface NotificationsShadeOverlayModule {
+
+ @Binds @IntoSet fun notificationsShade(overlay: NotificationsShadeOverlay): Overlay
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
new file mode 100644
index 0000000..37888f2
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2024 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.notifications.ui.composable
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.ContentScope
+import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel
+import com.android.systemui.scene.session.ui.composable.SaveableSession
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.composable.Overlay
+import com.android.systemui.shade.shared.model.ShadeMode
+import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
+import com.android.systemui.shade.ui.composable.OverlayShade
+import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
+import com.android.systemui.statusbar.phone.ui.TintedIconManager
+import dagger.Lazy
+import java.util.Optional
+import javax.inject.Inject
+
+@SysUISingleton
+class NotificationsShadeOverlay
+@Inject
+constructor(
+ private val actionsViewModelFactory: NotificationsShadeOverlayActionsViewModel.Factory,
+ private val overlayShadeViewModelFactory: OverlayShadeViewModel.Factory,
+ private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
+ private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
+ private val tintedIconManagerFactory: TintedIconManager.Factory,
+ private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
+ private val statusBarIconController: StatusBarIconController,
+ private val shadeSession: SaveableSession,
+ private val stackScrollView: Lazy<NotificationScrollView>,
+) : Overlay {
+
+ override val key = Overlays.NotificationsShade
+
+ private val actionsViewModel: NotificationsShadeOverlayActionsViewModel by lazy {
+ actionsViewModelFactory.create()
+ }
+
+ override suspend fun activate(): Nothing {
+ actionsViewModel.activate()
+ }
+
+ @Composable
+ override fun ContentScope.Content(
+ modifier: Modifier,
+ ) {
+ OverlayShade(
+ modifier = modifier,
+ viewModelFactory = overlayShadeViewModelFactory,
+ lockscreenContent = { Optional.empty() },
+ ) {
+ Column {
+ val placeholderViewModel =
+ rememberViewModel("NotificationsShadeOverlay") {
+ notificationsPlaceholderViewModelFactory.create()
+ }
+
+ ExpandedShadeHeader(
+ viewModelFactory = shadeHeaderViewModelFactory,
+ createTintedIconManager = tintedIconManagerFactory::create,
+ createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
+ statusBarIconController = statusBarIconController,
+ modifier = Modifier.padding(horizontal = 16.dp),
+ )
+
+ NotificationScrollingStack(
+ shadeSession = shadeSession,
+ stackScrollView = stackScrollView.get(),
+ viewModel = placeholderViewModel,
+ maxScrimTop = { 0f },
+ shouldPunchHoleBehindScrim = false,
+ shouldFillMaxSize = false,
+ shouldReserveSpaceForNavBar = false,
+ shadeMode = ShadeMode.Dual,
+ modifier = Modifier.fillMaxWidth(),
+ )
+
+ // Communicates the bottom position of the drawable area within the shade to NSSL.
+ NotificationStackCutoffGuideline(
+ stackScrollView = stackScrollView.get(),
+ viewModel = placeholderViewModel,
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
index 1db96cf..c9b8013 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
@@ -92,7 +92,12 @@
true
}
},
- color = MaterialTheme.colorScheme.surface,
+ color =
+ if (enabled) {
+ MaterialTheme.colorScheme.surface
+ } else {
+ MaterialTheme.colorScheme.surfaceContainerHighest
+ },
shape = RoundedCornerShape(28.dp),
onClick =
if (enabled) {
@@ -119,7 +124,7 @@
modifier = Modifier.basicMarquee(),
text = connectedDeviceViewModel.label.toString(),
style = MaterialTheme.typography.labelMedium,
- color = MaterialTheme.colorScheme.onSurfaceVariant,
+ color = connectedDeviceViewModel.labelColor.toColor(),
maxLines = 1,
)
connectedDeviceViewModel.deviceName?.let {
@@ -127,7 +132,7 @@
modifier = Modifier.basicMarquee(),
text = it.toString(),
style = MaterialTheme.typography.titleMedium,
- color = MaterialTheme.colorScheme.onSurface,
+ color = connectedDeviceViewModel.deviceNameColor.toColor(),
maxLines = 1,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
index 072e91a..d4f3b5b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
@@ -23,7 +23,6 @@
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
-import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@@ -78,7 +77,6 @@
modifier: Modifier = Modifier,
) {
require(viewModels.isNotEmpty())
- val transition = updateTransition(isExpanded, label = "CollapsableSliders")
Column(modifier = modifier) {
Box(
modifier = Modifier.fillMaxWidth(),
@@ -106,8 +104,9 @@
sliderColors = sliderColors,
)
}
- transition.AnimatedVisibility(
- visible = { it || !isExpandable },
+ AnimatedVisibility(
+ visible = isExpanded || !isExpandable,
+ label = "CollapsableSliders",
enter =
expandVertically(animationSpec = tween(durationMillis = EXPAND_DURATION_MILLIS)),
exit =
@@ -120,23 +119,31 @@
for (index in 1..viewModels.lastIndex) {
val sliderViewModel: SliderViewModel = viewModels[index]
val sliderState by sliderViewModel.slider.collectAsStateWithLifecycle()
- transition.AnimatedVisibility(
- modifier = Modifier.padding(top = 16.dp),
- visible = { it || !isExpandable },
- enter = enterTransition(index = index, totalCount = viewModels.size),
- exit = exitTransition(index = index, totalCount = viewModels.size)
- ) {
- VolumeSlider(
- modifier = Modifier.fillMaxWidth(),
- state = sliderState,
- onValueChange = { newValue: Float ->
- sliderViewModel.onValueChanged(sliderState, newValue)
- },
- onValueChangeFinished = { sliderViewModel.onValueChangeFinished() },
- onIconTapped = { sliderViewModel.toggleMuted(sliderState) },
- sliderColors = sliderColors,
- )
- }
+
+ VolumeSlider(
+ modifier =
+ Modifier.padding(top = 16.dp)
+ .fillMaxWidth()
+ .animateEnterExit(
+ enter =
+ enterTransition(
+ index = index,
+ totalCount = viewModels.size,
+ ),
+ exit =
+ exitTransition(
+ index = index,
+ totalCount = viewModels.size,
+ ),
+ ),
+ state = sliderState,
+ onValueChange = { newValue: Float ->
+ sliderViewModel.onValueChanged(sliderState, newValue)
+ },
+ onValueChangeFinished = { sliderViewModel.onValueChangeFinished() },
+ onIconTapped = { sliderViewModel.toggleMuted(sliderState) },
+ sliderColors = sliderColors,
+ )
}
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
index 5ffb6f8..1cc0fb2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
@@ -25,13 +25,13 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.paneTitle
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.theme.PlatformTheme
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.res.R
import com.android.systemui.volume.panel.ui.layout.ComponentsLayout
@@ -43,7 +43,6 @@
private val padding = 24.dp
@Composable
-@OptIn(ExperimentalComposeUiApi::class)
fun VolumePanelRoot(
viewModel: VolumePanelViewModel,
modifier: Modifier = Modifier,
@@ -54,18 +53,20 @@
with(VolumePanelComposeScope(state)) {
components?.let { componentsState ->
- Components(
- componentsState,
- modifier
- .sysuiResTag(VolumePanelTestTag)
- .semantics { paneTitle = accessibilityTitle }
- .padding(
- start = padding,
- top = padding,
- end = padding,
- bottom = 20.dp,
- )
- )
+ PlatformTheme {
+ Components(
+ componentsState,
+ modifier
+ .sysuiResTag(VolumePanelTestTag)
+ .semantics { paneTitle = accessibilityTitle }
+ .padding(
+ start = padding,
+ top = padding,
+ end = padding,
+ bottom = 20.dp,
+ )
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
index 3f8f5e7..ced177c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
@@ -153,4 +153,15 @@
override fun toString(): String {
return "TransitionKey(debugName=$debugName)"
}
+
+ companion object {
+ /**
+ * A special transition key indicating that the associated transition should be used for
+ * Predictive Back gestures.
+ *
+ * Use this key when defining a transition that you want to be specifically triggered when
+ * the user performs a Predictive Back gesture.
+ */
+ val PredictiveBack = TransitionKey("PredictiveBack")
+ }
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
index be4fea1..e930011 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt
@@ -18,7 +18,7 @@
import androidx.activity.BackEventCompat
import androidx.activity.compose.PredictiveBackHandler
-import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.AnimationSpec
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
import kotlin.coroutines.cancellation.CancellationException
@@ -43,7 +43,9 @@
createSwipeAnimation(
layoutImpl,
layoutImpl.coroutineScope,
- result,
+ result.userActionCopy(
+ transitionKey = result.transitionKey ?: TransitionKey.PredictiveBack
+ ),
isUpOrLeft = false,
// Note that the orientation does not matter here given that it's only used to
// compute the distance. In our case the distance is always 1f.
@@ -60,7 +62,7 @@
animation: SwipeAnimation<T>,
progress: Flow<BackEventCompat>,
) {
- fun animateOffset(targetContent: T) {
+ fun animateOffset(targetContent: T, spec: AnimationSpec<Float>? = null) {
if (
layoutImpl.state.transitionState != animation.contentTransition || animation.isFinishing
) {
@@ -70,12 +72,7 @@
animation.animateOffset(
initialVelocity = 0f,
targetContent = targetContent,
-
- // TODO(b/350705972): Allow to customize or reuse the same customization endpoints as
- // the normal swipe transitions. We can't just reuse them here because other swipe
- // transitions animate pixels while this transition animates progress, so the visibility
- // thresholds will be completely different.
- spec = spring(),
+ spec = spec,
)
}
@@ -84,9 +81,15 @@
progress.collect { backEvent -> animation.dragOffset = backEvent.progress }
// Back gesture successful.
- animateOffset(animation.toContent)
+ animateOffset(
+ animation.toContent,
+ animation.contentTransition.transformationSpec.progressSpec
+ )
} catch (e: CancellationException) {
// Back gesture cancelled.
+ // If the back gesture is cancelled, the progress is animated back to 0f by the system.
+ // Since the remaining change in progress is usually very small, the progressSpec is omitted
+ // and the default spring spec used instead.
animateOffset(animation.fromContent)
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index b3f74f7..e453430 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -492,6 +492,17 @@
) {
internal abstract fun toContent(currentScene: SceneKey): ContentKey
+ internal fun userActionCopy(
+ transitionKey: TransitionKey? = this.transitionKey
+ ): UserActionResult {
+ return when (this) {
+ is ChangeScene -> copy(transitionKey = transitionKey)
+ is ShowOverlay -> copy(transitionKey = transitionKey)
+ is HideOverlay -> copy(transitionKey = transitionKey)
+ is ReplaceByOverlay -> copy(transitionKey = transitionKey)
+ }
+ }
+
data class ChangeScene
internal constructor(
/** The scene we should be transitioning to during the [UserAction]. */
@@ -503,19 +514,19 @@
}
/** A [UserActionResult] that shows [overlay]. */
- class ShowOverlay(
+ data class ShowOverlay(
val overlay: OverlayKey,
- transitionKey: TransitionKey? = null,
- requiresFullDistanceSwipe: Boolean = false,
+ override val transitionKey: TransitionKey? = null,
+ override val requiresFullDistanceSwipe: Boolean = false,
) : UserActionResult(transitionKey, requiresFullDistanceSwipe) {
override fun toContent(currentScene: SceneKey): ContentKey = overlay
}
/** A [UserActionResult] that hides [overlay]. */
- class HideOverlay(
+ data class HideOverlay(
val overlay: OverlayKey,
- transitionKey: TransitionKey? = null,
- requiresFullDistanceSwipe: Boolean = false,
+ override val transitionKey: TransitionKey? = null,
+ override val requiresFullDistanceSwipe: Boolean = false,
) : UserActionResult(transitionKey, requiresFullDistanceSwipe) {
override fun toContent(currentScene: SceneKey): ContentKey = currentScene
}
@@ -526,10 +537,10 @@
* Note: This result can only be used for user actions of overlays and an exception will be
* thrown if it is used for a scene.
*/
- class ReplaceByOverlay(
+ data class ReplaceByOverlay(
val overlay: OverlayKey,
- transitionKey: TransitionKey? = null,
- requiresFullDistanceSwipe: Boolean = false,
+ override val transitionKey: TransitionKey? = null,
+ override val requiresFullDistanceSwipe: Boolean = false,
) : UserActionResult(transitionKey, requiresFullDistanceSwipe) {
override fun toContent(currentScene: SceneKey): ContentKey = overlay
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index cefcff7..e65ed9b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -90,10 +90,19 @@
return relaxedSpec
}
- return transition(from, to, key) {
+ val relaxedReversed =
+ transition(from, to, key) {
(it.from == to && it.to == null) || (it.to == from && it.from == null)
}
- ?.reversed() ?: defaultTransition(from, to)
+ if (relaxedReversed != null) {
+ return relaxedReversed.reversed()
+ }
+
+ return if (key != null) {
+ findSpec(from, to, null)
+ } else {
+ defaultTransition(from, to)
+ }
}
private fun transition(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
index 57ff597..be9c567 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt
@@ -17,8 +17,8 @@
package com.android.compose.animation.scene
import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationVector1D
-import androidx.compose.animation.core.SpringSpec
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
@@ -320,7 +320,7 @@
fun animateOffset(
initialVelocity: Float,
targetContent: T,
- spec: SpringSpec<Float>? = null,
+ spec: AnimationSpec<Float>? = null,
): OffsetAnimation {
val initialProgress = progress
// Skip the animation if we have already reached the target content and the overscroll does
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
index c5b6cdf..9284ffd 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt
@@ -18,6 +18,8 @@
import androidx.activity.BackEventCompat
import androidx.activity.ComponentActivity
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
@@ -65,7 +67,23 @@
@Test
fun testPredictiveBack() {
- val layoutState = rule.runOnUiThread { MutableSceneTransitionLayoutState(SceneA) }
+ val transitionFrames = 2
+ val layoutState =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutState(
+ SceneA,
+ transitions =
+ transitions {
+ from(SceneA, to = SceneB) {
+ spec =
+ tween(
+ durationMillis = transitionFrames * 16,
+ easing = LinearEasing
+ )
+ }
+ }
+ )
+ }
rule.setContent {
SceneTransitionLayout(layoutState) {
scene(SceneA, mapOf(Back to SceneB)) { Box(Modifier.fillMaxSize()) }
@@ -94,12 +112,27 @@
assertThat(layoutState.transitionState).hasCurrentScene(SceneA)
assertThat(layoutState.transitionState).isIdle()
+ rule.mainClock.autoAdvance = false
+
// Start again and commit it.
rule.runOnUiThread {
dispatcher.dispatchOnBackStarted(backEvent())
dispatcher.dispatchOnBackProgressed(backEvent(progress = 0.4f))
dispatcher.onBackPressed()
}
+ rule.mainClock.advanceTimeByFrame()
+ rule.waitForIdle()
+ val transition2 = assertThat(layoutState.transitionState).isSceneTransition()
+ // verify that transition picks up progress from preview
+ assertThat(transition2).hasProgress(0.4f, tolerance = 0.0001f)
+
+ rule.mainClock.advanceTimeByFrame()
+ rule.waitForIdle()
+ // verify that transition is half way between preview-end-state (0.4f) and target-state (1f)
+ // after one frame
+ assertThat(transition2).hasProgress(0.7f, tolerance = 0.0001f)
+
+ rule.mainClock.autoAdvance = true
rule.waitForIdle()
assertThat(layoutState.transitionState).hasCurrentScene(SceneB)
assertThat(layoutState.transitionState).isIdle()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index bed6cef..f8068e6 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -232,6 +232,47 @@
}
@Test
+ fun defaultPredictiveBack() {
+ val transitions = transitions {
+ from(
+ TestScenes.SceneA,
+ to = TestScenes.SceneB,
+ preview = { fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) } }
+ ) {
+ spec = tween(500)
+ fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) }
+ timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) }
+ }
+ }
+
+ // Verify that fetching the transitionSpec with the PredictiveBack key defaults to the above
+ // transition despite it not having the PredictiveBack key set.
+ val transitionSpec =
+ transitions.transitionSpec(
+ from = TestScenes.SceneA,
+ to = TestScenes.SceneB,
+ key = TransitionKey.PredictiveBack
+ )
+
+ val transformations = transitionSpec.transformationSpec().transformations
+
+ assertThat(transformations)
+ .comparingElementsUsing(TRANSFORMATION_RANGE)
+ .containsExactly(
+ TransformationRange(start = 0.1f, end = 0.8f),
+ TransformationRange(start = 100 / 500f, end = 300 / 500f),
+ )
+
+ val previewTransformations = transitionSpec.previewTransformationSpec()?.transformations
+
+ assertThat(previewTransformations)
+ .comparingElementsUsing(TRANSFORMATION_RANGE)
+ .containsExactly(
+ TransformationRange(start = 0.1f, end = 0.8f),
+ )
+ }
+
+ @Test
fun springSpec() {
val defaultSpec = spring<Float>(stiffness = 1f)
val specFromAToC = spring<Float>(stiffness = 2f)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index 7707a60..fe9105e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -29,6 +29,7 @@
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.domain.interactor.KeyguardKeyboardInteractor
+import com.android.systemui.Flags as AconfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FakeFeatureFlags
@@ -56,7 +57,6 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-import com.android.systemui.Flags as AconfigFlags
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -66,8 +66,7 @@
class KeyguardPasswordViewControllerTest : SysuiTestCase() {
@Mock private lateinit var keyguardPasswordView: KeyguardPasswordView
@Mock private lateinit var passwordEntry: EditText
- private var passwordEntryLayoutParams =
- ViewGroup.LayoutParams(/* width = */ 0, /* height = */ 0)
+ private var passwordEntryLayoutParams = ViewGroup.LayoutParams(/* width= */ 0, /* height= */ 0)
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock lateinit var securityMode: KeyguardSecurityModel.SecurityMode
@Mock lateinit var lockPatternUtils: LockPatternUtils
@@ -106,6 +105,8 @@
whenever(keyguardPasswordView.findViewById<ImageView>(R.id.switch_ime_button))
.thenReturn(mock(ImageView::class.java))
`when`(keyguardPasswordView.resources).thenReturn(context.resources)
+ // TODO(b/362362385): No need to mock keyguardPasswordView.context once this bug is fixed.
+ `when`(keyguardPasswordView.context).thenReturn(context)
whenever(passwordEntry.layoutParams).thenReturn(passwordEntryLayoutParams)
val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository())
val fakeFeatureFlags = FakeFeatureFlags()
@@ -187,9 +188,11 @@
verify(passwordEntry).setOnKeyListener(keyListenerArgumentCaptor.capture())
val eventHandled =
- keyListenerArgumentCaptor.value.onKey(keyguardPasswordView,
+ keyListenerArgumentCaptor.value.onKey(
+ keyguardPasswordView,
KeyEvent.KEYCODE_SPACE,
- KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE))
+ KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE)
+ )
assertFalse("Unlock attempted.", eventHandled)
}
@@ -204,9 +207,11 @@
verify(passwordEntry).setOnKeyListener(keyListenerArgumentCaptor.capture())
val eventHandled =
- keyListenerArgumentCaptor.value.onKey(keyguardPasswordView,
+ keyListenerArgumentCaptor.value.onKey(
+ keyguardPasswordView,
KeyEvent.KEYCODE_ENTER,
- KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER))
+ KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER)
+ )
assertTrue("Unlock not attempted.", eventHandled)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index f7f69d3..281047a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -18,10 +18,8 @@
package com.android.keyguard
import android.app.admin.DevicePolicyManager
-import android.app.admin.flags.Flags as DevicePolicyFlags
import android.content.res.Configuration
import android.media.AudioManager
-import android.platform.test.annotations.EnableFlags
import android.telephony.TelephonyManager
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableResources
@@ -56,6 +54,7 @@
import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardDismissTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.Kosmos
@@ -279,7 +278,7 @@
deviceProvisionedController,
faceAuthAccessibilityDelegate,
devicePolicyManager,
- keyguardTransitionInteractor,
+ kosmos.keyguardDismissTransitionInteractor,
{ primaryBouncerInteractor },
) {
deviceEntryInteractor
@@ -938,7 +937,6 @@
}
@Test
- @EnableFlags(DevicePolicyFlags.FLAG_HEADLESS_SINGLE_USER_FIXES)
fun showAlmostAtWipeDialog_calledOnMainUser_setsCorrectUserType() {
val mainUserId = 10
@@ -955,7 +953,6 @@
}
@Test
- @EnableFlags(DevicePolicyFlags.FLAG_HEADLESS_SINGLE_USER_FIXES)
fun showAlmostAtWipeDialog_calledOnNonMainUser_setsCorrectUserType() {
val secondaryUserId = 10
val mainUserId = 0
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
index d244482..58c3fec 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,15 +37,14 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.ambient.touch.scrim.ScrimController;
import com.android.systemui.ambient.touch.scrim.ScrimManager;
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.settings.FakeUserTracker;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -57,7 +58,6 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.Collections;
import java.util.Optional;
@SmallTest
@@ -106,15 +106,13 @@
UiEventLogger mUiEventLogger;
@Mock
- LockPatternUtils mLockPatternUtils;
-
- @Mock
ActivityStarter mActivityStarter;
@Mock
CommunalViewModel mCommunalViewModel;
- FakeUserTracker mUserTracker;
+ @Mock
+ KeyguardInteractor mKeyguardInteractor;
private static final float TOUCH_REGION = .3f;
private static final float MIN_BOUNCER_HEIGHT = .05f;
@@ -130,7 +128,6 @@
public void setup() {
mKosmos = new KosmosJavaAdapter(this);
MockitoAnnotations.initMocks(this);
- mUserTracker = new FakeUserTracker();
mTouchHandler = new BouncerSwipeTouchHandler(
mKosmos.getTestScope(),
mScrimManager,
@@ -138,24 +135,21 @@
mNotificationShadeWindowController,
mValueAnimatorCreator,
mVelocityTrackerFactory,
- mLockPatternUtils,
- mUserTracker,
mCommunalViewModel,
mFlingAnimationUtils,
mFlingAnimationUtilsClosing,
TOUCH_REGION,
MIN_BOUNCER_HEIGHT,
mUiEventLogger,
- mActivityStarter);
+ mActivityStarter,
+ mKeyguardInteractor);
when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator);
when(mVelocityTrackerFactory.obtain()).thenReturn(mVelocityTracker);
when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE);
when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS);
- when(mLockPatternUtils.isSecure(CURRENT_USER_INFO.id)).thenReturn(true);
-
- mUserTracker.set(Collections.singletonList(CURRENT_USER_INFO), 0);
+ when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(false));
}
/**
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
index b85e32b..9568167 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
@@ -44,16 +46,15 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.ambient.touch.scrim.ScrimController;
import com.android.systemui.ambient.touch.scrim.ScrimManager;
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.settings.FakeUserTracker;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -69,7 +70,6 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.Collections;
import java.util.Optional;
@SmallTest
@@ -116,9 +116,6 @@
UiEventLogger mUiEventLogger;
@Mock
- LockPatternUtils mLockPatternUtils;
-
- @Mock
ActivityStarter mActivityStarter;
@Mock
@@ -127,11 +124,12 @@
@Mock
CommunalViewModel mCommunalViewModel;
+ @Mock
+ KeyguardInteractor mKeyguardInteractor;
+
@Captor
ArgumentCaptor<Rect> mRectCaptor;
- FakeUserTracker mUserTracker;
-
private static final float TOUCH_REGION = .3f;
private static final int SCREEN_WIDTH_PX = 1024;
private static final int SCREEN_HEIGHT_PX = 100;
@@ -148,7 +146,6 @@
public void setup() {
mKosmos = new KosmosJavaAdapter(this);
MockitoAnnotations.initMocks(this);
- mUserTracker = new FakeUserTracker();
mTouchHandler = new BouncerSwipeTouchHandler(
mKosmos.getTestScope(),
mScrimManager,
@@ -156,24 +153,21 @@
mNotificationShadeWindowController,
mValueAnimatorCreator,
mVelocityTrackerFactory,
- mLockPatternUtils,
- mUserTracker,
mCommunalViewModel,
mFlingAnimationUtils,
mFlingAnimationUtilsClosing,
TOUCH_REGION,
MIN_BOUNCER_HEIGHT,
mUiEventLogger,
- mActivityStarter);
+ mActivityStarter,
+ mKeyguardInteractor);
when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator);
when(mVelocityTrackerFactory.obtain()).thenReturn(mVelocityTracker);
when(mFlingAnimationUtils.getMinVelocityPxPerSecond()).thenReturn(Float.MAX_VALUE);
when(mTouchSession.getBounds()).thenReturn(SCREEN_BOUNDS);
- when(mLockPatternUtils.isSecure(CURRENT_USER_INFO.id)).thenReturn(true);
-
- mUserTracker.set(Collections.singletonList(CURRENT_USER_INFO), 0);
+ when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(false));
}
/**
@@ -391,7 +385,7 @@
*/
@Test
public void testSwipeUp_keyguardNotSecure_doesNotExpand() {
- when(mLockPatternUtils.isSecure(CURRENT_USER_INFO.id)).thenReturn(false);
+ when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(true));
mTouchHandler.onSessionStart(mTouchSession);
ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
@@ -426,7 +420,7 @@
*/
@Test
public void testSwipeDown_keyguardNotSecure_doesNotExpand() {
- when(mLockPatternUtils.isSecure(CURRENT_USER_INFO.id)).thenReturn(false);
+ when(mKeyguardInteractor.isKeyguardDismissible()).thenReturn(MutableStateFlow(true));
mTouchHandler.onSessionStart(mTouchSession);
ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor =
ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index 0c5e726..080b48a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -17,8 +17,6 @@
package com.android.systemui.authentication.domain.interactor
import android.app.admin.DevicePolicyManager
-import android.app.admin.flags.Flags as DevicePolicyFlags
-import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
@@ -414,7 +412,6 @@
}
@Test
- @EnableFlags(DevicePolicyFlags.FLAG_HEADLESS_SINGLE_USER_FIXES)
fun upcomingWipe() =
testScope.runTest {
val upcomingWipe by collectLastValue(underTest.upcomingWipe)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
index 3b8ffcd..17e3006 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
@@ -116,7 +116,7 @@
reset(transitionRepository)
// Authentication results in calling startDismissKeyguardTransition.
- kosmos.keyguardTransitionInteractor.startDismissKeyguardTransition()
+ kosmos.keyguardDismissTransitionInteractor.startDismissKeyguardTransition()
runCurrent()
assertThat(transitionRepository)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
index 9273dce..33f3cd4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
@@ -327,7 +327,7 @@
testScope.runTest {
kosmos.fakeKeyguardRepository.setKeyguardShowing(false)
kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
- kosmos.keyguardTransitionInteractor.startDismissKeyguardTransition()
+ kosmos.keyguardDismissTransitionInteractor.startDismissKeyguardTransition()
powerInteractor.setAwakeForTest()
advanceTimeBy(100) // account for debouncing
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
new file mode 100644
index 0000000..cdba4db
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 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.notifications.ui.viewmodel
+
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayActionsViewModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+@EnableSceneContainer
+class NotificationsShadeOverlayActionsViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val fakeShadeRepository by lazy { kosmos.fakeShadeRepository }
+
+ private val underTest by lazy { kosmos.notificationsShadeOverlayActionsViewModel }
+
+ @Test
+ fun upTransitionSceneKey_topAligned_hidesShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ fakeShadeRepository.setDualShadeAlignedToBottom(false)
+ underTest.activateIn(this)
+
+ assertThat((actions?.get(Swipe.Up) as? UserActionResult.HideOverlay)?.overlay)
+ .isEqualTo(Overlays.NotificationsShade)
+ assertThat(actions?.get(Swipe.Down)).isNull()
+ }
+
+ @Test
+ fun upTransitionSceneKey_bottomAligned_doesNothing() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ fakeShadeRepository.setDualShadeAlignedToBottom(true)
+ underTest.activateIn(this)
+
+ assertThat(actions?.get(Swipe.Up)).isNull()
+ assertThat((actions?.get(Swipe.Down) as? UserActionResult.HideOverlay)?.overlay)
+ .isEqualTo(Overlays.NotificationsShade)
+ }
+
+ @Test
+ fun back_hidesShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ underTest.activateIn(this)
+
+ assertThat((actions?.get(Back) as? UserActionResult.HideOverlay)?.overlay)
+ .isEqualTo(Overlays.NotificationsShade)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
index 5925819..5fd3a24 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
@@ -24,9 +24,10 @@
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.settingslib.notification.modes.ZenIconLoader
+import com.android.internal.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.asIcon
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -36,7 +37,6 @@
import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import com.google.common.util.concurrent.MoreExecutors
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toCollection
@@ -60,10 +60,10 @@
@Before
fun setUp() {
context.orCreateTestableResources.apply {
- addOverride(com.android.internal.R.drawable.ic_zen_mode_type_bedtime, BEDTIME_DRAWABLE)
- addOverride(com.android.internal.R.drawable.ic_zen_mode_type_driving, DRIVING_DRAWABLE)
+ addOverride(MODES_DRAWABLE_ID, MODES_DRAWABLE)
+ addOverride(R.drawable.ic_zen_mode_type_bedtime, BEDTIME_DRAWABLE)
+ addOverride(R.drawable.ic_zen_mode_type_driving, DRIVING_DRAWABLE)
}
- ZenIconLoader.setInstance(ZenIconLoader(MoreExecutors.newDirectExecutorService()))
}
@EnableFlags(Flags.FLAG_MODES_UI)
@@ -128,28 +128,34 @@
@Test
@EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
- fun changesIconWhenActiveModesChange() =
+ fun tileData_iconsFlagEnabled_changesIconWhenActiveModesChange() =
testScope.runTest {
- val dataList: List<ModesTileModel> by
- collectValues(
+ val tileData by
+ collectLastValue(
underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
)
- runCurrent()
- assertThat(dataList.map { it.icon }).containsExactly(null).inOrder()
- // Add an inactive mode: state hasn't changed, so this shouldn't cause another emission
+ // Tile starts with the generic Modes icon.
+ runCurrent()
+ assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+ assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
+
+ // Add an inactive mode -> Still modes icon
zenModeRepository.addMode(id = "Mode", active = false)
runCurrent()
- assertThat(dataList.map { it.icon }).containsExactly(null).inOrder()
+ assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+ assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
- // Add an active mode: icon should be the mode icon
+ // Add an active mode: icon should be the mode icon. No iconResId, because we don't
+ // really know that it's a system icon.
zenModeRepository.addMode(
id = "Bedtime",
type = AutomaticZenRule.TYPE_BEDTIME,
active = true
)
runCurrent()
- assertThat(dataList.map { it.icon }).containsExactly(null, BEDTIME_ICON).inOrder()
+ assertThat(tileData?.icon).isEqualTo(BEDTIME_ICON)
+ assertThat(tileData?.iconResId).isNull()
// Add another, less-prioritized mode: icon should remain the first mode icon
zenModeRepository.addMode(
@@ -158,29 +164,58 @@
active = true
)
runCurrent()
- assertThat(dataList.map { it.icon })
- .containsExactly(null, BEDTIME_ICON, BEDTIME_ICON)
- .inOrder()
+ assertThat(tileData?.icon).isEqualTo(BEDTIME_ICON)
+ assertThat(tileData?.iconResId).isNull()
- // Deactivate more important mode: icon should be the less important, still active mode.
+ // Deactivate more important mode: icon should be the less important, still active mode
zenModeRepository.deactivateMode("Bedtime")
runCurrent()
- assertThat(dataList.map { it.icon })
- .containsExactly(null, BEDTIME_ICON, BEDTIME_ICON, DRIVING_ICON)
- .inOrder()
+ assertThat(tileData?.icon).isEqualTo(DRIVING_ICON)
+ assertThat(tileData?.iconResId).isNull()
- // Deactivate remaining mode: no icon
+ // Deactivate remaining mode: back to the default modes icon
zenModeRepository.deactivateMode("Driving")
runCurrent()
- assertThat(dataList.map { it.icon })
- .containsExactly(null, BEDTIME_ICON, BEDTIME_ICON, DRIVING_ICON, null)
- .inOrder()
+ assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+ assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_UI)
+ @DisableFlags(Flags.FLAG_MODES_UI_ICONS)
+ fun tileData_iconsFlagDisabled_hasPriorityModesIcon() =
+ testScope.runTest {
+ val tileData by
+ collectLastValue(
+ underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))
+ )
+
+ runCurrent()
+ assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+ assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
+
+ // Activate a Mode -> Icon doesn't change.
+ zenModeRepository.addMode(id = "Mode", active = true)
+ runCurrent()
+ assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+ assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
+
+ zenModeRepository.deactivateMode(id = "Mode")
+ runCurrent()
+ assertThat(tileData?.icon).isEqualTo(MODES_ICON)
+ assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
}
private companion object {
val TEST_USER = UserHandle.of(1)!!
+
+ val MODES_DRAWABLE_ID = com.android.systemui.res.R.drawable.qs_dnd_icon_off
+
+ val MODES_DRAWABLE = TestStubDrawable("modes_icon")
val BEDTIME_DRAWABLE = TestStubDrawable("bedtime")
val DRIVING_DRAWABLE = TestStubDrawable("driving")
+
+ val MODES_ICON = MODES_DRAWABLE.asIcon()
val BEDTIME_ICON = BEDTIME_DRAWABLE.asIcon()
val DRIVING_ICON = DRIVING_DRAWABLE.asIcon()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt
index 4b75649..cd58127 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractorTest.kt
@@ -16,12 +16,14 @@
package com.android.systemui.qs.tiles.impl.modes.domain.interactor
+import android.graphics.drawable.TestStubDrawable
import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Expandable
+import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
import com.android.systemui.qs.tiles.base.actions.qsTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
@@ -54,10 +56,7 @@
fun handleClick_active() = runTest {
val expandable = mock<Expandable>()
underTest.handleInput(
- QSTileInputTestKtx.click(
- data = ModesTileModel(true, listOf("DND")),
- expandable = expandable
- )
+ QSTileInputTestKtx.click(data = modelOf(true, listOf("DND")), expandable = expandable)
)
verify(mockDialogDelegate).showDialog(eq(expandable))
@@ -67,10 +66,7 @@
fun handleClick_inactive() = runTest {
val expandable = mock<Expandable>()
underTest.handleInput(
- QSTileInputTestKtx.click(
- data = ModesTileModel(false, emptyList()),
- expandable = expandable
- )
+ QSTileInputTestKtx.click(data = modelOf(false, emptyList()), expandable = expandable)
)
verify(mockDialogDelegate).showDialog(eq(expandable))
@@ -78,7 +74,7 @@
@Test
fun handleLongClick_active() = runTest {
- underTest.handleInput(QSTileInputTestKtx.longClick(ModesTileModel(true, listOf("DND"))))
+ underTest.handleInput(QSTileInputTestKtx.longClick(modelOf(true, listOf("DND"))))
QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
assertThat(it.intent.action).isEqualTo(Settings.ACTION_ZEN_MODE_SETTINGS)
@@ -87,10 +83,14 @@
@Test
fun handleLongClick_inactive() = runTest {
- underTest.handleInput(QSTileInputTestKtx.longClick(ModesTileModel(false, emptyList())))
+ underTest.handleInput(QSTileInputTestKtx.longClick(modelOf(false, emptyList())))
QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
assertThat(it.intent.action).isEqualTo(Settings.ACTION_ZEN_MODE_SETTINGS)
}
}
+
+ private fun modelOf(isActivated: Boolean, activeModeNames: List<String>): ModesTileModel {
+ return ModesTileModel(isActivated, activeModeNames, TestStubDrawable("icon").asIcon(), 123)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
index a41f15d..f7bdcb8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
@@ -18,11 +18,12 @@
import android.app.Flags
import android.graphics.drawable.TestStubDrawable
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder
import com.android.systemui.qs.tiles.viewmodel.QSTileState
@@ -58,47 +59,88 @@
@Test
fun inactiveState() {
- val model = ModesTileModel(isActivated = false, activeModes = emptyList())
+ val icon = TestStubDrawable("res123").asIcon()
+ val model =
+ ModesTileModel(
+ isActivated = false,
+ activeModes = emptyList(),
+ icon = icon,
+ )
val state = underTest.map(config, model)
assertThat(state.activationState).isEqualTo(QSTileState.ActivationState.INACTIVE)
- assertThat(state.iconRes).isEqualTo(R.drawable.qs_dnd_icon_off)
+ assertThat(state.icon()).isEqualTo(icon)
assertThat(state.secondaryLabel).isEqualTo("No active modes")
}
@Test
fun activeState_oneMode() {
- val model = ModesTileModel(isActivated = true, activeModes = listOf("DND"))
+ val icon = TestStubDrawable("res123").asIcon()
+ val model =
+ ModesTileModel(
+ isActivated = true,
+ activeModes = listOf("DND"),
+ icon = icon,
+ )
val state = underTest.map(config, model)
assertThat(state.activationState).isEqualTo(QSTileState.ActivationState.ACTIVE)
- assertThat(state.iconRes).isEqualTo(R.drawable.qs_dnd_icon_on)
+ assertThat(state.icon()).isEqualTo(icon)
assertThat(state.secondaryLabel).isEqualTo("DND is active")
}
@Test
fun activeState_multipleModes() {
+ val icon = TestStubDrawable("res123").asIcon()
val model =
- ModesTileModel(isActivated = true, activeModes = listOf("Mode 1", "Mode 2", "Mode 3"))
+ ModesTileModel(
+ isActivated = true,
+ activeModes = listOf("Mode 1", "Mode 2", "Mode 3"),
+ icon = icon,
+ )
val state = underTest.map(config, model)
assertThat(state.activationState).isEqualTo(QSTileState.ActivationState.ACTIVE)
- assertThat(state.iconRes).isEqualTo(R.drawable.qs_dnd_icon_on)
+ assertThat(state.icon()).isEqualTo(icon)
assertThat(state.secondaryLabel).isEqualTo("3 modes are active")
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI_ICONS)
- fun activeState_withIcon() {
- val icon = Icon.Resource(1234, contentDescription = null)
- val model = ModesTileModel(isActivated = true, activeModes = listOf("DND"), icon = icon)
+ fun state_withEnabledFlag_noIconResId() {
+ val icon = TestStubDrawable("res123").asIcon()
+ val model =
+ ModesTileModel(
+ isActivated = false,
+ activeModes = emptyList(),
+ icon = icon,
+ iconResId = 123 // Should not be populated, but is ignored even if present
+ )
val state = underTest.map(config, model)
- assertThat(state.iconRes).isNull()
assertThat(state.icon()).isEqualTo(icon)
+ assertThat(state.iconRes).isNull()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MODES_UI_ICONS)
+ fun state_withDisabledFlag_includesIconResId() {
+ val icon = TestStubDrawable("res123").asIcon()
+ val model =
+ ModesTileModel(
+ isActivated = false,
+ activeModes = emptyList(),
+ icon = icon,
+ iconResId = 123
+ )
+
+ val state = underTest.map(config, model)
+
+ assertThat(state.icon()).isEqualTo(icon)
+ assertThat(state.iconRes).isEqualTo(123)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt
index e2149d9..424afe1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.ui.viewmodel
+import android.platform.test.annotations.DisableFlags
import android.testing.TestableLooper.RunWithLooper
import androidx.lifecycle.LifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -26,20 +27,26 @@
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
import com.android.systemui.media.controls.data.repository.mediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.qs.FooterActionsController
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.startable.sceneContainerStartable
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory
+import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -51,6 +58,7 @@
@RunWith(AndroidJUnit4::class)
@RunWithLooper
@EnableSceneContainer
+@DisableFlags(com.android.systemui.Flags.FLAG_DUAL_SHADE)
class QuickSettingsSceneContentViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -64,6 +72,8 @@
private val footerActionsController = mock<FooterActionsController>()
private val sceneContainerStartable = kosmos.sceneContainerStartable
+ private val sceneInteractor by lazy { kosmos.sceneInteractor }
+ private val shadeInteractor by lazy { kosmos.shadeInteractor }
private lateinit var underTest: QuickSettingsSceneContentViewModel
@@ -80,7 +90,10 @@
footerActionsViewModelFactory = footerActionsViewModelFactory,
footerActionsController = footerActionsController,
mediaCarouselInteractor = kosmos.mediaCarouselInteractor,
+ shadeInteractor = shadeInteractor,
+ sceneInteractor = sceneInteractor,
)
+ underTest.activateIn(testScope)
}
@Test
@@ -122,4 +135,16 @@
assertThat(isMediaVisible).isTrue()
}
+
+ @Test
+ fun shadeModeChange_switchToShadeScene() =
+ testScope.runTest {
+ val scene by collectLastValue(sceneInteractor.currentScene)
+
+ // switch to split shade
+ kosmos.shadeRepository.setShadeLayoutWide(true)
+ runCurrent()
+
+ assertThat(scene).isEqualTo(Scenes.Shade)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModelTest.kt
index 45a8b3e..db58c85 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModelTest.kt
@@ -46,7 +46,6 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -64,14 +63,10 @@
private val underTest by lazy { kosmos.quickSettingsShadeSceneActionsViewModel }
- @Before
- fun setUp() {
- underTest.activateIn(testScope)
- }
-
@Test
fun upTransitionSceneKey_deviceLocked_lockscreen() =
testScope.runTest {
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
lockDevice()
@@ -85,6 +80,7 @@
@Test
fun upTransitionSceneKey_deviceLocked_keyguardDisabled_gone() =
testScope.runTest {
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
lockDevice()
@@ -98,6 +94,7 @@
@Test
fun upTransitionSceneKey_deviceUnlocked_gone() =
testScope.runTest {
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
lockDevice()
@@ -113,6 +110,7 @@
fun downTransitionSceneKey_deviceLocked_bottomAligned_lockscreen() =
testScope.runTest {
kosmos.fakeShadeRepository.setDualShadeAlignedToBottom(true)
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
lockDevice()
@@ -127,6 +125,7 @@
fun downTransitionSceneKey_deviceUnlocked_bottomAligned_gone() =
testScope.runTest {
kosmos.fakeShadeRepository.setDualShadeAlignedToBottom(true)
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
lockDevice()
@@ -141,6 +140,7 @@
@Test
fun upTransitionSceneKey_authMethodSwipe_lockscreenNotDismissed_goesToLockscreen() =
testScope.runTest {
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
@@ -157,6 +157,7 @@
@Test
fun upTransitionSceneKey_authMethodSwipe_lockscreenDismissed_goesToGone() =
testScope.runTest {
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
@@ -174,6 +175,7 @@
@Test
fun backTransitionSceneKey_notEditing_Home() =
testScope.runTest {
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
assertThat((actions?.get(Back) as? UserActionResult.ChangeScene)?.toScene)
@@ -183,6 +185,7 @@
@Test
fun backTransition_editing_noDestination() =
testScope.runTest {
+ underTest.activateIn(this)
val actions by collectLastValue(underTest.actions)
kosmos.editModeViewModel.startEditing()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModelTest.kt
index dd4432d..900f2a4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModelTest.kt
@@ -35,7 +35,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -123,7 +122,7 @@
override suspend fun hydrateActions(
setActions: (Map<UserAction, UserActionResult>) -> Unit,
) {
- upstream.collectLatest { setActions(it) }
+ upstream.collect { setActions(it) }
}
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
index 20d3a7b..639d34d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorTest.kt
@@ -22,8 +22,10 @@
import android.provider.Settings.Secure.ZEN_DURATION
import android.provider.Settings.Secure.ZEN_DURATION_FOREVER
import android.provider.Settings.Secure.ZEN_DURATION_PROMPT
+import android.service.notification.SystemZenRules
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.R
import com.android.settingslib.notification.data.repository.updateNotificationPolicy
import com.android.settingslib.notification.modes.TestModeBuilder
import com.android.systemui.SysuiTestCase
@@ -220,30 +222,86 @@
}
@Test
- fun mainActiveMode_returnsMainActiveMode() =
+ fun activeModes_computesMainActiveMode() =
testScope.runTest {
- val mainActiveMode by collectLastValue(underTest.mainActiveMode)
+ val activeModes by collectLastValue(underTest.activeModes)
zenModeRepository.addMode(id = "Bedtime", type = AutomaticZenRule.TYPE_BEDTIME)
zenModeRepository.addMode(id = "Other", type = AutomaticZenRule.TYPE_OTHER)
runCurrent()
+ assertThat(activeModes?.modeNames).hasSize(0)
+ assertThat(activeModes?.mainMode).isNull()
+
+ zenModeRepository.activateMode("Other")
+ runCurrent()
+ assertThat(activeModes?.modeNames).containsExactly("Mode Other")
+ assertThat(activeModes?.mainMode?.name).isEqualTo("Mode Other")
+
+ zenModeRepository.activateMode("Bedtime")
+ runCurrent()
+ assertThat(activeModes?.modeNames)
+ .containsExactly("Mode Bedtime", "Mode Other")
+ .inOrder()
+ assertThat(activeModes?.mainMode?.name).isEqualTo("Mode Bedtime")
+
+ zenModeRepository.deactivateMode("Other")
+ runCurrent()
+ assertThat(activeModes?.modeNames).containsExactly("Mode Bedtime")
+ assertThat(activeModes?.mainMode?.name).isEqualTo("Mode Bedtime")
+
+ zenModeRepository.deactivateMode("Bedtime")
+ runCurrent()
+ assertThat(activeModes?.modeNames).hasSize(0)
+ assertThat(activeModes?.mainMode).isNull()
+ }
+
+ @Test
+ fun mainActiveMode_flows() =
+ testScope.runTest {
+ val mainActiveMode by collectLastValue(underTest.mainActiveMode)
+
+ zenModeRepository.addModes(
+ listOf(
+ TestModeBuilder()
+ .setId("Bedtime")
+ .setName("Mode Bedtime")
+ .setType(AutomaticZenRule.TYPE_BEDTIME)
+ .setActive(false)
+ .setPackage(mContext.packageName)
+ .setIconResId(R.drawable.ic_zen_mode_type_bedtime)
+ .build(),
+ TestModeBuilder()
+ .setId("Other")
+ .setName("Mode Other")
+ .setType(AutomaticZenRule.TYPE_OTHER)
+ .setActive(false)
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .setIconResId(R.drawable.ic_zen_mode_type_other)
+ .build(),
+ )
+ )
+
+ runCurrent()
assertThat(mainActiveMode).isNull()
zenModeRepository.activateMode("Other")
runCurrent()
- assertThat(mainActiveMode).isNotNull()
- assertThat(mainActiveMode!!.id).isEqualTo("Other")
+ assertThat(mainActiveMode?.name).isEqualTo("Mode Other")
+ assertThat(mainActiveMode?.icon?.key?.resId)
+ .isEqualTo(R.drawable.ic_zen_mode_type_other)
zenModeRepository.activateMode("Bedtime")
runCurrent()
- assertThat(mainActiveMode).isNotNull()
- assertThat(mainActiveMode!!.id).isEqualTo("Bedtime")
+ assertThat(mainActiveMode?.name).isEqualTo("Mode Bedtime")
+ assertThat(mainActiveMode?.icon?.key?.resId)
+ .isEqualTo(R.drawable.ic_zen_mode_type_bedtime)
zenModeRepository.deactivateMode("Other")
runCurrent()
- assertThat(mainActiveMode).isNotNull()
- assertThat(mainActiveMode!!.id).isEqualTo("Bedtime")
+ assertThat(mainActiveMode?.name).isEqualTo("Mode Bedtime")
+ assertThat(mainActiveMode?.icon?.key?.resId)
+ .isEqualTo(R.drawable.ic_zen_mode_type_bedtime)
zenModeRepository.deactivateMode("Bedtime")
runCurrent()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
index 33f379d..a0f6431 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt
@@ -23,7 +23,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.notification.modes.TestModeBuilder
-import com.android.settingslib.notification.modes.ZenIconLoader
import com.android.settingslib.notification.modes.ZenMode
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -35,12 +34,10 @@
import com.android.systemui.statusbar.policy.ui.dialog.mockModesDialogEventLogger
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import com.google.common.util.concurrent.MoreExecutors
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.clearInvocations
@@ -67,11 +64,6 @@
mockDialogEventLogger
)
- @Before
- fun setUp() {
- ZenIconLoader.setInstance(ZenIconLoader(MoreExecutors.newDirectExecutorService()))
- }
-
@Test
fun tiles_filtersOutUserDisabledModes() =
testScope.runTest {
@@ -338,6 +330,83 @@
}
@Test
+ fun tiles_populatesFieldsForAccessibility() =
+ testScope.runTest {
+ val tiles by collectLastValue(underTest.tiles)
+
+ repository.addModes(
+ listOf(
+ TestModeBuilder()
+ .setName("With description, inactive")
+ .setManualInvocationAllowed(true)
+ .setTriggerDescription("When the going gets tough")
+ .setActive(false)
+ .build(),
+ TestModeBuilder()
+ .setName("With description, active")
+ .setManualInvocationAllowed(true)
+ .setTriggerDescription("When in Rome")
+ .setActive(true)
+ .build(),
+ TestModeBuilder()
+ .setName("With description, needs setup")
+ .setManualInvocationAllowed(true)
+ .setTriggerDescription("When you find yourself in a hole")
+ .setEnabled(false, /* byUser= */ false)
+ .build(),
+ TestModeBuilder()
+ .setName("Without description, inactive")
+ .setManualInvocationAllowed(true)
+ .setTriggerDescription(null)
+ .setActive(false)
+ .build(),
+ TestModeBuilder()
+ .setName("Without description, active")
+ .setManualInvocationAllowed(true)
+ .setTriggerDescription(null)
+ .setActive(true)
+ .build(),
+ TestModeBuilder()
+ .setName("Without description, needs setup")
+ .setManualInvocationAllowed(true)
+ .setTriggerDescription(null)
+ .setEnabled(false, /* byUser= */ false)
+ .build(),
+ )
+ )
+ runCurrent()
+
+ assertThat(tiles!!).hasSize(6)
+ with(tiles?.elementAt(0)!!) {
+ assertThat(this.stateDescription).isEqualTo("Off")
+ assertThat(this.subtextDescription).isEqualTo("When the going gets tough")
+ }
+ with(tiles?.elementAt(1)!!) {
+ assertThat(this.stateDescription).isEqualTo("On")
+ assertThat(this.subtextDescription).isEqualTo("When in Rome")
+ }
+ with(tiles?.elementAt(2)!!) {
+ assertThat(this.stateDescription).isEqualTo("Off")
+ assertThat(this.subtextDescription).isEqualTo("Set up")
+ }
+ with(tiles?.elementAt(3)!!) {
+ assertThat(this.stateDescription).isEqualTo("Off")
+ assertThat(this.subtextDescription).isEmpty()
+ }
+ with(tiles?.elementAt(4)!!) {
+ assertThat(this.stateDescription).isEqualTo("On")
+ assertThat(this.subtextDescription).isEmpty()
+ }
+ with(tiles?.elementAt(5)!!) {
+ assertThat(this.stateDescription).isEqualTo("Off")
+ assertThat(this.subtextDescription).isEqualTo("Set up")
+ }
+
+ // All tiles have the same long click info
+ tiles!!.forEach { assertThat(it.onLongClickLabel).isEqualTo("Open settings") }
+ }
+
+ @Test
fun onClick_togglesTileState() =
testScope.runTest {
val tiles by collectLastValue(underTest.tiles)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
index 0f56d0b..fa7f37c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractorTest.kt
@@ -90,8 +90,9 @@
assertThat(model)
.isEqualTo(
MediaOutputComponentModel.Calling(
- AudioOutputDevice.BuiltIn(builtInDeviceName, testIcon),
- false,
+ device = AudioOutputDevice.BuiltIn(builtInDeviceName, testIcon),
+ isInAudioSharing = false,
+ canOpenAudioSwitcher = false,
)
)
}
@@ -101,6 +102,9 @@
fun hasSession_stateIs_MediaSession() =
with(kosmos) {
testScope.runTest {
+ localMediaRepository.updateCurrentConnectedDevice(
+ TestMediaDevicesFactory.builtInMediaDevice()
+ )
mediaControllerRepository.setActiveSessions(listOf(localMediaController))
val model by collectLastValue(underTest.mediaOutputModel.filterData())
@@ -113,6 +117,7 @@
assertThat(device)
.isEqualTo(AudioOutputDevice.BuiltIn("built_in_media", testIcon))
assertThat(isInAudioSharing).isFalse()
+ assertThat(canOpenAudioSwitcher).isTrue()
}
}
}
@@ -129,8 +134,9 @@
assertThat(model)
.isEqualTo(
MediaOutputComponentModel.Idle(
- AudioOutputDevice.BuiltIn("built_in_media", testIcon),
- true,
+ device = AudioOutputDevice.BuiltIn("built_in_media", testIcon),
+ isInAudioSharing = true,
+ canOpenAudioSwitcher = false,
)
)
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e6cc6cf..1307301 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -270,6 +270,7 @@
<!-- Add to note button used in App Clips flow to return the saved screenshot image to notes app. [CHAR LIMIT=NONE] -->
<string name="app_clips_save_add_to_note">Add to note</string>
<string name="backlinks_include_link">Include link</string>
+ <string name="backlinks_duplicate_label_format"><xliff:g id="appName" example="Google Chrome">%1$s</xliff:g> <xliff:g id="frequencyCount" example="(1)">(%2$d)</xliff:g></string>
<!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
<string name="screenrecord_title">Screen Recorder</string>
@@ -1379,9 +1380,13 @@
<string name="media_projection_entry_app_permission_dialog_title">Share your screen with <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g>?</string>
<!-- 1P/3P app media projection permission option for capturing just a single app [CHAR LIMIT=50] -->
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app">Share one app</string>
+ <string name="screen_share_permission_dialog_option_single_app">Share one app</string>
+ <!-- CTS tests rely on the `screen_share_permission_dialog_option_single_app` resource name, so just point the updated resource name to the old resource name. -->
+ <string name="media_projection_entry_app_permission_dialog_option_text_single_app">@string/screen_share_permission_dialog_option_single_app</string>
<!-- 1P/3P app media projection permission option for capturing the whole screen [CHAR LIMIT=50] -->
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen">Share entire screen</string>
+ <string name="screen_share_permission_dialog_option_entire_screen">Share entire screen</string>
+ <!-- CTS tests rely on the `screen_share_permission_dialog_option_entire_screen` resource name, so just point the updated resource name to the old resource name. -->
+ <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen">@string/screen_share_permission_dialog_option_entire_screen</string>
<!-- 1P/3P app media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] -->
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen">When you’re sharing your entire screen, anything on your screen is visible to <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
<!-- 1P/3P app media projection permission warning for capturing an app. [CHAR LIMIT=350] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 490ad5c..3ad73bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -19,9 +19,12 @@
import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
@@ -170,8 +173,33 @@
mPasswordEntry.setOnEditorActionListener(mOnEditorActionListener);
mPasswordEntry.setOnKeyListener(mKeyListener);
mPasswordEntry.addTextChangedListener(mTextWatcher);
+
// Poke the wakelock any time the text is selected or modified
- mPasswordEntry.setOnClickListener(v -> mKeyguardSecurityCallback.userActivity());
+ // TODO(b/362362385): Revert to the previous onClickListener implementation once this bug is
+ // fixed.
+ mPasswordEntry.setOnClickListener(new View.OnClickListener() {
+
+ private final boolean mAutomotiveAndVisibleBackgroundUsers =
+ isAutomotiveAndVisibleBackgroundUsers();
+
+ @Override
+ public void onClick(View v) {
+ if (mAutomotiveAndVisibleBackgroundUsers) {
+ mInputMethodManager.restartInput(v);
+ }
+ mKeyguardSecurityCallback.userActivity();
+ }
+
+ private boolean isAutomotiveAndVisibleBackgroundUsers() {
+ final Context context = getContext();
+ return context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE)
+ && UserManager.isVisibleBackgroundUsersEnabled()
+ && context.getResources().getBoolean(
+ android.R.bool.config_perDisplayFocusEnabled);
+ }
+ });
+
mSwitchImeButton.setOnClickListener(v -> {
mKeyguardSecurityCallback.userActivity(); // Leave the screen on a bit longer
// Do not show auxiliary subtypes in password lock screen.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index afd42cb..2d28a18 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -35,7 +35,6 @@
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
-import android.app.admin.flags.Flags;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -81,7 +80,7 @@
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardWmStateRefactor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -134,7 +133,7 @@
private final DeviceEntryFaceAuthInteractor mDeviceEntryFaceAuthInteractor;
private final BouncerMessageInteractor mBouncerMessageInteractor;
private int mTranslationY;
- private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final KeyguardDismissTransitionInteractor mKeyguardDismissTransitionInteractor;
private final DevicePolicyManager mDevicePolicyManager;
// Whether the volume keys should be handled by keyguard. If true, then
// they will be handled here for specific media types such as music, otherwise
@@ -321,7 +320,7 @@
}
if (KeyguardWmStateRefactor.isEnabled()) {
- mKeyguardTransitionInteractor.startDismissKeyguardTransition(
+ mKeyguardDismissTransitionInteractor.startDismissKeyguardTransition(
"KeyguardSecurityContainerController#finish");
}
}
@@ -458,7 +457,7 @@
DeviceProvisionedController deviceProvisionedController,
FaceAuthAccessibilityDelegate faceAuthAccessibilityDelegate,
DevicePolicyManager devicePolicyManager,
- KeyguardTransitionInteractor keyguardTransitionInteractor,
+ KeyguardDismissTransitionInteractor keyguardDismissTransitionInteractor,
Lazy<PrimaryBouncerInteractor> primaryBouncerInteractor,
Provider<DeviceEntryInteractor> deviceEntryInteractor
) {
@@ -490,7 +489,7 @@
mSelectedUserInteractor = selectedUserInteractor;
mDeviceEntryInteractor = deviceEntryInteractor;
mJavaAdapter = javaAdapter;
- mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mKeyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor;
mDeviceProvisionedController = deviceProvisionedController;
mPrimaryBouncerInteractor = primaryBouncerInteractor;
mDevicePolicyManager = devicePolicyManager;
@@ -1140,12 +1139,7 @@
int remainingBeforeWipe, int failedAttempts) {
int userType = USER_TYPE_PRIMARY;
if (expiringUserId == userId) {
- int primaryUser = UserHandle.USER_SYSTEM;
- if (Flags.headlessSingleUserFixes()) {
- if (mainUserId != null) {
- primaryUser = mainUserId;
- }
- }
+ int primaryUser = mainUserId != null ? mainUserId : UserHandle.USER_SYSTEM;
// TODO: http://b/23522538
if (expiringUserId != primaryUser) {
userType = USER_TYPE_SECONDARY_USER;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 9b45fa4..f731186 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -3811,7 +3811,8 @@
if (!mSimDatas.containsKey(subId)) {
refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
}
- return mSimDatas.get(subId).slotId;
+ SimData simData = mSimDatas.get(subId);
+ return simData != null ? simData.slotId : SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 9b6501e..2f0ca6e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -482,6 +482,10 @@
} else { // mode = ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
mEditButton.setVisibility(View.VISIBLE);
mAllowDiagonalScrollingView.setVisibility(View.VISIBLE);
+ if (Flags.saveAndRestoreMagnificationSettingsButtons()) {
+ selectedButtonIndex =
+ windowMagnificationFrameSizePrefs.getIndexForCurrentDensity();
+ }
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index e4b7b7e..275147e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -21,11 +21,13 @@
import android.content.Context;
import android.hardware.display.DisplayManager;
+import android.os.Handler;
import android.os.UserHandle;
import android.text.TextUtils;
import android.view.Display;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IUserInitializationCompleteCallback;
import androidx.annotation.MainThread;
@@ -68,6 +70,9 @@
private int mBtnMode;
private String mBtnTargets;
private boolean mIsKeyguardVisible;
+ private boolean mIsUserInInitialization;
+ @VisibleForTesting
+ Handler mHandler;
@VisibleForTesting
final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() {
@@ -86,18 +91,14 @@
@Override
public void onUserSwitching(int userId) {
destroyFloatingMenu();
- }
-
- @Override
- public void onUserSwitchComplete(int userId) {
- mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
- mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
- mBtnTargets =
- mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
- handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
+ mIsUserInInitialization = true;
}
};
+ @VisibleForTesting
+ final UserInitializationCompleteCallback mUserInitializationCompleteCallback =
+ new UserInitializationCompleteCallback();
+
@Inject
public AccessibilityFloatingMenuController(Context context,
WindowManager windowManager,
@@ -109,7 +110,8 @@
KeyguardUpdateMonitor keyguardUpdateMonitor,
SecureSettings secureSettings,
DisplayTracker displayTracker,
- NavigationModeController navigationModeController) {
+ NavigationModeController navigationModeController,
+ Handler handler) {
mContext = context;
mWindowManager = windowManager;
mViewCaptureAwareWindowManager = viewCaptureAwareWindowManager;
@@ -121,6 +123,7 @@
mSecureSettings = secureSettings;
mDisplayTracker = displayTracker;
mNavigationModeController = navigationModeController;
+ mHandler = handler;
mIsKeyguardVisible = false;
}
@@ -159,6 +162,8 @@
mAccessibilityButtonModeObserver.addListener(this);
mAccessibilityButtonTargetsObserver.addListener(this);
mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback);
+ mAccessibilityManager.registerUserInitializationCompleteCallback(
+ mUserInitializationCompleteCallback);
}
/**
@@ -172,7 +177,7 @@
*/
private void handleFloatingMenuVisibility(boolean keyguardVisible,
@AccessibilityButtonMode int mode, String targets) {
- if (keyguardVisible) {
+ if (keyguardVisible || mIsUserInInitialization) {
destroyFloatingMenu();
return;
}
@@ -210,4 +215,18 @@
mFloatingMenu.hide();
mFloatingMenu = null;
}
+
+ class UserInitializationCompleteCallback
+ extends IUserInitializationCompleteCallback.Stub {
+ @Override
+ public void onUserInitializationComplete(int userId) {
+ mIsUserInInitialization = false;
+ mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
+ mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
+ mBtnTargets =
+ mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
+ mHandler.post(
+ () -> handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets));
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
index 03f282e..bb80396 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
@@ -120,42 +120,42 @@
@IntoMap
@StringKey(COLOR_CORRECTION_TILE_SPEC)
fun provideColorCorrectionAvailabilityInteractor(
- impl: ColorCorrectionTileDataInteractor
+ impl: ColorCorrectionTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(COLOR_INVERSION_TILE_SPEC)
fun provideColorInversionAvailabilityInteractor(
- impl: ColorCorrectionTileDataInteractor
+ impl: ColorCorrectionTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(FONT_SCALING_TILE_SPEC)
fun provideFontScalingAvailabilityInteractor(
- impl: FontScalingTileDataInteractor
+ impl: FontScalingTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(REDUCE_BRIGHTNESS_TILE_SPEC)
fun provideReduceBrightnessAvailabilityInteractor(
- impl: ReduceBrightColorsTileDataInteractor
+ impl: ReduceBrightColorsTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(ONE_HANDED_TILE_SPEC)
fun provideOneHandedAvailabilityInteractor(
- impl: OneHandedModeTileDataInteractor
+ impl: OneHandedModeTileDataInteractor
): QSTileAvailabilityInteractor
@Binds
@IntoMap
@StringKey(NIGHT_DISPLAY_TILE_SPEC)
fun provideNightDisplayAvailabilityInteractor(
- impl: NightDisplayTileDataInteractor
+ impl: NightDisplayTileDataInteractor
): QSTileAvailabilityInteractor
companion object {
@@ -165,6 +165,7 @@
const val REDUCE_BRIGHTNESS_TILE_SPEC = "reduce_brightness"
const val ONE_HANDED_TILE_SPEC = "onehanded"
const val NIGHT_DISPLAY_TILE_SPEC = "night"
+ const val HEARING_DEVICES_TILE_SPEC = "hearing_devices"
@Provides
@IntoMap
@@ -273,6 +274,20 @@
instanceId = uiEventLogger.getNewInstanceId(),
)
+ @Provides
+ @IntoMap
+ @StringKey(HEARING_DEVICES_TILE_SPEC)
+ fun provideHearingDevicesTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(HEARING_DEVICES_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.qs_hearing_devices_icon,
+ labelRes = R.string.quick_settings_hearing_devices_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
/**
* Inject Reduce Bright Colors Tile into tileViewModelMap in QSModule. The tile is hidden
* behind a flag.
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
index a093f58..fd06bb1 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
@@ -29,7 +29,6 @@
import androidx.annotation.VisibleForTesting
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
-import com.android.internal.widget.LockPatternUtils
import com.android.systemui.Flags
import com.android.systemui.ambient.touch.TouchHandler.TouchSession
import com.android.systemui.ambient.touch.dagger.BouncerSwipeModule
@@ -37,8 +36,8 @@
import com.android.systemui.ambient.touch.scrim.ScrimManager
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -63,8 +62,6 @@
private val notificationShadeWindowController: NotificationShadeWindowController,
private val valueAnimatorCreator: ValueAnimatorCreator,
private val velocityTrackerFactory: VelocityTrackerFactory,
- private val lockPatternUtils: LockPatternUtils,
- private val userTracker: UserTracker,
private val communalViewModel: CommunalViewModel,
@param:Named(BouncerSwipeModule.SWIPE_TO_BOUNCER_FLING_ANIMATION_UTILS_OPENING)
private val flingAnimationUtils: FlingAnimationUtils,
@@ -75,7 +72,8 @@
@param:Named(BouncerSwipeModule.MIN_BOUNCER_ZONE_SCREEN_PERCENTAGE)
private val minBouncerZoneScreenPercentage: Float,
private val uiEventLogger: UiEventLogger,
- private val activityStarter: ActivityStarter
+ private val activityStarter: ActivityStarter,
+ private val keyguardInteractor: KeyguardInteractor,
) : TouchHandler {
/** An interface for creating ValueAnimators. */
interface ValueAnimatorCreator {
@@ -148,7 +146,7 @@
// If scrolling up and keyguard is not locked, dismiss both keyguard and the
// dream since there's no bouncer to show.
- if (y > e2.y && !lockPatternUtils.isSecure(userTracker.userId)) {
+ if (y > e2.y && keyguardInteractor.isKeyguardDismissible.value) {
activityStarter.executeRunnableDismissingKeyguard(
{ centralSurfaces.get().awakenDreams() },
/* cancelAction= */ null,
@@ -331,8 +329,8 @@
return
}
- // Don't set expansion if the user doesn't have a pin/password set.
- if (!lockPatternUtils.isSecure(userTracker.userId)) {
+ // Don't set expansion if keyguard is dismissible (i.e. unlocked).
+ if (keyguardInteractor.isKeyguardDismissible.value) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index fcba425..3080e19 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -16,7 +16,6 @@
package com.android.systemui.authentication.domain.interactor
-import android.app.admin.flags.Flags
import android.os.UserHandle
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternView
@@ -289,12 +288,7 @@
private suspend fun getWipeTarget(): WipeTarget {
// Check which profile has the strictest policy for failed authentication attempts.
val userToBeWiped = repository.getProfileWithMinFailedUnlockAttemptsForWipe()
- val primaryUser =
- if (Flags.headlessSingleUserFixes()) {
- selectedUserInteractor.getMainUserId() ?: UserHandle.USER_SYSTEM
- } else {
- UserHandle.USER_SYSTEM
- }
+ val primaryUser = selectedUserInteractor.getMainUserId() ?: UserHandle.USER_SYSTEM
return when (userToBeWiped) {
selectedUserInteractor.getSelectedUserId() ->
if (userToBeWiped == primaryUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
index 05b4656..e54dc7d 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModel.kt
@@ -155,7 +155,7 @@
emptyFlow()
}
}
- .collectLatest { messageViewModel -> message.value = messageViewModel }
+ .collect { messageViewModel -> message.value = messageViewModel }
}
private suspend fun listenForSimBouncerEvents() {
@@ -170,7 +170,7 @@
emptyFlow()
}
}
- .collectLatest {
+ .collect {
if (it != null) {
message.value = it
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneActionsViewModel.kt
index 2a27271..2d57e5b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneActionsViewModel.kt
@@ -25,7 +25,6 @@
import com.android.systemui.scene.ui.viewmodel.SceneActionsViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
/**
@@ -46,7 +45,7 @@
Swipe(SwipeDirection.Down) to UserActionResult(prevScene),
)
}
- .collectLatest { actions -> setActions(actions) }
+ .collect { actions -> setActions(actions) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
index b985fc4..adc4bc9 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerSceneContentViewModel.kt
@@ -160,7 +160,7 @@
launch {
userSwitcher.selectedUser
.map { it.image.toBitmap() }
- .collectLatest { _selectedUserImage.value = it }
+ .collect { _selectedUserImage.value = it }
}
launch {
@@ -187,34 +187,32 @@
)
}
}
- .collectLatest { _userSwitcherDropdown.value = it }
+ .collect { _userSwitcherDropdown.value = it }
}
launch {
combine(wipeDialogMessage, lockoutDialogMessage) { _, _ -> createDialogViewModel() }
- .collectLatest { _dialogViewModel.value = it }
+ .collect { _dialogViewModel.value = it }
}
- launch {
- actionButtonInteractor.actionButton.collectLatest { _actionButton.value = it }
- }
+ launch { actionButtonInteractor.actionButton.collect { _actionButton.value = it } }
launch {
authMethodViewModel
.map { authMethod -> isSideBySideSupported(authMethod) }
- .collectLatest { _isSideBySideSupported.value = it }
+ .collect { _isSideBySideSupported.value = it }
}
launch {
authMethodViewModel
.map { authMethod -> isFoldSplitRequired(authMethod) }
- .collectLatest { _isFoldSplitRequired.value = it }
+ .collect { _isFoldSplitRequired.value = it }
}
launch {
message.isLockoutMessagePresent
.map { lockoutMessagePresent -> !lockoutMessagePresent }
- .collectLatest { _isInputEnabled.value = it }
+ .collect { _isInputEnabled.value = it }
}
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index fc860e5..2493cf1 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -34,7 +34,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
@@ -105,11 +104,9 @@
combine(isInputEnabled, isTextFieldFocused) { hasInput, hasFocus ->
hasInput && !hasFocus
}
- .collectLatest { _isTextFieldFocusRequested.value = it }
+ .collect { _isTextFieldFocusRequested.value = it }
}
- launch {
- selectedUserInteractor.selectedUser.collectLatest { _selectedUserId.value = it }
- }
+ launch { selectedUserInteractor.selectedUser.collect { _selectedUserId.value = it } }
launch {
// Re-fetch the currently-enabled IMEs whenever the selected user changes, and
// whenever
@@ -125,7 +122,7 @@
) { selectedUserId, _ ->
inputMethodInteractor.hasMultipleEnabledImesOrSubtypes(selectedUserId)
}
- .collectLatest { _isImeSwitcherButtonVisible.value = it }
+ .collect { _isImeSwitcherButtonVisible.value = it }
}
awaitCancellation()
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 60ec3019..0a866b4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -34,7 +34,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
@@ -86,9 +85,7 @@
coroutineScope {
launch { super.onActivated() }
launch {
- selectedDotSet
- .map { it.toList() }
- .collectLatest { selectedDotList.value = it.toList() }
+ selectedDotSet.map { it.toList() }.collect { selectedDotList.value = it.toList() }
}
awaitCancellation()
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index db78a98..df6ca9b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -42,7 +42,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -123,7 +122,7 @@
} else {
interactor.hintedPinLength
}
- .collectLatest { _hintedPinLength.value = it }
+ .collect { _hintedPinLength.value = it }
}
launch {
combine(
@@ -135,17 +134,17 @@
isAutoConfirmEnabled = isAutoConfirmEnabled,
)
}
- .collectLatest { _backspaceButtonAppearance.value = it }
+ .collect { _backspaceButtonAppearance.value = it }
}
launch {
interactor.isAutoConfirmEnabled
.map { if (it) ActionButtonAppearance.Hidden else ActionButtonAppearance.Shown }
- .collectLatest { _confirmButtonAppearance.value = it }
+ .collect { _confirmButtonAppearance.value = it }
}
launch {
interactor.isPinEnhancedPrivacyEnabled
.map { !it }
- .collectLatest { _isDigitButtonAnimationEnabled.value = it }
+ .collect { _isDigitButtonAnimationEnabled.value = it }
}
awaitCancellation()
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
index 3cdb573..aef5f1f 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
@@ -38,5 +38,5 @@
}
/** Creates [Icon.Loaded] for a given drawable with an optional [contentDescription]. */
-fun Drawable.asIcon(contentDescription: ContentDescription? = null): Icon =
+fun Drawable.asIcon(contentDescription: ContentDescription? = null): Icon.Loaded =
Icon.Loaded(this, contentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
index dff391a..f591410 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt
@@ -60,14 +60,23 @@
fun unregisterListener(listener: FaceAuthenticationListener)
fun onUdfpsSensorTouched()
+
fun onAssistantTriggeredOnLockScreen()
+
fun onDeviceLifted()
- fun onQsExpansionStared()
+
+ fun onQsExpansionStarted()
+
fun onNotificationPanelClicked()
+
fun onSwipeUpOnBouncer()
+
fun onPrimaryBouncerUserInput()
+
fun onAccessibilityAction()
+
fun onWalletLaunched()
+
fun onDeviceUnfolded()
/** Whether face auth is considered class 3 */
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
index de5d0aa..b7d2a57 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt
@@ -47,6 +47,7 @@
override fun isFaceAuthEnabledAndEnrolled(): Boolean = false
override fun isFaceAuthStrong(): Boolean = false
+
override fun start() = Unit
override fun registerListener(listener: FaceAuthenticationListener) {}
@@ -59,13 +60,17 @@
override fun onDeviceLifted() {}
- override fun onQsExpansionStared() {}
+ override fun onQsExpansionStarted() {}
override fun onNotificationPanelClicked() {}
override fun onSwipeUpOnBouncer() {}
+
override fun onPrimaryBouncerUserInput() {}
+
override fun onAccessibilityAction() {}
+
override fun onWalletLaunched() = Unit
+
override fun onDeviceUnfolded() {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
index 183e0e9..5ef63d9b 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
@@ -60,6 +60,7 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
@@ -214,6 +215,16 @@
}
}
.launchIn(applicationScope)
+
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor
+ .get()
+ .transitionState
+ .filter { it.isTransitioning(from = Scenes.QuickSettings, to = Scenes.Shade) }
+ .distinctUntilChanged()
+ .onEach { onQsExpansionStarted() }
+ .launchIn(applicationScope)
+ }
}
private val isBouncerVisible: Flow<Boolean> by lazy {
@@ -239,7 +250,7 @@
runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED, true)
}
- override fun onQsExpansionStared() {
+ override fun onQsExpansionStarted() {
runFaceAuth(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED, true)
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 40e2f17..1f5878b 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -48,6 +48,7 @@
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.shareIn
@@ -184,6 +185,9 @@
if (Flags.enableEfficientDisplayRepository()) {
enabledDisplayIds
.mapElementsLazily { displayId -> getDisplay(displayId) }
+ .onEach {
+ if (it.isEmpty()) Log.wtf(TAG, "No enabled displays. This should never happen.")
+ }
.flowOn(backgroundCoroutineDispatcher)
.debugLog("enabledDisplays")
.stateIn(
@@ -194,7 +198,8 @@
// performance concerns.
// Ultimately, this is a trade-off between a one-time UI thread binder call and
// the constant overhead of sharedFlows.
- initialValue = getDisplays())
+ initialValue = getDisplays()
+ )
} else {
oldEnabledDisplays
}
@@ -380,9 +385,8 @@
val resultSet: Set<V>
)
- val initialState = State(emptySet<T>(), emptyMap(), emptySet<V>())
-
- return this.scan(initialState) { state, currentSet ->
+ val emptyInitialState = State(emptySet<T>(), emptyMap(), emptySet<V>())
+ return this.scan(emptyInitialState) { state, currentSet ->
if (currentSet == state.previousSet) {
state
} else {
@@ -397,6 +401,7 @@
State(currentSet, newMap, resultSet)
}
}
+ .filter { it != emptyInitialState }
.map { it.resultSet }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index 180afb2..e89594e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -23,7 +23,7 @@
import android.view.WindowManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier
import com.android.systemui.statusbar.policy.KeyguardStateController
import java.util.concurrent.Executor
@@ -41,7 +41,7 @@
private val activityTaskManagerService: IActivityTaskManager,
private val keyguardStateController: KeyguardStateController,
private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor,
) {
/**
@@ -148,7 +148,7 @@
// a transition to GONE. This transition needs to start even if we're not provided an app
// animation target - it's possible the app is destroyed on creation, etc. but we'll still
// be unlocking.
- keyguardTransitionInteractor.startDismissKeyguardTransition(
+ keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
reason = "Going away remote animation started"
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 1042ae3..e4b0f6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -35,7 +35,6 @@
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -49,7 +48,6 @@
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
-@ExperimentalCoroutinesApi
@SysUISingleton
class FromAlternateBouncerTransitionInteractor
@Inject
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt
new file mode 100644
index 0000000..c19bbbc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissTransitionInteractor.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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.keyguard.domain.interactor
+
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import javax.inject.Inject
+
+@SysUISingleton
+class KeyguardDismissTransitionInteractor
+@Inject
+constructor(
+ private val repository: KeyguardTransitionRepository,
+ private val fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor,
+ private val fromPrimaryBouncerTransitionInteractor: FromPrimaryBouncerTransitionInteractor,
+ private val fromAodTransitionInteractor: FromAodTransitionInteractor,
+ private val fromAlternateBouncerTransitionInteractor: FromAlternateBouncerTransitionInteractor,
+ private val fromDozingTransitionInteractor: FromDozingTransitionInteractor,
+ private val fromOccludedTransitionInteractor: FromOccludedTransitionInteractor,
+) {
+
+ /**
+ * Called to start a transition that will ultimately dismiss the keyguard from the current
+ * state.
+ *
+ * This is called exclusively by sources that can authoritatively say we should be unlocked,
+ * including KeyguardSecurityContainerController and WindowManager.
+ */
+ fun startDismissKeyguardTransition(reason: String = "") {
+ if (SceneContainerFlag.isEnabled) return
+ Log.d(TAG, "#startDismissKeyguardTransition(reason=$reason)")
+ when (val startedState = repository.currentTransitionInfoInternal.value.to) {
+ LOCKSCREEN -> fromLockscreenTransitionInteractor.dismissKeyguard()
+ PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.dismissPrimaryBouncer()
+ ALTERNATE_BOUNCER -> fromAlternateBouncerTransitionInteractor.dismissAlternateBouncer()
+ AOD -> fromAodTransitionInteractor.dismissAod()
+ DOZING -> fromDozingTransitionInteractor.dismissFromDozing()
+ KeyguardState.OCCLUDED -> fromOccludedTransitionInteractor.dismissFromOccluded()
+ KeyguardState.GONE ->
+ Log.i(
+ TAG,
+ "Already transitioning to GONE; ignoring startDismissKeyguardTransition."
+ )
+ else -> Log.e(TAG, "We don't know how to dismiss keyguard from state $startedState.")
+ }
+ }
+
+ companion object {
+ private val TAG = KeyguardDismissTransitionInteractor::class.simpleName
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
index 4aef808..44aafab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
@@ -48,7 +48,7 @@
@Application scope: CoroutineScope,
val repository: KeyguardRepository,
val biometricSettingsRepository: BiometricSettingsRepository,
- transitionInteractor: KeyguardTransitionInteractor,
+ keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor,
internalTransitionInteractor: InternalKeyguardTransitionInteractor,
) {
@@ -94,7 +94,9 @@
showKeyguardWhenReenabled
.filter { shouldDismiss -> shouldDismiss }
.collect {
- transitionInteractor.startDismissKeyguardTransition("keyguard disabled")
+ keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
+ "keyguard disabled"
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 92e2a91..d11a41e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -25,14 +25,7 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
-import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
-import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
-import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
-import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
-import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
-import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.KeyguardState.UNDEFINED
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -67,14 +60,6 @@
constructor(
@Application val scope: CoroutineScope,
private val repository: KeyguardTransitionRepository,
- private val fromLockscreenTransitionInteractor: dagger.Lazy<FromLockscreenTransitionInteractor>,
- private val fromPrimaryBouncerTransitionInteractor:
- dagger.Lazy<FromPrimaryBouncerTransitionInteractor>,
- private val fromAodTransitionInteractor: dagger.Lazy<FromAodTransitionInteractor>,
- private val fromAlternateBouncerTransitionInteractor:
- dagger.Lazy<FromAlternateBouncerTransitionInteractor>,
- private val fromDozingTransitionInteractor: dagger.Lazy<FromDozingTransitionInteractor>,
- private val fromOccludedTransitionInteractor: dagger.Lazy<FromOccludedTransitionInteractor>,
private val sceneInteractor: SceneInteractor,
) {
private val transitionMap = mutableMapOf<Edge.StateToState, MutableSharedFlow<TransitionStep>>()
@@ -365,33 +350,6 @@
}
/**
- * Called to start a transition that will ultimately dismiss the keyguard from the current
- * state.
- *
- * This is called exclusively by sources that can authoritatively say we should be unlocked,
- * including KeyguardSecurityContainerController and WindowManager.
- */
- fun startDismissKeyguardTransition(reason: String = "") {
- if (SceneContainerFlag.isEnabled) return
- Log.d(TAG, "#startDismissKeyguardTransition(reason=$reason)")
- when (val startedState = repository.currentTransitionInfoInternal.value.to) {
- LOCKSCREEN -> fromLockscreenTransitionInteractor.get().dismissKeyguard()
- PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.get().dismissPrimaryBouncer()
- ALTERNATE_BOUNCER ->
- fromAlternateBouncerTransitionInteractor.get().dismissAlternateBouncer()
- AOD -> fromAodTransitionInteractor.get().dismissAod()
- DOZING -> fromDozingTransitionInteractor.get().dismissFromDozing()
- OCCLUDED -> fromOccludedTransitionInteractor.get().dismissFromOccluded()
- GONE ->
- Log.i(
- TAG,
- "Already transitioning to GONE; ignoring startDismissKeyguardTransition."
- )
- else -> Log.e(TAG, "We don't know how to dismiss keyguard from state $startedState.")
- }
- }
-
- /**
* Whether we're in a transition to and from the given [KeyguardState]s, but haven't yet
* completed it.
*
@@ -464,6 +422,17 @@
return finishedKeyguardState.map { it == state }.distinctUntilChanged()
}
+ fun isCurrentlyIn(scene: SceneKey, stateWithoutSceneContainer: KeyguardState): Flow<Boolean> {
+ return if (SceneContainerFlag.isEnabled) {
+ // In STL there is no difference between finished/currentState
+ isFinishedIn(scene, stateWithoutSceneContainer)
+ } else {
+ stateWithoutSceneContainer.checkValidState()
+ currentKeyguardState.map { it == stateWithoutSceneContainer }
+ }
+ .distinctUntilChanged()
+ }
+
fun getCurrentState(): KeyguardState {
return currentKeyguardState.replayCache.last()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
index f0bf402..9b8d9ea1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardWakeDirectlyToGoneInteractor.kt
@@ -37,6 +37,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.Companion.deviceIsAwakeInState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.settings.SecureSettings
@@ -181,14 +182,20 @@
scope.launch {
powerInteractor.detailedWakefulness
.distinctUntilChangedBy { it.isAwake() }
- .sample(transitionInteractor.currentKeyguardState, ::Pair)
- .collect { (wakefulness, currentState) ->
+ .sample(
+ transitionInteractor.isCurrentlyIn(
+ Scenes.Gone,
+ stateWithoutSceneContainer = KeyguardState.GONE
+ ),
+ ::Pair
+ )
+ .collect { (wakefulness, finishedInGone) ->
// Save isAwake for use in onDreamingStarted/onDreamingStopped.
this@KeyguardWakeDirectlyToGoneInteractor.isAwake = wakefulness.isAwake()
// If we're sleeping from GONE, check the timeout and lock instantly settings.
// These are not relevant if we're coming from non-GONE states.
- if (!isAwake && currentState == KeyguardState.GONE) {
+ if (!isAwake && finishedInGone) {
val lockTimeoutDuration = getCanIgnoreAuthAndReturnToGoneDuration()
// If the screen timed out and went to sleep, and the lock timeout is > 0ms,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
index 0032c2f..e2ad4635 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -46,6 +46,7 @@
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.OccludedToDozingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OffToLockscreenTransitionViewModel
@@ -205,6 +206,12 @@
@Binds
@IntoSet
+ abstract fun occludedToDozing(
+ impl: OccludedToDozingTransitionViewModel
+ ): DeviceEntryIconTransition
+
+ @Binds
+ @IntoSet
abstract fun occludedToLockscreen(
impl: OccludedToLockscreenTransitionViewModel
): DeviceEntryIconTransition
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 6f8389f..9f68210 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -59,6 +59,7 @@
alternateBouncerToDozingTransitionViewModel: AlternateBouncerToDozingTransitionViewModel,
dreamingToAodTransitionViewModel: DreamingToAodTransitionViewModel,
primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
+ occludedToDozingTransitionViewModel: OccludedToDozingTransitionViewModel,
) {
val color: Flow<Int> =
deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -103,6 +104,7 @@
dreamingToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
primaryBouncerToLockscreenTransitionViewModel
.deviceEntryBackgroundViewAlpha,
+ occludedToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
)
.merge()
.onStart {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index fcafd5e..adb63b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -40,7 +40,6 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
@@ -91,13 +90,13 @@
end = end,
)
}
- .collectLatest { _unfoldTranslations.value = it }
+ .collect { _unfoldTranslations.value = it }
}
launch {
occlusionInteractor.isOccludingActivityShown
.map { !it }
- .collectLatest { _isContentVisible.value = it }
+ .collect { _isContentVisible.value = it }
}
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneActionsViewModel.kt
index 7383f57..2819e61 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneActionsViewModel.kt
@@ -35,7 +35,6 @@
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
@@ -100,7 +99,7 @@
}
}
}
- .collectLatest { setActions(it) }
+ .collect { setActions(it) }
}
private fun swipeDownFromTop(pointerCount: Int): Swipe {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModel.kt
index af01930..4fb2b9b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModel.kt
@@ -17,15 +17,19 @@
package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
/**
* Breaks down OCCLUDED->DOZING transition into discrete steps for corresponding views to consume.
@@ -35,8 +39,9 @@
class OccludedToDozingTransitionViewModel
@Inject
constructor(
+ deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
animationFlow: KeyguardTransitionAnimationFlow,
-) {
+) : DeviceEntryIconTransition {
private val transitionAnimation =
animationFlow.setup(
duration = FromOccludedTransitionInteractor.TO_DOZING_DURATION,
@@ -50,4 +55,17 @@
duration = 250.milliseconds,
onStep = { it },
)
+
+ val deviceEntryBackgroundViewAlpha: Flow<Float> =
+ transitionAnimation.immediatelyTransitionTo(0f)
+
+ override val deviceEntryParentViewAlpha: Flow<Float> =
+ deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
+ ->
+ if (udfpsEnrolledAndEnabled) {
+ transitionAnimation.immediatelyTransitionTo(1f)
+ } else {
+ emptyFlow()
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
index 378a147..bcf748e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
@@ -59,13 +59,14 @@
val playOrPause =
if (isConnectingState(state.state)) {
// Spinner needs to be animating to render anything. Start it here.
- val drawable = MediaControlDrawables.getProgress(context)
+ val drawable =
+ context.getDrawable(com.android.internal.R.drawable.progress_small_material)
(drawable as Animatable).start()
MediaAction(
drawable,
null, // no action to perform when clicked
context.getString(R.string.controls_media_button_connecting),
- MediaControlDrawables.getConnecting(context),
+ context.getDrawable(R.drawable.ic_media_connecting_container),
// Specify a rebind id to prevent the spinner from restarting on later binds.
com.android.internal.R.drawable.progress_small_material
)
@@ -153,18 +154,18 @@
return when (action) {
PlaybackState.ACTION_PLAY -> {
MediaAction(
- MediaControlDrawables.getPlayIcon(context),
+ context.getDrawable(R.drawable.ic_media_play),
{ controller.transportControls.play() },
context.getString(R.string.controls_media_button_play),
- MediaControlDrawables.getPlayBackground(context)
+ context.getDrawable(R.drawable.ic_media_play_container)
)
}
PlaybackState.ACTION_PAUSE -> {
MediaAction(
- MediaControlDrawables.getPauseIcon(context),
+ context.getDrawable(R.drawable.ic_media_pause),
{ controller.transportControls.pause() },
context.getString(R.string.controls_media_button_pause),
- MediaControlDrawables.getPauseBackground(context)
+ context.getDrawable(R.drawable.ic_media_pause_container)
)
}
PlaybackState.ACTION_SKIP_TO_PREVIOUS -> {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
index 415449f..4555810 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
@@ -71,7 +71,6 @@
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager.Companion.isMediaNotification
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
-import com.android.systemui.media.controls.shared.MediaControlDrawables
import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_SOURCE
import com.android.systemui.media.controls.shared.model.EXTRA_VALUE_TRIGGER_PERIODIC
import com.android.systemui.media.controls.shared.model.MediaAction
@@ -1229,7 +1228,7 @@
.loadDrawable(context),
action,
context.getString(R.string.controls_media_resume),
- MediaControlDrawables.getPlayBackground(context)
+ context.getDrawable(R.drawable.ic_media_play_container)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt
index c78220e..95ca11c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt
@@ -17,20 +17,12 @@
package com.android.systemui.media.controls.shared
import android.content.Context
-import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
import com.android.systemui.Flags.mediaControlsDrawablesReuse
import com.android.systemui.res.R
object MediaControlDrawables {
- // Play/Pause Button drawables.
- private var progress: Drawable? = null
- private var connecting: Drawable? = null
- private var playIcon: AnimatedVectorDrawable? = null
- private var playBackground: AnimatedVectorDrawable? = null
- private var pauseIcon: AnimatedVectorDrawable? = null
- private var pauseBackground: AnimatedVectorDrawable? = null
// Prev button.
private var prevIcon: Drawable? = null
// Next button.
@@ -40,81 +32,6 @@
private var antenna: Drawable? = null
private var groupDevice: Drawable? = null
private var homeDevices: Drawable? = null
- // Guts drawables.
- private var outline: Drawable? = null
- private var solid: Drawable? = null
-
- fun getProgress(context: Context): Drawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(com.android.internal.R.drawable.progress_small_material)
- }
- return progress?.mutate()
- ?: context.getDrawable(com.android.internal.R.drawable.progress_small_material).also {
- progress = it
- }
- }
-
- fun getConnecting(context: Context): Drawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(R.drawable.ic_media_connecting_container)
- }
- return connecting?.mutate()
- ?: context.getDrawable(R.drawable.ic_media_connecting_container).also {
- connecting = it
- }
- }
-
- fun getPlayIcon(context: Context): AnimatedVectorDrawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(R.drawable.ic_media_play) as AnimatedVectorDrawable?
- }
- return playIcon?.let {
- it.reset()
- it.mutate() as AnimatedVectorDrawable
- }
- ?: (context.getDrawable(R.drawable.ic_media_play) as AnimatedVectorDrawable?).also {
- playIcon = it
- }
- }
-
- fun getPlayBackground(context: Context): AnimatedVectorDrawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(R.drawable.ic_media_play_container)
- as AnimatedVectorDrawable?
- }
- return playBackground?.let {
- it.reset()
- it.mutate() as AnimatedVectorDrawable
- }
- ?: (context.getDrawable(R.drawable.ic_media_play_container) as AnimatedVectorDrawable?)
- .also { playBackground = it }
- }
-
- fun getPauseIcon(context: Context): AnimatedVectorDrawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(R.drawable.ic_media_pause) as AnimatedVectorDrawable?
- }
- return pauseIcon?.let {
- it.reset()
- it.mutate() as AnimatedVectorDrawable
- }
- ?: (context.getDrawable(R.drawable.ic_media_pause) as AnimatedVectorDrawable?).also {
- pauseIcon = it
- }
- }
-
- fun getPauseBackground(context: Context): AnimatedVectorDrawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(R.drawable.ic_media_pause_container)
- as AnimatedVectorDrawable?
- }
- return pauseBackground?.let {
- it.reset()
- it.mutate() as AnimatedVectorDrawable
- }
- ?: (context.getDrawable(R.drawable.ic_media_pause_container) as AnimatedVectorDrawable?)
- .also { pauseBackground = it }
- }
fun getNextIcon(context: Context): Drawable? {
if (!mediaControlsDrawablesReuse()) {
@@ -165,19 +82,4 @@
return homeDevices
?: context.getDrawable(R.drawable.ic_media_home_devices).also { homeDevices = it }
}
-
- fun getOutline(context: Context): Drawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(R.drawable.qs_media_outline_button)
- }
- return outline
- ?: context.getDrawable(R.drawable.qs_media_outline_button).also { outline = it }
- }
-
- fun getSolid(context: Context): Drawable? {
- if (!mediaControlsDrawablesReuse()) {
- return context.getDrawable(R.drawable.qs_media_solid_button)
- }
- return solid ?: context.getDrawable(R.drawable.qs_media_solid_button).also { solid = it }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
index f460134..64820e0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
@@ -30,7 +30,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaControlInteractor
-import com.android.systemui.media.controls.shared.MediaControlDrawables
import com.android.systemui.media.controls.shared.model.MediaAction
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaControlModel
@@ -285,9 +284,9 @@
},
cancelTextBackground =
if (model.isDismissible) {
- MediaControlDrawables.getOutline(applicationContext)
+ applicationContext.getDrawable(R.drawable.qs_media_outline_button)
} else {
- MediaControlDrawables.getSolid(applicationContext)
+ applicationContext.getDrawable(R.drawable.qs_media_solid_button)
},
onSettingsClicked = {
logger.logLongPressSettings(model.uid, model.packageName, model.instanceId)
diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
new file mode 100644
index 0000000..db988f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 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.notifications.ui.viewmodel
+
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.TransitionKeys
+import com.android.systemui.scene.ui.viewmodel.SceneActionsViewModel
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeAlignment
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/** Models the UI state for the user actions for navigating to other scenes or overlays. */
+class NotificationsShadeOverlayActionsViewModel
+@AssistedInject
+constructor(
+ private val shadeInteractor: ShadeInteractor,
+) : SceneActionsViewModel() {
+
+ override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
+ setActions(
+ mapOf(
+ if (shadeInteractor.shadeAlignment == ShadeAlignment.Top) {
+ Swipe.Up to UserActionResult.HideOverlay(Overlays.NotificationsShade)
+ } else {
+ Swipe.Down to
+ UserActionResult.HideOverlay(
+ overlay = Overlays.NotificationsShade,
+ transitionKey = TransitionKeys.OpenBottomShade,
+ )
+ },
+ Back to UserActionResult.HideOverlay(Overlays.NotificationsShade),
+ )
+ )
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(): NotificationsShadeOverlayActionsViewModel
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
index d948dfd..c75b601 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.panels.ui.compose
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.runtime.Composable
@@ -24,7 +23,6 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.dimensionResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
@@ -33,7 +31,6 @@
import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.res.R
import javax.inject.Inject
@SysUISingleton
@@ -64,7 +61,7 @@
Tile(
tile = sizedTiles[index].tile,
iconOnly = iconTilesViewModel.isIconTile(sizedTiles[index].tile.spec),
- modifier = Modifier.height(dimensionResource(id = R.dimen.qs_tile_height))
+ modifier = Modifier
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index a9027ff..eeb55ca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -16,18 +16,15 @@
package com.android.systemui.qs.panels.ui.compose
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.dimensionResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel
-import com.android.systemui.res.R
@Composable
fun QuickQuickSettings(
@@ -54,11 +51,7 @@
key = { index -> sizedTiles[index].tile.spec.spec },
span = { index -> GridItemSpan(sizedTiles[index].width) }
) { index ->
- Tile(
- tile = tiles[index],
- iconOnly = sizedTiles[index].isIcon,
- modifier = Modifier.height(dimensionResource(id = R.dimen.qs_tile_height))
- )
+ Tile(tile = tiles[index], iconOnly = sizedTiles[index].isIcon, modifier = Modifier)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
index 79c2eb9..24af09d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
@@ -44,7 +44,6 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -136,23 +135,23 @@
// TODO(b/361789146): Draw the shapes instead of clipping
val tileShape = TileDefaults.animateTileShape(uiState.state)
- val iconShape = TileDefaults.animateIconShape(uiState.state)
TileContainer(
colors = colors,
showLabels = showLabels,
label = uiState.label,
iconOnly = iconOnly,
- shape = if (iconOnly) iconShape else tileShape,
+ shape = tileShape,
clickEnabled = true,
onClick = tile::onClick,
onLongClick = tile::onLongClick,
- modifier = modifier,
+ modifier = modifier.height(tileHeight()),
) {
val icon = getTileIcon(icon = uiState.icon)
if (iconOnly) {
TileIcon(icon = icon, color = colors.icon, modifier = Modifier.align(Alignment.Center))
} else {
+ val iconShape = TileDefaults.animateIconShape(uiState.state)
LargeTileContent(
label = uiState.label,
secondaryLabel = uiState.secondaryLabel,
@@ -199,7 +198,7 @@
Expandable(
color = backgroundColor,
shape = shape,
- modifier = Modifier.height(dimensionResource(id = R.dimen.qs_tile_height)).clip(shape)
+ modifier = Modifier.height(tileHeight()).clip(shape)
) {
Box(
modifier =
@@ -246,7 +245,7 @@
// Icon
Box(
modifier =
- Modifier.fillMaxHeight().aspectRatio(1f).thenIf(toggleClickSupported) {
+ Modifier.size(TileDefaults.ToggleTargetSize).thenIf(toggleClickSupported) {
Modifier.clip(iconShape)
.background(colors.iconBackground, { 1f })
.combinedClickable(onClick = onClick, onLongClick = onLongClick)
@@ -673,7 +672,7 @@
animateToEnd: Boolean = false,
modifier: Modifier = Modifier,
) {
- val iconModifier = modifier.size(dimensionResource(id = R.dimen.qs_icon_size))
+ val iconModifier = modifier.size(TileDefaults.IconSize)
val context = LocalContext.current
val loadedDrawable =
remember(icon, context) {
@@ -710,17 +709,12 @@
}
}
-@Composable
private fun Modifier.tilePadding(): Modifier {
- return padding(dimensionResource(id = R.dimen.qs_label_container_margin))
+ return padding(TileDefaults.TilePadding)
}
-@Composable
private fun tileHorizontalArrangement(): Arrangement.Horizontal {
- return spacedBy(
- space = dimensionResource(id = R.dimen.qs_label_container_margin),
- alignment = Alignment.Start
- )
+ return spacedBy(space = TileDefaults.TileArrangementPadding, alignment = Alignment.Start)
}
@Composable
@@ -728,7 +722,7 @@
return if (iconWithLabel) {
TileDefaults.IconTileWithLabelHeight
} else {
- dimensionResource(id = R.dimen.qs_tile_height)
+ TileDefaults.TileHeight
}
}
@@ -749,6 +743,14 @@
val InactiveCornerRadius = 50.dp
val ActiveIconCornerRadius = 16.dp
val ActiveTileCornerRadius = 24.dp
+
+ val ToggleTargetSize = 56.dp
+ val IconSize = 24.dp
+
+ val TilePadding = 8.dp
+ val TileArrangementPadding = 6.dp
+
+ val TileHeight = 72.dp
val IconTileWithLabelHeight = 140.dp
/** An active tile without dual target uses the active color as background */
@@ -812,7 +814,7 @@
fun animateIconShape(state: Int): Shape {
return animateShape(
state = state,
- activeCornerRadius = ActiveTileCornerRadius,
+ activeCornerRadius = ActiveIconCornerRadius,
label = "QSTileCornerRadius",
)
}
@@ -821,7 +823,7 @@
fun animateTileShape(state: Int): Shape {
return animateShape(
state = state,
- activeCornerRadius = ActiveIconCornerRadius,
+ activeCornerRadius = ActiveTileCornerRadius,
label = "QSTileIconCornerRadius",
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
index 71f8639..89b9eee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
@@ -306,6 +306,8 @@
mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(context));
mWifiRecyclerView.setAdapter(mAdapter);
+
+ updateDialogUI(getWifiNetworkContent());
}
@Override
@@ -315,6 +317,7 @@
}
mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
+
mInternetDialogController.onStart(this, mCanConfigWifi);
if (!mCanConfigWifi) {
hideWifiViews();
@@ -402,10 +405,12 @@
internetContent.mShouldUpdateMobileNetwork = shouldUpdateMobileNetwork;
internetContent.mInternetDialogTitleString = getDialogTitleText();
internetContent.mInternetDialogSubTitle = getSubtitleText();
- internetContent.mActiveNetworkIsCellular =
- mInternetDialogController.activeNetworkIsCellular();
- internetContent.mIsCarrierNetworkActive =
- mInternetDialogController.isCarrierNetworkActive();
+ if (shouldUpdateMobileNetwork) {
+ internetContent.mActiveNetworkIsCellular =
+ mInternetDialogController.activeNetworkIsCellular();
+ internetContent.mIsCarrierNetworkActive =
+ mInternetDialogController.isCarrierNetworkActive();
+ }
internetContent.mIsAirplaneModeEnabled = mInternetDialogController.isAirplaneModeEnabled();
internetContent.mHasEthernet = mInternetDialogController.hasEthernet();
internetContent.mIsWifiEnabled = mInternetDialogController.isWifiEnabled();
@@ -416,6 +421,15 @@
return internetContent;
}
+ private InternetContent getWifiNetworkContent() {
+ InternetContent internetContent = new InternetContent();
+ internetContent.mInternetDialogTitleString = getDialogTitleText();
+ internetContent.mInternetDialogSubTitle = getSubtitleText();
+ internetContent.mIsWifiEnabled = mInternetDialogController.isWifiEnabled();
+ internetContent.mIsDeviceLocked = mInternetDialogController.isDeviceLocked();
+ return internetContent;
+ }
+
private void setOnClickListener(SystemUIDialog dialog) {
mMobileNetworkLayout.setOnClickListener(v -> {
int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 3f18fc2..664951d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -20,10 +20,12 @@
import android.content.Context
import android.os.UserHandle
import com.android.app.tracing.coroutines.flow.map
+import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
+import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -52,18 +54,32 @@
*/
fun tileData() =
zenModeInteractor.activeModes
- .map { modes ->
- ModesTileModel(
- isActivated = modes.isNotEmpty(),
- icon =
- if (Flags.modesApi() && Flags.modesUi() && Flags.modesUiIcons())
- zenModeInteractor.getActiveModeIcon(modes)
- else null,
- activeModes = modes.map { it.name }
- )
+ .map { activeModes ->
+ val modesIconResId = R.drawable.qs_dnd_icon_off
+
+ if (usesModeIcons()) {
+ val mainModeDrawable = activeModes.mainMode?.icon?.drawable
+ val iconResId = if (mainModeDrawable == null) modesIconResId else null
+
+ ModesTileModel(
+ isActivated = activeModes.isAnyActive(),
+ icon = (mainModeDrawable ?: context.getDrawable(modesIconResId)!!).asIcon(),
+ iconResId = iconResId,
+ activeModes = activeModes.modeNames
+ )
+ } else {
+ ModesTileModel(
+ isActivated = activeModes.isAnyActive(),
+ icon = context.getDrawable(modesIconResId)!!.asIcon(),
+ iconResId = modesIconResId,
+ activeModes = activeModes.modeNames
+ )
+ }
}
.flowOn(bgDispatcher)
.distinctUntilChanged()
override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi())
+
+ private fun usesModeIcons() = Flags.modesApi() && Flags.modesUi() && Flags.modesUiIcons()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
index 904ff3a..db48123 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/model/ModesTileModel.kt
@@ -21,5 +21,12 @@
data class ModesTileModel(
val isActivated: Boolean,
val activeModes: List<String>,
- val icon: Icon? = null
+ val icon: Icon.Loaded,
+
+ /**
+ * Resource id corresponding to [icon]. Will only be present if it's know to correspond to a
+ * resource with a known id in SystemUI (such as resources from `android.R`,
+ * `com.android.internal.R`, or `com.android.systemui.res` itself).
+ */
+ val iconResId: Int? = null
)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
index 83c3335..7f571b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
@@ -16,11 +16,9 @@
package com.android.systemui.qs.tiles.impl.modes.ui
-import android.app.Flags
import android.content.res.Resources
import android.icu.text.MessageFormat
import android.widget.Button
-import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
@@ -38,15 +36,10 @@
) : QSTileDataToStateMapper<ModesTileModel> {
override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState =
QSTileState.build(resources, theme, config.uiConfig) {
- if (Flags.modesApi() && Flags.modesUi() && Flags.modesUiIcons() && data.icon != null) {
- icon = { data.icon }
- } else {
- val iconRes =
- if (data.isActivated) R.drawable.qs_dnd_icon_on else R.drawable.qs_dnd_icon_off
- val icon = resources.getDrawable(iconRes, theme).asIcon()
- this.iconRes = iconRes
- this.icon = { icon }
+ if (!android.app.Flags.modesUiIcons()) {
+ iconRes = data.iconResId
}
+ icon = { data.icon }
activationState =
if (data.isActivated) {
QSTileState.ActivationState.ACTIVE
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt
index af55f5a..2bb5dc66 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneActionsViewModel.kt
@@ -31,7 +31,6 @@
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
@@ -78,7 +77,7 @@
}
}
}
- .collectLatest { actions -> setActions(actions) }
+ .collect { actions -> setActions(actions) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt
index 93bf73f..a264f51 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt
@@ -17,16 +17,24 @@
package com.android.systemui.qs.ui.viewmodel
import androidx.lifecycle.LifecycleOwner
+import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.qs.FooterActionsController
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import java.util.concurrent.atomic.AtomicBoolean
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
/**
* Models UI state needed for rendering the content of the quick settings scene.
@@ -43,7 +51,9 @@
private val footerActionsViewModelFactory: FooterActionsViewModel.Factory,
private val footerActionsController: FooterActionsController,
val mediaCarouselInteractor: MediaCarouselInteractor,
-) {
+ private val shadeInteractor: ShadeInteractor,
+ private val sceneInteractor: SceneInteractor,
+) : ExclusiveActivatable() {
val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasAnyMediaOrRecommendation
@@ -56,6 +66,19 @@
return footerActionsViewModelFactory.create(lifecycleOwner)
}
+ override suspend fun onActivated(): Nothing {
+ coroutineScope {
+ launch {
+ shadeInteractor.shadeMode.collect { shadeMode ->
+ if (shadeMode == ShadeMode.Split) {
+ sceneInteractor.snapToScene(Scenes.Shade, "Unfold while on QS")
+ }
+ }
+ }
+ awaitCancellation()
+ }
+ }
+
@AssistedFactory
interface Factory {
fun create(): QuickSettingsSceneContentViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModel.kt
index d2967b8..9956a46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneActionsViewModel.kt
@@ -29,7 +29,6 @@
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
/**
@@ -62,7 +61,7 @@
}
}
}
- .collectLatest { actions -> setActions(actions) }
+ .collect { actions -> setActions(actions) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index 6e89973..98cf941 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -27,6 +27,7 @@
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
import com.android.systemui.scene.domain.startable.StatusBarStartable
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shared.flag.DualShade
@@ -42,6 +43,7 @@
[
EmptySceneModule::class,
GoneSceneModule::class,
+ NotificationsShadeOverlayModule::class,
NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
QuickSettingsSceneModule::class,
@@ -99,6 +101,10 @@
Scenes.Shade.takeUnless { DualShade.isEnabled },
),
initialSceneKey = Scenes.Gone,
+ overlayKeys =
+ listOfNotNull(
+ Overlays.NotificationsShade.takeIf { DualShade.isEnabled },
+ ),
navigationDistances =
mapOf(
Scenes.Gone to 0,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 7d63b4c..86b2427 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -28,6 +28,7 @@
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
import com.android.systemui.scene.domain.startable.StatusBarStartable
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shared.flag.DualShade
@@ -50,6 +51,7 @@
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
QuickSettingsShadeSceneModule::class,
+ NotificationsShadeOverlayModule::class,
NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
SceneDomainModule::class,
@@ -108,6 +110,10 @@
Scenes.Shade.takeUnless { DualShade.isEnabled },
),
initialSceneKey = Scenes.Lockscreen,
+ overlayKeys =
+ listOfNotNull(
+ Overlays.NotificationsShade.takeIf { DualShade.isEnabled },
+ ),
navigationDistances =
mapOf(
Scenes.Gone to 0,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
index c176cca..2d40845 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt
@@ -58,29 +58,20 @@
fun onSceneChange(from: SceneKey, to: SceneKey) {
check(from != to) { "from == to, from=${from.debugName}, to=${to.debugName}" }
- when (stackOperation(from, to)) {
- Clear -> {
- _backStack.value = sceneStackOf()
- }
- Push -> {
- _backStack.update { s -> s.push(from) }
- }
- Pop -> {
- _backStack.update { s ->
- checkNotNull(s.pop()) { "Cannot pop ${from.debugName} when stack is empty" }
- .also {
- val popped = s.peek()
- check(popped == to) {
- "Expected to pop ${to.debugName} but instead popped ${popped?.debugName}"
- }
- }
- }
+
+ _backStack.update { stack ->
+ when (stackOperation(from, to, stack)) {
+ null -> stack
+ Clear -> sceneStackOf()
+ Push -> stack.push(from)
+ Pop ->
+ checkNotNull(stack.pop()) { "Cannot pop ${from.debugName} when stack is empty" }
}
}
logger.logSceneBackStack(backStack.value.asIterable())
}
- private fun stackOperation(from: SceneKey, to: SceneKey): StackOperation {
+ private fun stackOperation(from: SceneKey, to: SceneKey, stack: SceneStack): StackOperation? {
val fromDistance =
checkNotNull(sceneContainerConfig.navigationDistances[from]) {
"No distance mapping for scene \"${from.debugName}\"!"
@@ -93,6 +84,7 @@
return when {
toDistance == 0 -> Clear
toDistance > fromDistance -> Push
+ stack.peek() != to -> null
toDistance < fromDistance -> Pop
else ->
error(
@@ -103,7 +95,10 @@
}
private sealed interface StackOperation
+
private data object Clear : StackOperation
+
private data object Push : StackOperation
+
private data object Pop : StackOperation
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Overlays.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Overlays.kt
new file mode 100644
index 0000000..0bb02e9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Overlays.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 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.scene.shared.model
+
+import com.android.compose.animation.scene.OverlayKey
+
+/**
+ * Keys of all known overlays.
+ *
+ * PLEASE KEEP THE KEYS SORTED ALPHABETICALLY.
+ */
+object Overlays {
+ /**
+ * The notifications shade overlay primarily shows a scrollable list of notifications.
+ *
+ * It's used only in the dual shade configuration, where there are two separate shades: one for
+ * notifications (this overlay) and another for [QuickSettingsShade].
+ *
+ * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
+ * swipe down again the to expand quick settings) or in the "split" shade configuration (on
+ * large screens or unfolded foldables, where notifications and quick settings are shown
+ * side-by-side in their own columns).
+ */
+ @JvmField val NotificationsShade = OverlayKey("notifications_shade")
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneActionsViewModel.kt
index b707a5a..88d4c4f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneActionsViewModel.kt
@@ -29,7 +29,6 @@
import com.android.systemui.shade.shared.model.ShadeMode
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
class GoneSceneActionsViewModel
@@ -82,7 +81,7 @@
}
}
}
- .collectLatest { setActions(it) }
+ .collect { setActions(it) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt
index 368e4fa..0766130 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneActionsViewModel.kt
@@ -32,6 +32,7 @@
* need to worry about resetting the value of [actions] when the view-model is deactivated/canceled,
* this base class takes care of it.
*/
+// TODO(b/363206563): Rename to UserActionsViewModel.
abstract class SceneActionsViewModel : ExclusiveActivatable() {
private val _actions = MutableStateFlow<Map<UserAction, UserActionResult>>(emptyMap())
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
index 9db1f24..ad5e772 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
@@ -71,7 +71,9 @@
import com.android.systemui.screenshot.scroll.CropView;
import com.android.systemui.settings.UserTracker;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
@@ -344,10 +346,63 @@
// Set up the dropdown when multiple backlinks are available.
if (backlinksData.size() > 1) {
- setUpListPopupWindow(backlinksData, mBacklinksDataTextView);
+ setUpListPopupWindow(updateBacklinkLabelsWithDuplicateNames(backlinksData),
+ mBacklinksDataTextView);
}
}
+ /**
+ * If there are more than 1 backlinks that have the same app name, then this method appends
+ * a numerical suffix to such backlinks to help users distinguish.
+ */
+ private List<InternalBacklinksData> updateBacklinkLabelsWithDuplicateNames(
+ List<InternalBacklinksData> backlinksData) {
+ // Check if there are multiple backlinks with same name.
+ Map<String, Integer> duplicateNamedBacklinksCountMap = new HashMap<>();
+ for (InternalBacklinksData data : backlinksData) {
+ if (duplicateNamedBacklinksCountMap.containsKey(data.getDisplayLabel())) {
+ int duplicateCount = duplicateNamedBacklinksCountMap.get(data.getDisplayLabel());
+ if (duplicateCount == 0) {
+ // If this is the first time the loop is coming across a duplicate name, set the
+ // count to 2. This way the count starts from 1 for all duplicate named
+ // backlinks.
+ duplicateNamedBacklinksCountMap.put(data.getDisplayLabel(), 2);
+ } else {
+ // For all duplicate named backlinks, increase the duplicate count by 1.
+ duplicateNamedBacklinksCountMap.put(data.getDisplayLabel(), duplicateCount + 1);
+ }
+ } else {
+ // This is the first time the loop is coming across a backlink with this name. Set
+ // its count to 0. The loop will increase its count by 1 when a duplicate is found.
+ duplicateNamedBacklinksCountMap.put(data.getDisplayLabel(), 0);
+ }
+ }
+
+ // Go through the backlinks in reverse order as it is easier to assign the numerical suffix
+ // in descending order of frequency using the duplicate map that was built earlier. For
+ // example, if "App A" is present 3 times, then we assign display label "App A (3)" first
+ // and then "App A (2)", lastly "App A (1)".
+ for (InternalBacklinksData data : backlinksData.reversed()) {
+ String originalBacklinkLabel = data.getDisplayLabel();
+ int duplicateCount = duplicateNamedBacklinksCountMap.get(originalBacklinkLabel);
+
+ // The display label should only be updated if there are multiple backlinks with the
+ // same name.
+ if (duplicateCount > 0) {
+ // Update the display label to: "App name (count)"
+ data.setDisplayLabel(
+ getString(R.string.backlinks_duplicate_label_format, originalBacklinkLabel,
+ duplicateCount));
+
+ // Decrease the duplicate count and update the map.
+ duplicateCount--;
+ duplicateNamedBacklinksCountMap.put(originalBacklinkLabel, duplicateCount);
+ }
+ }
+
+ return backlinksData;
+ }
+
private void setUpListPopupWindow(List<InternalBacklinksData> backlinksData, View anchor) {
ListPopupWindow listPopupWindow = new ListPopupWindow(this);
listPopupWindow.setAnchorView(anchor);
@@ -365,7 +420,7 @@
public View getView(int position, @Nullable View convertView, ViewGroup parent) {
TextView itemView = (TextView) super.getView(position, convertView, parent);
InternalBacklinksData data = backlinksData.get(position);
- itemView.setText(data.getClipData().getDescription().getLabel());
+ itemView.setText(data.getDisplayLabel());
Drawable icon = data.getAppIcon();
icon.setBounds(createBacklinksTextViewDrawableBounds());
@@ -387,7 +442,7 @@
* expected to be already set when this method is called.
*/
private void updateBacklinksTextView(InternalBacklinksData backlinksData) {
- mBacklinksDataTextView.setText(backlinksData.getClipData().getDescription().getLabel());
+ mBacklinksDataTextView.setText(backlinksData.getDisplayLabel());
Drawable appIcon = backlinksData.getAppIcon();
Rect compoundDrawableBounds = createBacklinksTextViewDrawableBounds();
appIcon.setBounds(compoundDrawableBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt
index 0e312f9..30c33c5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt
@@ -20,4 +20,6 @@
import android.graphics.drawable.Drawable
/** A class to hold the [ClipData] for backlinks and the corresponding app's [Drawable] icon. */
-internal data class InternalBacklinksData(val clipData: ClipData, val appIcon: Drawable)
+internal data class InternalBacklinksData(val clipData: ClipData, val appIcon: Drawable) {
+ var displayLabel: String = clipData.description.label.toString()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
index e7ee961..edff4bf 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
@@ -17,6 +17,7 @@
package com.android.systemui.settings
import android.view.Display
+import com.android.systemui.util.annotations.WeaklyReferencedCallback
import java.util.concurrent.Executor
/**
@@ -52,6 +53,7 @@
fun getDisplay(displayId: Int): Display
/** Ćallback for notifying of changes. */
+ @WeaklyReferencedCallback
interface Callback {
/** Notifies that a display has been added. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 4639e22..3bb494b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -203,6 +203,13 @@
*/
private var shadeConsumingTouches = false
+ /**
+ * True if the shade is showing at all.
+ *
+ * Inverse of [ShadeInteractor.isShadeFullyCollapsed]
+ */
+ private var shadeShowing = false
+
/** True if the keyguard transition state is finished on [KeyguardState.LOCKSCREEN]. */
private var onLockscreen = false
@@ -414,6 +421,7 @@
),
{ (isFullyExpanded, isUserInteracting, isShadeFullyCollapsed) ->
shadeConsumingTouches = isUserInteracting
+ shadeShowing = !isShadeFullyCollapsed
val expandedAndNotInteractive = isFullyExpanded && !isUserInteracting
// If we ever are fully expanded and not interacting, capture this state as we
@@ -529,7 +537,7 @@
val isMove = ev.actionMasked == MotionEvent.ACTION_MOVE
val isCancel = ev.actionMasked == MotionEvent.ACTION_CANCEL
- val hubOccluded = anyBouncerShowing || shadeShowingAndConsumingTouches
+ val hubOccluded = anyBouncerShowing || shadeConsumingTouches || shadeShowing
if ((isDown || isMove) && !hubOccluded) {
if (isDown) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 5537c6b..31813b2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -191,7 +191,6 @@
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor;
-import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor;
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -608,7 +607,6 @@
private final PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
private final SharedNotificationContainerInteractor mSharedNotificationContainerInteractor;
private final ActiveNotificationsInteractor mActiveNotificationsInteractor;
- private final HeadsUpNotificationInteractor mHeadsUpNotificationInteractor;
private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
private final KeyguardInteractor mKeyguardInteractor;
private final PowerInteractor mPowerInteractor;
@@ -774,7 +772,6 @@
ActivityStarter activityStarter,
SharedNotificationContainerInteractor sharedNotificationContainerInteractor,
ActiveNotificationsInteractor activeNotificationsInteractor,
- HeadsUpNotificationInteractor headsUpNotificationInteractor,
ShadeAnimationInteractor shadeAnimationInteractor,
KeyguardViewConfigurator keyguardViewConfigurator,
DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor,
@@ -809,7 +806,6 @@
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
mSharedNotificationContainerInteractor = sharedNotificationContainerInteractor;
mActiveNotificationsInteractor = activeNotificationsInteractor;
- mHeadsUpNotificationInteractor = headsUpNotificationInteractor;
mKeyguardInteractor = keyguardInteractor;
mPowerInteractor = powerInteractor;
mKeyguardViewConfigurator = keyguardViewConfigurator;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
index 16aef65..34c0cb7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
@@ -1005,7 +1005,7 @@
// When expanding QS, let's authenticate the user if possible,
// this will speed up notification actions.
if (height == 0 && !mKeyguardStateController.canDismissLockScreen()) {
- mDeviceEntryFaceAuthInteractor.onQsExpansionStared();
+ mDeviceEntryFaceAuthInteractor.onQsExpansionStarted();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
index c210fc5..abf1f4c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
@@ -28,7 +28,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.collectLatest
/**
* Models UI state and handles user input for the overlay shade UI, which shows a shade as an
@@ -48,7 +47,7 @@
val panelAlignment = shadeInteractor.shadeAlignment
override suspend fun onActivated(): Nothing {
- sceneInteractor.resolveSceneFamily(SceneFamilies.Home).collectLatest { sceneKey ->
+ sceneInteractor.resolveSceneFamily(SceneFamilies.Home).collect { sceneKey ->
_backgroundScene.value = sceneKey
}
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index c8abb1f..a154e91 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -46,7 +46,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -132,12 +131,10 @@
launch {
mobileIconsInteractor.filteredSubscriptions
.map { list -> list.map { it.subscriptionId } }
- .collectLatest { _mobileSubIds.value = it }
+ .collect { _mobileSubIds.value = it }
}
- launch {
- shadeInteractor.isQsEnabled.map { !it }.collectLatest { _isDisabled.value = it }
- }
+ launch { shadeInteractor.isQsEnabled.map { !it }.collect { _isDisabled.value = it } }
awaitCancellation()
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneActionsViewModel.kt
index bdc0fdb..ab71913 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneActionsViewModel.kt
@@ -29,7 +29,6 @@
import com.android.systemui.shade.shared.model.ShadeMode
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
/**
@@ -67,7 +66,7 @@
}
}
}
- .collectLatest { actions -> setActions(actions) }
+ .collect { actions -> setActions(actions) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
index 7a79a22..7c70759 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModel.kt
@@ -35,12 +35,10 @@
import dagger.assisted.AssistedInject
import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.collectLatest
/**
* Models UI state used to render the content of the shade scene.
@@ -75,11 +73,9 @@
private val footerActionsControllerInitialized = AtomicBoolean(false)
override suspend fun onActivated(): Nothing {
- deviceEntryInteractor.isDeviceEntered.collectLatest { isDeviceEntered ->
+ deviceEntryInteractor.isDeviceEntered.collect { isDeviceEntered ->
_isEmptySpaceClickable.value = !isDeviceEntered
}
-
- awaitCancellation()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 696e222..d523bc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -255,8 +255,8 @@
}
final float stackBottom = SceneContainerFlag.isEnabled()
- ? ambientState.getStackTop() + ambientState.getStackHeight()
- : ambientState.getStackY() + ambientState.getStackHeight();
+ ? ambientState.getStackTop() + ambientState.getInterpolatedStackHeight()
+ : ambientState.getStackY() + ambientState.getInterpolatedStackHeight();
if (viewState.hidden) {
// if the shelf is hidden, position it at the end of the stack (plus the clip
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 6eadd26..2b44c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -58,6 +58,7 @@
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIcon.Shape;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Flags;
import com.android.systemui.res.R;
@@ -211,16 +212,19 @@
/** Should always be preceded by {@link #reloadDimens()} */
@VisibleForTesting
public void maybeUpdateIconScaleDimens() {
- // We do not resize and scale system icons (on the right), only notification icons (on the
- // left).
- if (isNotification()) {
- updateIconScaleForNotifications();
+ // We scale notification icons (on the left) plus icons on the right that explicitly
+ // want FIXED_SPACE.
+ boolean useNonSystemIconScaling = isNotification()
+ || (usesModeIcons() && mIcon != null && mIcon.shape == Shape.FIXED_SPACE);
+
+ if (useNonSystemIconScaling) {
+ updateIconScaleForNonSystemIcons();
} else {
updateIconScaleForSystemIcons();
}
}
- private void updateIconScaleForNotifications() {
+ private void updateIconScaleForNonSystemIcons() {
float iconScale;
// we need to scale the image size to be same as the original size
// (fit mOriginalStatusBarIconSize), then we can scale it with mScaleToFitNewIconSize
@@ -411,7 +415,9 @@
if (!levelEquals) {
setImageLevel(icon.iconLevel);
}
-
+ if (usesModeIcons()) {
+ setScaleType(icon.shape == Shape.FIXED_SPACE ? ScaleType.FIT_CENTER : ScaleType.CENTER);
+ }
if (!visibilityEquals) {
setVisibility(icon.visible && !mBlocked ? VISIBLE : GONE);
}
@@ -501,7 +507,12 @@
@Nullable
private Drawable loadDrawable(Context context, StatusBarIcon statusBarIcon) {
if (usesModeIcons() && statusBarIcon.preloadedIcon != null) {
- return statusBarIcon.preloadedIcon.mutate();
+ Drawable.ConstantState cached = statusBarIcon.preloadedIcon.getConstantState();
+ if (cached != null) {
+ return cached.newDrawable(mContext.getResources()).mutate();
+ } else {
+ return statusBarIcon.preloadedIcon.mutate();
+ }
} else {
int userId = statusBarIcon.user.getIdentifier();
if (userId == UserHandle.USER_ALL) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index ecb6d7f..406a664 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -22,6 +22,7 @@
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.statusbar.data.StatusBarDataLayerModule
import com.android.systemui.statusbar.phone.LightBarController
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl
@@ -51,6 +52,11 @@
@ClassKey(LightBarController::class)
abstract fun bindLightBarController(impl: LightBarController): CoreStartable
+ @Binds
+ @IntoMap
+ @ClassKey(StatusBarSignalPolicy::class)
+ abstract fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable
+
companion object {
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 4be638f..2f3719a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -173,7 +173,8 @@
}
/**
- * @return Height of the notifications panel without top padding when expansion completes.
+ * @return Height of the available space for the notification content, when the shade
+ * expansion completes.
*/
public float getStackEndHeight() {
return mStackEndHeight;
@@ -276,17 +277,18 @@
}
/**
- * @see #getStackHeight()
+ * @return Height of the notification content returned by {@link #getStackEndHeight()}, but
+ * interpolated by the shade expansion fraction.
*/
- public void setStackHeight(float stackHeight) {
- mStackHeight = stackHeight;
+ public float getInterpolatedStackHeight() {
+ return mStackHeight;
}
/**
- * @return Height of notifications panel interpolated by the expansion fraction.
+ * @see #getInterpolatedStackHeight()
*/
- public float getStackHeight() {
- return mStackHeight;
+ public void setInterpolatedStackHeight(float stackHeight) {
+ mStackHeight = stackHeight;
}
@Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1f767aa..64d7124 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -874,7 +874,7 @@
y = (int) (mAmbientState.getStackY());
drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = " + y);
- y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
+ y = (int) (mAmbientState.getStackY() + mAmbientState.getInterpolatedStackHeight());
drawDebugInfo(canvas, y, Color.LTGRAY,
/* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = " + y);
@@ -1123,11 +1123,13 @@
@Override
public void addStackHeightChangedListener(@NonNull Runnable runnable) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
mStackHeightChangedListeners.addIfAbsent(runnable);
}
@Override
public void removeStackHeightChangedListener(@NonNull Runnable runnable) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
mStackHeightChangedListeners.remove(runnable);
}
@@ -1233,7 +1235,6 @@
if (mAmbientState.getStackTop() != stackTop) {
mAmbientState.setStackTop(stackTop);
onTopPaddingChanged(/* animate = */ isAddOrRemoveAnimationPending());
- setExpandedHeight(mExpandedHeight);
}
}
@@ -1476,7 +1477,7 @@
@VisibleForTesting
public void updateStackEndHeightAndStackHeight(float fraction) {
- final float oldStackHeight = mAmbientState.getStackHeight();
+ final float oldStackHeight = mAmbientState.getInterpolatedStackHeight();
if (SceneContainerFlag.isEnabled()) {
final float endHeight;
if (!shouldSkipHeightUpdate()) {
@@ -1484,20 +1485,20 @@
} else {
endHeight = mAmbientState.getStackEndHeight();
}
- updateStackHeight(endHeight, fraction);
+ updateInterpolatedStackHeight(endHeight, fraction);
} else {
if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
final float endHeight = updateStackEndHeight(
getHeight(), getEmptyBottomMarginInternal(), getTopPadding());
- updateStackHeight(endHeight, fraction);
+ updateInterpolatedStackHeight(endHeight, fraction);
} else {
// Always updateStackHeight to prevent jumps in the stack height when this fraction
// suddenly reapplies after a freeze.
final float endHeight = mAmbientState.getStackEndHeight();
- updateStackHeight(endHeight, fraction);
+ updateInterpolatedStackHeight(endHeight, fraction);
}
}
- if (oldStackHeight != mAmbientState.getStackHeight()) {
+ if (oldStackHeight != mAmbientState.getInterpolatedStackHeight()) {
requestChildrenUpdate();
}
}
@@ -1531,7 +1532,7 @@
}
@VisibleForTesting
- public void updateStackHeight(float endHeight, float fraction) {
+ public void updateInterpolatedStackHeight(float endHeight, float fraction) {
if (!newAodTransition()) {
// During the (AOD<=>LS) transition where dozeAmount is changing,
// apply dozeAmount to stack height instead of expansionFraction
@@ -1541,7 +1542,7 @@
fraction = 1f - dozeAmount;
}
}
- mAmbientState.setStackHeight(
+ mAmbientState.setInterpolatedStackHeight(
MathUtils.lerp(endHeight * StackScrollAlgorithm.START_FRACTION,
endHeight, fraction));
}
@@ -1570,8 +1571,11 @@
// Update the expand progress between started/stopped events
mAmbientState.setExpansionFraction(expandFraction);
- // TODO(b/332577544): don't convert to height which then converts to the fraction again
- setExpandedHeight(expandFraction * getHeight());
+
+ if (!shouldSkipHeightUpdate()) {
+ updateStackEndHeightAndStackHeight(expandFraction);
+ updateExpandedHeight(expandFraction);
+ }
// expansion stopped event requires that the expandFraction has already been updated
if (!nowExpanding && wasExpanding) {
@@ -1580,6 +1584,19 @@
}
}
+ private void updateExpandedHeight(float expandFraction) {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ float expandedHeight = expandFraction * getHeight();
+ setIsExpanded(expandedHeight > 0);
+
+ if (mExpandedHeight != expandedHeight) {
+ mExpandedHeight = expandedHeight;
+ updateAlgorithmHeightAndPadding();
+ requestChildrenUpdate();
+ notifyAppearChangedListeners();
+ }
+ }
+
@Override
public void setQsExpandFraction(float expandFraction) {
if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
@@ -1592,6 +1609,7 @@
* @param height the expanded height of the panel
*/
public void setExpandedHeight(float height) {
+ SceneContainerFlag.assertInLegacyMode();
final boolean skipHeightUpdate = shouldSkipHeightUpdate();
updateStackPosition();
@@ -1723,6 +1741,7 @@
* Measured relative to the resting position.
*/
private float getExpandTranslationStart() {
+ SceneContainerFlag.assertInLegacyMode();
return -getTopPadding() + getMinExpansionHeight() - mShelf.getIntrinsicHeight();
}
@@ -1731,6 +1750,7 @@
* Measured in absolute height.
*/
private float getAppearStartPosition() {
+ SceneContainerFlag.assertInLegacyMode();
if (isHeadsUpTransition()) {
final NotificationSection firstVisibleSection = getFirstVisibleSection();
final int pinnedHeight = firstVisibleSection != null
@@ -1786,6 +1806,7 @@
* have the shelf on its own)
*/
private float getAppearEndPosition() {
+ SceneContainerFlag.assertInLegacyMode();
if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
return getAppearEndPositionLegacy();
}
@@ -1846,7 +1867,7 @@
*/
@FloatRange(from = -1.0, to = 1.0)
public float calculateAppearFraction(float height) {
- if (isHeadsUpTransition()) {
+ if (isHeadsUpTransition() && !SceneContainerFlag.isEnabled()) {
// HUN is a special case because fraction can go negative if swiping up. And for now
// it must go negative as other pieces responsible for proper translation up assume
// negative value for HUN going up.
@@ -2522,10 +2543,33 @@
}
@VisibleForTesting
- void updateContentHeight() {
+ void updateStackHeight() {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+
+ final int shelfIntrinsicHeight = mShelf != null ? mShelf.getIntrinsicHeight() : 0;
+ final int footerIntrinsicHeight =
+ mFooterView != null ? mFooterView.getIntrinsicHeight() : 0;
+ final int notificationsHeight = (int) mNotificationStackSizeCalculator.computeHeight(
+ /* notificationStackScrollLayout= */ this,
+ mMaxDisplayedNotifications,
+ shelfIntrinsicHeight
+ );
+ mIntrinsicContentHeight = notificationsHeight;
+ final int fullStackHeight = notificationsHeight + footerIntrinsicHeight + mBottomPadding;
+ if (mScrollViewFields.getIntrinsicStackHeight() != fullStackHeight) {
+ mScrollViewFields.setIntrinsicStackHeight(fullStackHeight);
+ notifyStackHeightChangedListeners();
+ }
+ }
+
+ private void updateContentHeight() {
+ if (SceneContainerFlag.isEnabled()) {
+ updateStackHeight();
+ return;
+ }
+
final float scrimTopPadding = getScrimTopPaddingOrZero();
final int shelfIntrinsicHeight = mShelf != null ? mShelf.getIntrinsicHeight() : 0;
- final int footerIntrinsicHeight = mFooterView != null ? mFooterView.getIntrinsicHeight() : 0;
final float height =
(int) scrimTopPadding + (int) mNotificationStackSizeCalculator.computeHeight(
/* notificationStackScrollLayout= */ this, mMaxDisplayedNotifications,
@@ -2536,19 +2580,15 @@
// state the maxPanelHeight and the contentHeight should be bigger
mContentHeight =
(int) (height + Math.max(getIntrinsicPadding(), getTopPadding()) + mBottomPadding);
- mScrollViewFields.setIntrinsicStackHeight(
- (int) (getIntrinsicPadding() + mIntrinsicContentHeight + footerIntrinsicHeight
- + mBottomPadding));
updateScrollability();
clampScrollPosition();
updateStackPosition();
mAmbientState.setContentHeight(mContentHeight);
-
- notifyStackHeightChangedListeners();
}
@Override
public int getIntrinsicStackHeight() {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0;
return mScrollViewFields.getIntrinsicStackHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 08d3e9f..e112c99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1408,6 +1408,7 @@
}
public float calculateAppearFraction(float height) {
+ SceneContainerFlag.assertInLegacyMode();
return mView.calculateAppearFraction(height);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 0c2b5ae..ef1bcfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -575,7 +575,8 @@
final float shelfHeight = showingShelf ? ambientState.getShelf().getIntrinsicHeight() : 0f;
final float scrimPadding = getScrimTopPaddingOrZero(ambientState);
- final float stackHeight = ambientState.getStackHeight() - shelfHeight - scrimPadding;
+ final float stackHeight =
+ ambientState.getInterpolatedStackHeight() - shelfHeight - scrimPadding;
final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding;
if (stackEndHeight == 0f) {
// This should not happen, since even when the shade is empty we show EmptyShadeView
@@ -734,7 +735,7 @@
|| ambientState.getDozeAmount() == 1f
|| bypassPulseNotExpanding
? ambientState.getInnerHeight()
- : ambientState.getStackHeight();
+ : ambientState.getInterpolatedStackHeight();
final float shelfStart = stackBottom
- ambientState.getShelf().getIntrinsicHeight()
- mPaddingBetweenElements;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index e3242d1..7227b93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -31,6 +31,7 @@
import static com.android.systemui.Flags.lightRevealMigration;
import static com.android.systemui.Flags.newAodTransition;
import static com.android.systemui.Flags.relockWithPowerButtonImmediately;
+import static com.android.systemui.Flags.statusBarSignalPolicyRefactor;
import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
import static com.android.systemui.flags.Flags.SHORTCUT_LIST_SEARCH_LAYOUT;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -870,7 +871,10 @@
mBubblesOptional.ifPresent(this::initBubbles);
mKeyguardBypassController.listenForQsExpandedChange();
- mStatusBarSignalPolicy.init();
+ if (!statusBarSignalPolicyRefactor()) {
+ mStatusBarSignalPolicy.init();
+ }
+
mKeyguardIndicationController.init();
mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 05bd1a7..ba39c3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -44,7 +44,7 @@
import androidx.lifecycle.Observer;
-import com.android.settingslib.notification.modes.ZenMode;
+import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.Flags;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.DisplayId;
@@ -80,6 +80,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor;
+import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo;
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.DateFormatUtil;
@@ -363,7 +364,7 @@
// Note that we're not fully replacing ZenModeController with ZenModeInteractor, so
// we listen for the extra event here but still add the ZMC callback.
mJavaAdapter.alwaysCollectFlow(mZenModeInteractor.getMainActiveMode(),
- this::onActiveModeChanged);
+ this::onMainActiveModeChanged);
}
mZenController.addCallback(mZenControllerCallback);
if (!Flags.statusBarScreenSharingChips()) {
@@ -395,20 +396,23 @@
() -> mResources.getString(R.string.accessibility_managed_profile));
}
- private void onActiveModeChanged(@Nullable ZenMode mode) {
+ private void onMainActiveModeChanged(@Nullable ZenModeInfo mainActiveMode) {
if (!usesModeIcons()) {
- Log.wtf(TAG, "onActiveModeChanged shouldn't be called if MODES_UI_ICONS is disabled");
+ Log.wtf(TAG, "onMainActiveModeChanged shouldn't run if MODES_UI_ICONS is disabled");
return;
}
- boolean visible = mode != null;
- if (visible) {
- // TODO: b/360399800 - Get the resource id, package, and cached drawable from the mode;
- // this is a shortcut for testing.
- String resPackage = mode.getIconKey().resPackage();
- int iconResId = mode.getIconKey().resId();
- mIconController.setResourceIcon(mSlotZen, resPackage, iconResId,
- /* preloadedIcon= */ null, mode.getName());
+ boolean visible = mainActiveMode != null;
+ if (visible) {
+ // Shape=FIXED_SPACE because mode icons can be from 3P packages and may not be square;
+ // we don't want to allow apps to set incredibly wide icons and take up too much space
+ // in the status bar.
+ mIconController.setResourceIcon(mSlotZen,
+ mainActiveMode.getIcon().key().resPackage(),
+ mainActiveMode.getIcon().key().resId(),
+ mainActiveMode.getIcon().drawable(),
+ mainActiveMode.getName(),
+ StatusBarIcon.Shape.FIXED_SPACE);
}
if (visible != mZenVisible) {
mIconController.setIconVisibility(mSlotZen, visible);
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 09b6b68..43f9af6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -68,13 +68,11 @@
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardWmStateRefactor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
import com.android.systemui.keyguard.shared.model.DismissAction;
import com.android.systemui.keyguard.shared.model.Edge;
import com.android.systemui.keyguard.shared.model.KeyguardDone;
@@ -363,8 +361,6 @@
}
}
};
- private Lazy<WindowManagerLockscreenVisibilityInteractor> mWmLockscreenVisibilityInteractor;
- private Lazy<KeyguardSurfaceBehindInteractor> mSurfaceBehindInteractor;
private Lazy<KeyguardDismissActionInteractor> mKeyguardDismissActionInteractor;
private final JavaAdapter mJavaAdapter;
private StatusBarKeyguardViewManagerInteractor mStatusBarKeyguardViewManagerInteractor;
@@ -394,11 +390,10 @@
UdfpsOverlayInteractor udfpsOverlayInteractor,
ActivityStarter activityStarter,
KeyguardTransitionInteractor keyguardTransitionInteractor,
+ KeyguardDismissTransitionInteractor keyguardDismissTransitionInteractor,
@Main CoroutineDispatcher mainDispatcher,
- Lazy<WindowManagerLockscreenVisibilityInteractor> wmLockscreenVisibilityInteractor,
Lazy<KeyguardDismissActionInteractor> keyguardDismissActionInteractorLazy,
SelectedUserInteractor selectedUserInteractor,
- Lazy<KeyguardSurfaceBehindInteractor> surfaceBehindInteractor,
JavaAdapter javaAdapter,
Lazy<SceneInteractor> sceneInteractorLazy,
StatusBarKeyguardViewManagerInteractor statusBarKeyguardViewManagerInteractor,
@@ -432,11 +427,10 @@
mUdfpsOverlayInteractor = udfpsOverlayInteractor;
mActivityStarter = activityStarter;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mKeyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor;
mMainDispatcher = mainDispatcher;
- mWmLockscreenVisibilityInteractor = wmLockscreenVisibilityInteractor;
mKeyguardDismissActionInteractor = keyguardDismissActionInteractorLazy;
mSelectedUserInteractor = selectedUserInteractor;
- mSurfaceBehindInteractor = surfaceBehindInteractor;
mJavaAdapter = javaAdapter;
mSceneInteractorLazy = sceneInteractorLazy;
mStatusBarKeyguardViewManagerInteractor = statusBarKeyguardViewManagerInteractor;
@@ -445,6 +439,7 @@
}
KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ KeyguardDismissTransitionInteractor mKeyguardDismissTransitionInteractor;
CoroutineDispatcher mMainDispatcher;
@Override
@@ -1616,7 +1611,7 @@
}
if (KeyguardWmStateRefactor.isEnabled()) {
- mKeyguardTransitionInteractor.startDismissKeyguardTransition(
+ mKeyguardDismissTransitionInteractor.startDismissKeyguardTransition(
"SBKVM#keyguardAuthenticated");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index ba59398..d5fafe2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.Flags.statusBarSignalPolicyRefactor;
+
import android.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
@@ -23,16 +25,19 @@
import android.util.Log;
import com.android.settingslib.mobile.TelephonyIcons;
+import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.CarrierConfigTracker;
+import com.android.systemui.util.kotlin.JavaAdapter;
import java.util.ArrayList;
import java.util.List;
@@ -40,10 +45,13 @@
import javax.inject.Inject;
-/** Controls the signal policies for icons shown in the statusbar. **/
+/** Controls the signal policies for icons shown in the statusbar. */
@SysUISingleton
-public class StatusBarSignalPolicy implements SignalCallback,
- SecurityController.SecurityControllerCallback, Tunable {
+public class StatusBarSignalPolicy
+ implements SignalCallback,
+ SecurityController.SecurityControllerCallback,
+ Tunable,
+ CoreStartable {
private static final String TAG = "StatusBarSignalPolicy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -61,16 +69,15 @@
private final Handler mHandler = Handler.getMain();
private final CarrierConfigTracker mCarrierConfigTracker;
private final TunerService mTunerService;
+ private final JavaAdapter mJavaAdapter;
+ private final AirplaneModeInteractor mAirplaneModeInteractor;
private boolean mHideAirplane;
private boolean mHideMobile;
private boolean mHideEthernet;
- private boolean mActivityEnabled;
+ private final boolean mActivityEnabled;
- // Track as little state as possible, and only for padding purposes
- private boolean mIsAirplaneMode = false;
-
- private ArrayList<CallIndicatorIconState> mCallIndicatorStates = new ArrayList<>();
+ private final ArrayList<CallIndicatorIconState> mCallIndicatorStates = new ArrayList<>();
private boolean mInitialized;
@Inject
@@ -80,15 +87,19 @@
CarrierConfigTracker carrierConfigTracker,
NetworkController networkController,
SecurityController securityController,
- TunerService tunerService
+ TunerService tunerService,
+ JavaAdapter javaAdapter,
+ AirplaneModeInteractor airplaneModeInteractor
) {
mContext = context;
mIconController = iconController;
mCarrierConfigTracker = carrierConfigTracker;
+ mJavaAdapter = javaAdapter;
mNetworkController = networkController;
mSecurityController = securityController;
mTunerService = tunerService;
+ mAirplaneModeInteractor = airplaneModeInteractor;
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
@@ -100,15 +111,35 @@
mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
}
+ @Override
+ public void start() {
+ if (!statusBarSignalPolicyRefactor()) {
+ return;
+ }
+
+ mTunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
+ mNetworkController.addCallback(this);
+ mSecurityController.addCallback(this);
+
+ mJavaAdapter.alwaysCollectFlow(
+ mAirplaneModeInteractor.isAirplaneMode(), this::updateAirplaneModeIcon);
+ }
+
/** Call to initialize and register this class with the system. */
public void init() {
- if (mInitialized) {
+ if (mInitialized || statusBarSignalPolicyRefactor()) {
return;
}
mInitialized = true;
mTunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mNetworkController.addCallback(this);
mSecurityController.addCallback(this);
+
+ if (statusBarSignalPolicyRefactor()) {
+ mJavaAdapter.alwaysCollectFlow(
+ mAirplaneModeInteractor.isAirplaneMode(),
+ this::updateAirplaneModeIcon);
+ }
}
public void destroy() {
@@ -222,15 +253,19 @@
@Override
public void setIsAirplaneMode(IconState icon) {
+ if (statusBarSignalPolicyRefactor()) {
+ return;
+ }
+
if (DEBUG) {
Log.d(TAG, "setIsAirplaneMode: "
+ "icon = " + (icon == null ? "" : icon.toString()));
}
- mIsAirplaneMode = icon.visible && !mHideAirplane;
+ boolean isAirplaneMode = icon.visible && !mHideAirplane;
int resId = icon.icon;
String description = icon.contentDescription;
- if (mIsAirplaneMode && resId > 0) {
+ if (isAirplaneMode && resId > 0) {
mIconController.setIcon(mSlotAirplane, resId, description);
mIconController.setIconVisibility(mSlotAirplane, true);
} else {
@@ -238,6 +273,21 @@
}
}
+ public void updateAirplaneModeIcon(boolean isAirplaneModeOn) {
+ if (StatusBarSignalPolicyRefactor.isUnexpectedlyInLegacyMode()) {
+ return;
+ }
+
+ boolean isAirplaneMode = isAirplaneModeOn && !mHideAirplane;
+ mIconController.setIconVisibility(mSlotAirplane, isAirplaneMode);
+ if (isAirplaneMode) {
+ mIconController.setIcon(
+ mSlotAirplane,
+ TelephonyIcons.FLIGHT_MODE_ICON,
+ mContext.getString(R.string.accessibility_airplane_mode));
+ }
+ }
+
/**
* Stores the statusbar state for no Calling & SMS.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicyRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicyRefactor.kt
new file mode 100644
index 0000000..0577f49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicyRefactor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.statusbar.phone
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the status_bar_signal_policy_refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object StatusBarSignalPolicyRefactor {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.statusBarSignalPolicyRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/DarkIconManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/DarkIconManager.java
index 8871dae..6c30330 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/DarkIconManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/DarkIconManager.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone.ui;
-import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
@@ -64,9 +63,8 @@
}
@Override
- protected LinearLayout.LayoutParams onCreateLayoutParams() {
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+ protected LinearLayout.LayoutParams onCreateLayoutParams(StatusBarIcon.Shape shape) {
+ LinearLayout.LayoutParams lp = super.onCreateLayoutParams(shape);
lp.setMargins(mIconHorizontalMargin, 0, mIconHorizontalMargin, 0);
return lp;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
index 5ad7376..91ead61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
@@ -20,6 +20,7 @@
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE_NEW;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI_NEW;
+import static com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl.usesModeIcons;
import android.annotation.Nullable;
import android.content.Context;
@@ -27,9 +28,8 @@
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import androidx.annotation.VisibleForTesting;
-
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.statusbar.StatusBarIcon.Shape;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.statusbar.BaseStatusBarFrameLayout;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -155,12 +155,11 @@
};
}
- @VisibleForTesting
protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
StatusBarIcon icon) {
StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
view.set(icon);
- mGroup.addView(view, index, onCreateLayoutParams());
+ mGroup.addView(view, index, onCreateLayoutParams(icon.shape));
return view;
}
@@ -174,7 +173,7 @@
int index) {
mBindableIcons.put(holder.getSlot(), holder);
ModernStatusBarView view = holder.getInitializer().createAndBind(mContext);
- mGroup.addView(view, index, onCreateLayoutParams());
+ mGroup.addView(view, index, onCreateLayoutParams(Shape.WRAP_CONTENT));
if (mIsInDemoMode) {
mDemoStatusIcons.addBindableIcon(holder);
}
@@ -183,7 +182,7 @@
protected StatusIconDisplayable addNewWifiIcon(int index, String slot) {
ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot);
- mGroup.addView(view, index, onCreateLayoutParams());
+ mGroup.addView(view, index, onCreateLayoutParams(Shape.WRAP_CONTENT));
if (mIsInDemoMode) {
mDemoStatusIcons.addModernWifiView(mWifiViewModel);
@@ -199,7 +198,7 @@
int subId
) {
BaseStatusBarFrameLayout view = onCreateModernStatusBarMobileView(slot, subId);
- mGroup.addView(view, index, onCreateLayoutParams());
+ mGroup.addView(view, index, onCreateLayoutParams(Shape.WRAP_CONTENT));
if (mIsInDemoMode) {
Context mobileContext = mMobileContextProvider
@@ -233,8 +232,12 @@
);
}
- protected LinearLayout.LayoutParams onCreateLayoutParams() {
- return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
+ protected LinearLayout.LayoutParams onCreateLayoutParams(Shape shape) {
+ int width = usesModeIcons() && shape == StatusBarIcon.Shape.FIXED_SPACE
+ ? mIconSize
+ : ViewGroup.LayoutParams.WRAP_CONTENT;
+
+ return new LinearLayout.LayoutParams(width, mIconSize);
}
protected void destroy() {
@@ -256,6 +259,13 @@
/** Called once an icon has been set. */
public void onSetIcon(int viewIndex, StatusBarIcon icon) {
StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
+ if (usesModeIcons()) {
+ ViewGroup.LayoutParams current = view.getLayoutParams();
+ ViewGroup.LayoutParams desired = onCreateLayoutParams(icon.shape);
+ if (desired.width != current.width || desired.height != current.height) {
+ view.setLayoutParams(desired);
+ }
+ }
view.set(icon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
index ee528e9..0459b97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
@@ -70,7 +70,8 @@
* @param preloadedIcon optional drawable corresponding to {@code iconResId}, if known
*/
void setResourceIcon(String slot, @Nullable String resPackage, @DrawableRes int iconResId,
- @Nullable Drawable preloadedIcon, CharSequence contentDescription);
+ @Nullable Drawable preloadedIcon, CharSequence contentDescription,
+ StatusBarIcon.Shape shape);
/**
* Sets up a wifi icon using the new data pipeline. No effect if the wifi icon has already been
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
index ad3a9e3..9b6d32b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
@@ -234,13 +234,14 @@
Icon.createWithResource(mContext, resourceId),
/* preloadedIcon= */ null,
contentDescription,
- StatusBarIcon.Type.SystemIcon);
+ StatusBarIcon.Type.SystemIcon,
+ StatusBarIcon.Shape.WRAP_CONTENT);
}
@Override
public void setResourceIcon(String slot, @Nullable String resPackage,
@DrawableRes int iconResId, @Nullable Drawable preloadedIcon,
- CharSequence contentDescription) {
+ CharSequence contentDescription, StatusBarIcon.Shape shape) {
if (!usesModeIcons()) {
Log.wtf("TAG",
"StatusBarIconController.setResourceIcon() should not be called without "
@@ -260,12 +261,13 @@
icon,
preloadedIcon,
contentDescription,
- StatusBarIcon.Type.ResourceIcon);
+ StatusBarIcon.Type.ResourceIcon,
+ shape);
}
private void setResourceIconInternal(String slot, Icon resourceIcon,
@Nullable Drawable preloadedIcon, CharSequence contentDescription,
- StatusBarIcon.Type type) {
+ StatusBarIcon.Type type, StatusBarIcon.Shape shape) {
checkArgument(resourceIcon.getType() == Icon.TYPE_RESOURCE,
"Expected Icon of TYPE_RESOURCE, but got " + resourceIcon.getType());
String resPackage = resourceIcon.getResPackage();
@@ -277,7 +279,7 @@
if (holder == null) {
StatusBarIcon icon = new StatusBarIcon(UserHandle.SYSTEM, resPackage,
resourceIcon, /* iconLevel= */ 0, /* number=*/ 0,
- contentDescription, type);
+ contentDescription, type, shape);
icon.preloadedIcon = preloadedIcon;
holder = StatusBarIconHolder.fromIcon(icon);
setIcon(slot, holder);
@@ -286,6 +288,7 @@
holder.getIcon().icon = resourceIcon;
holder.getIcon().contentDescription = contentDescription;
holder.getIcon().type = type;
+ holder.getIcon().shape = shape;
holder.getIcon().preloadedIcon = preloadedIcon;
handleSet(slot, holder);
}
@@ -578,7 +581,7 @@
}
}
- private static boolean usesModeIcons() {
+ static boolean usesModeIcons() {
return android.app.Flags.modesApi() && android.app.Flags.modesUi()
&& android.app.Flags.modesUiIcons();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt
deleted file mode 100644
index cce3eb0..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2024 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.statusbar.pipeline.mobile.data.model
-
-import android.telephony.ServiceState
-
-/**
- * Simplified representation of a [ServiceState] for use in SystemUI. Add any fields that we need to
- * extract from service state here for consumption downstream
- */
-data class ServiceStateModel(val isEmergencyOnly: Boolean) {
- companion object {
- fun fromServiceState(serviceState: ServiceState): ServiceStateModel {
- return ServiceStateModel(isEmergencyOnly = serviceState.isEmergencyOnly)
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 5ad8bf1..32e9c85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -21,7 +21,6 @@
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
-import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -93,17 +92,15 @@
val defaultMobileIconGroup: Flow<MobileIconGroup>
/**
- * [deviceServiceState] is equivalent to the last [Intent.ACTION_SERVICE_STATE] broadcast with a
- * subscriptionId of -1 (aka [SubscriptionManager.INVALID_SUBSCRIPTION_ID]).
+ * Can the device make emergency calls using the device-based service state? This field is only
+ * useful when all known active subscriptions are OOS and not emergency call capable.
*
- * While each [MobileConnectionsRepository] listens for the service state of each subscription,
- * there is potentially a service state associated with the device itself. This value can be
- * used to calculate e.g., the emergency calling capability of the device (as opposed to the
- * emergency calling capability of an individual mobile connection)
+ * Specifically, this checks every [ServiceState] of the device, and looks for any that report
+ * [ServiceState.isEmergencyOnly].
*
- * Note: this is a [StateFlow] using an eager sharing strategy.
+ * This is an eager flow, and re-evaluates whenever ACTION_SERVICE_STATE is sent for subId = -1.
*/
- val deviceServiceState: StateFlow<ServiceStateModel?>
+ val isDeviceEmergencyCallCapable: StateFlow<Boolean>
/**
* If any active SIM on the device is in
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index b068152..b247da4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -25,7 +25,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
-import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
@@ -152,16 +151,17 @@
override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
activeRepo.flatMapLatest { it.defaultMobileIconGroup }
- override val deviceServiceState: StateFlow<ServiceStateModel?> =
+ override val isDeviceEmergencyCallCapable: StateFlow<Boolean> =
activeRepo
- .flatMapLatest { it.deviceServiceState }
+ .flatMapLatest { it.isDeviceEmergencyCallCapable }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
- realRepository.deviceServiceState.value
+ realRepository.isDeviceEmergencyCallCapable.value
)
override val isAnySimSecure: Flow<Boolean> = activeRepo.flatMapLatest { it.isAnySimSecure }
+
override fun getIsAnySimSecure(): Boolean = activeRepo.value.getIsAnySimSecure()
override val defaultDataSubId: StateFlow<Int> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index a944e91..3a79f3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -27,7 +27,6 @@
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
-import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
@@ -137,10 +136,11 @@
override val defaultMobileIconGroup = flowOf(TelephonyIcons.THREE_G)
- // TODO(b/339023069): demo command for device-based connectivity state
- override val deviceServiceState: StateFlow<ServiceStateModel?> = MutableStateFlow(null)
+ // TODO(b/339023069): demo command for device-based emergency calls state
+ override val isDeviceEmergencyCallCapable: StateFlow<Boolean> = MutableStateFlow(false)
override val isAnySimSecure: Flow<Boolean> = flowOf(getIsAnySimSecure())
+
override fun getIsAnySimSecure(): Boolean = false
override val defaultMobileIconMapping = MutableStateFlow(TelephonyIcons.ICON_NAME_TO_ICON)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 261258a..b756a05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -21,7 +21,6 @@
import android.content.Intent
import android.content.IntentFilter
import android.telephony.CarrierConfigManager
-import android.telephony.ServiceState
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
@@ -49,7 +48,6 @@
import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
-import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
@@ -72,7 +70,6 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
@@ -175,8 +172,8 @@
}
.flowOn(bgDispatcher)
- /** Note that this flow is eager, so we don't miss any state */
- override val deviceServiceState: StateFlow<ServiceStateModel?> =
+ /** Turn ACTION_SERVICE_STATE (for subId = -1) into an event */
+ private val serviceStateChangedEvent: Flow<Unit> =
broadcastDispatcher
.broadcastFlow(IntentFilter(Intent.ACTION_SERVICE_STATE)) { intent, _ ->
val subId =
@@ -185,24 +182,34 @@
INVALID_SUBSCRIPTION_ID
)
- val extras = intent.extras
- if (extras == null) {
- logger.logTopLevelServiceStateBroadcastMissingExtras(subId)
- return@broadcastFlow null
- }
-
- val serviceState = ServiceState.newFromBundle(extras)
- logger.logTopLevelServiceStateBroadcastEmergencyOnly(subId, serviceState)
+ // Only emit if the subId is not associated with an active subscription
if (subId == INVALID_SUBSCRIPTION_ID) {
- // Assume that -1 here is the device's service state. We don't care about
- // other ones.
- ServiceStateModel.fromServiceState(serviceState)
- } else {
- null
+ Unit
}
}
- .filterNotNull()
- .stateIn(scope, SharingStarted.Eagerly, null)
+ // Emit on start so that we always check the state at least once
+ .onStart { emit(Unit) }
+
+ /** Eager flow to determine the device-based emergency calls only state */
+ override val isDeviceEmergencyCallCapable: StateFlow<Boolean> =
+ serviceStateChangedEvent
+ .mapLatest {
+ val modems = telephonyManager.activeModemCount
+ // Check the service state for every modem. If any state reports emergency calling
+ // capable, then consider the device to have emergency call capabilities
+ (0..<modems)
+ .map { telephonyManager.getServiceStateForSlot(it) }
+ .any { it?.isEmergencyOnly == true }
+ }
+ .flowOn(bgDispatcher)
+ .distinctUntilChanged()
+ .logDiffsForTable(
+ tableLogger,
+ columnPrefix = LOGGING_PREFIX,
+ columnName = "deviceEmergencyOnly",
+ initialValue = false,
+ )
+ .stateIn(scope, SharingStarted.Eagerly, false)
/**
* State flow that emits the set of mobile data subscriptions, each represented by its own
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 26553e6..28fff4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -385,15 +385,7 @@
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean> =
- mobileConnectionsRepo.deviceServiceState
- .map { it?.isEmergencyOnly ?: false }
- .distinctUntilChanged()
- .logDiffsForTable(
- tableLogger,
- columnPrefix = LOGGING_PREFIX,
- columnName = "deviceEmergencyOnly",
- initialValue = false,
- )
+ mobileConnectionsRepo.isDeviceEmergencyCallCapable
/** Vends out new [MobileIconInteractor] for a particular subId */
override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
index 1a55f7d..f5cfc8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepository.kt
@@ -31,7 +31,7 @@
import androidx.annotation.ArrayRes
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
@@ -47,6 +47,7 @@
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Wifi
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo
import com.android.systemui.tuner.TunerService
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -252,7 +253,10 @@
}
// Only CELLULAR networks may have underlying wifi information that's relevant to SysUI,
// so skip the underlying network check if it's not CELLULAR.
- if (!this.hasTransport(TRANSPORT_CELLULAR)) {
+ if (
+ !this.hasTransport(TRANSPORT_CELLULAR) &&
+ !Flags.statusBarAlwaysCheckUnderlyingNetworks()
+ ) {
return mainWifiInfo
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index 71bcdfcb..6cebcbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -22,8 +22,10 @@
import com.android.internal.R;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
+import com.android.settingslib.notification.modes.ZenIconLoader;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogBufferFactory;
import com.android.systemui.settings.UserTracker;
@@ -79,6 +81,7 @@
import dagger.Provides;
import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
import javax.inject.Named;
@@ -236,4 +239,12 @@
static LogBuffer provideCastControllerLog(LogBufferFactory factory) {
return factory.create("CastControllerLog", 50);
}
+
+ /** Provides a {@link ZenIconLoader} that fetches icons in a background thread. */
+ @Provides
+ @SysUISingleton
+ static ZenIconLoader provideZenIconLoader(
+ @UiBackground ExecutorService backgroundExecutorService) {
+ return new ZenIconLoader(backgroundExecutorService);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
index a67b47a..93c631f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
@@ -23,16 +23,20 @@
import android.util.Log
import androidx.concurrent.futures.await
import com.android.settingslib.notification.data.repository.ZenModeRepository
+import com.android.settingslib.notification.modes.ZenIcon
import com.android.settingslib.notification.modes.ZenIconLoader
import com.android.settingslib.notification.modes.ZenMode
-import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.common.shared.model.asIcon
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
+import com.android.systemui.statusbar.policy.domain.model.ActiveZenModes
+import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo
import java.time.Duration
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
/**
@@ -45,9 +49,9 @@
private val context: Context,
private val zenModeRepository: ZenModeRepository,
private val notificationSettingsRepository: NotificationSettingsRepository,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ private val iconLoader: ZenIconLoader,
) {
- private val iconLoader: ZenIconLoader = ZenIconLoader.getInstance()
-
val isZenModeEnabled: Flow<Boolean> =
zenModeRepository.globalZenMode
.map {
@@ -76,34 +80,27 @@
val modes: Flow<List<ZenMode>> = zenModeRepository.modes
- val activeModes: Flow<List<ZenMode>> =
- modes.map { modes -> modes.filter { mode -> mode.isActive } }.distinctUntilChanged()
+ /** Flow returning the currently active mode(s), if any. */
+ val activeModes: Flow<ActiveZenModes> =
+ modes
+ .map { modes ->
+ val activeModesList =
+ modes
+ .filter { mode -> mode.isActive }
+ .sortedWith(ZenMode.PRIORITIZING_COMPARATOR)
+ val mainActiveMode =
+ activeModesList.firstOrNull()?.let { ZenModeInfo(it.name, getModeIcon(it)) }
- /** Flow returning the most prioritized of the active modes, if any. */
- val mainActiveMode: Flow<ZenMode?> =
- activeModes.map { modes -> getMainActiveMode(modes) }.distinctUntilChanged()
+ ActiveZenModes(activeModesList.map { m -> m.name }, mainActiveMode)
+ }
+ .flowOn(bgDispatcher)
+ .distinctUntilChanged()
- /**
- * Given the list of modes (which may include zero or more currently active modes), returns the
- * most prioritized of the active modes, if any.
- */
- private fun getMainActiveMode(modes: List<ZenMode>): ZenMode? {
- return modes.sortedWith(ZenMode.PRIORITIZING_COMPARATOR).firstOrNull { it.isActive }
- }
+ val mainActiveMode: Flow<ZenModeInfo?> =
+ activeModes.map { a -> a.mainMode }.distinctUntilChanged()
- suspend fun getModeIcon(mode: ZenMode): Icon {
- return iconLoader.getIcon(context, mode).await().drawable().asIcon()
- }
-
- /**
- * Given the list of modes (which may include zero or more currently active modes), returns an
- * icon representing the active mode, if any (or, if multiple modes are active, to the most
- * prioritized one). This icon is suitable for use in the status bar or lockscreen (uses the
- * standard DND icon for implicit modes, instead of the launcher icon of the associated
- * package).
- */
- suspend fun getActiveModeIcon(modes: List<ZenMode>): Icon? {
- return getMainActiveMode(modes)?.let { m -> getModeIcon(m) }
+ suspend fun getModeIcon(mode: ZenMode): ZenIcon {
+ return iconLoader.getIcon(context, mode).await()
}
fun activateMode(zenMode: ZenMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/model/ActiveZenModes.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/model/ActiveZenModes.kt
new file mode 100644
index 0000000..569e517
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/model/ActiveZenModes.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.statusbar.policy.domain.model
+
+import com.android.settingslib.notification.modes.ZenMode
+
+/**
+ * Represents the list of [ZenMode] instances that are currently active.
+ *
+ * @property modeNames Names of all the active modes, sorted by their priority.
+ * @property mainMode The most prioritized active mode, if any modes active. Guaranteed to be
+ * non-null if [modeNames] is not empty.
+ */
+data class ActiveZenModes(val modeNames: List<String>, val mainMode: ZenModeInfo?) {
+ fun isAnyActive(): Boolean = modeNames.isNotEmpty()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/model/ZenModeInfo.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/model/ZenModeInfo.kt
new file mode 100644
index 0000000..5004f4c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/model/ZenModeInfo.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.statusbar.policy.domain.model
+
+import com.android.settingslib.notification.modes.ZenIcon
+import com.android.settingslib.notification.modes.ZenMode
+
+/** Name and icon of a [ZenMode] */
+data class ZenModeInfo(val name: String, val icon: ZenIcon)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
index 3fffd9f..cacb384 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
@@ -33,6 +33,10 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.stateDescription
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.android.systemui.common.ui.compose.Icon
@@ -56,9 +60,11 @@
modifier =
Modifier.combinedClickable(
onClick = viewModel.onClick,
- onLongClick = viewModel.onLongClick
+ onLongClick = viewModel.onLongClick,
+ onLongClickLabel = viewModel.onLongClickLabel
)
- .padding(20.dp),
+ .padding(20.dp)
+ .semantics { stateDescription = viewModel.stateDescription },
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement =
Arrangement.spacedBy(
@@ -76,7 +82,10 @@
Text(
viewModel.subtext,
fontWeight = FontWeight.W400,
- modifier = Modifier.tileMarquee().testTag("state")
+ modifier =
+ Modifier.tileMarquee().testTag("state").clearAndSetSemantics {
+ contentDescription = viewModel.subtextDescription
+ }
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
index 7c1cb6a..abd2453 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModeTileViewModel.kt
@@ -28,7 +28,10 @@
val icon: Icon,
val text: String,
val subtext: String,
+ val subtextDescription: String, // version of subtext without "on"/"off" for screen readers
val enabled: Boolean,
+ val stateDescription: String, // "on"/"off" state of the tile, for screen readers
val onClick: () -> Unit,
val onLongClick: () -> Unit,
+ val onLongClickLabel: String, // for screen readers
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
index be90bec..6764839c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt
@@ -23,6 +23,7 @@
import android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID
import com.android.settingslib.notification.modes.EnableZenModeDialog
import com.android.settingslib.notification.modes.ZenMode
+import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.qs.tiles.dialog.QSZenModeDialogMetricsLogger
@@ -88,10 +89,15 @@
modesList.map { mode ->
ModeTileViewModel(
id = mode.id,
- icon = zenModeInteractor.getModeIcon(mode),
+ icon = zenModeInteractor.getModeIcon(mode).drawable().asIcon(),
text = mode.name,
subtext = getTileSubtext(mode),
+ subtextDescription = getModeDescription(mode) ?: "",
enabled = mode.isActive,
+ stateDescription =
+ context.getString(
+ if (mode.isActive) R.string.zen_mode_on else R.string.zen_mode_off
+ ),
onClick = {
if (!mode.rule.isEnabled) {
openSettings(mode)
@@ -112,7 +118,9 @@
}
}
},
- onLongClick = { openSettings(mode) }
+ onLongClick = { openSettings(mode) },
+ onLongClickLabel =
+ context.resources.getString(R.string.accessibility_long_click_tile)
)
}
}
@@ -127,23 +135,36 @@
dialogDelegate.launchFromDialog(intent)
}
- private fun getTileSubtext(mode: ZenMode): String {
+ /**
+ * Returns a description of the mode, which is:
+ * * a prompt to set up the mode if it is not enabled
+ * * if it cannot be manually activated, text that says so
+ * * otherwise, the trigger description of the mode if it exists...
+ * * ...or null if it doesn't
+ *
+ * This description is used directly for the content description of a mode tile for screen
+ * readers, and for the tile subtext will be augmented with the current status of the mode.
+ */
+ private fun getModeDescription(mode: ZenMode): String? {
if (!mode.rule.isEnabled) {
return context.resources.getString(R.string.zen_mode_set_up)
}
if (!mode.rule.isManualInvocationAllowed && !mode.isActive) {
return context.resources.getString(R.string.zen_mode_no_manual_invocation)
}
+ return mode.getDynamicDescription(context)
+ }
- val modeSubtext = mode.getDynamicDescription(context)
+ private fun getTileSubtext(mode: ZenMode): String {
+ val modeDescription = getModeDescription(mode)
return if (mode.isActive) {
- if (modeSubtext != null) {
- context.getString(R.string.zen_mode_on_with_details, modeSubtext)
+ if (modeDescription != null) {
+ context.getString(R.string.zen_mode_on_with_details, modeDescription)
} else {
context.getString(R.string.zen_mode_on)
}
} else {
- modeSubtext ?: context.getString(R.string.zen_mode_off)
+ modeDescription ?: context.getString(R.string.zen_mode_off)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
index ecf1165..70774f13 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
@@ -28,6 +28,7 @@
import dagger.Provides;
import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Singleton;
@@ -81,6 +82,18 @@
@Singleton
@UiBackground
public static Executor provideUiBackgroundExecutor() {
+ return provideUiBackgroundExecutorService();
+ }
+
+ /**
+ * Provide an ExecutorService specifically for running UI operations on a separate thread.
+ *
+ * <p>Keep submitted runnables short and to the point, just as with any other UI code.
+ */
+ @Provides
+ @Singleton
+ @UiBackground
+ public static ExecutorService provideUiBackgroundExecutorService() {
return Executors.newSingleThreadExecutor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
index 4f77cd0..73728e6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
@@ -75,7 +75,7 @@
}
.map { it ?: AudioOutputDevice.Unknown }
.flowOn(backgroundCoroutineContext)
- .stateIn(scope, SharingStarted.Eagerly, AudioOutputDevice.Unknown)
+ .stateIn(scope, SharingStarted.Eagerly, AudioOutputDevice.Unavailable)
private fun AudioDeviceInfo.toAudioOutputDevice(): AudioOutputDevice {
if (
@@ -120,6 +120,11 @@
name = name,
icon = icon,
)
+ deviceType == MediaDeviceType.TYPE_CAST_DEVICE ->
+ AudioOutputDevice.Remote(
+ name = name,
+ icon = icon,
+ )
else ->
AudioOutputDevice.BuiltIn(
name = name,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/model/AudioOutputDevice.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/model/AudioOutputDevice.kt
index ba0b082..0e4cac0b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/domain/model/AudioOutputDevice.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/domain/model/AudioOutputDevice.kt
@@ -31,6 +31,12 @@
override val icon: Drawable?,
) : AudioOutputDevice
+ /** Models a cast audio output device. */
+ data class Remote(
+ override val name: String,
+ override val icon: Drawable?,
+ ) : AudioOutputDevice
+
/** Models a wired audio output device. */
data class Wired(
override val name: String,
@@ -52,4 +58,16 @@
override val icon: Drawable
get() = error("Unsupported for unknown device")
}
+
+ /**
+ * Models a state when current audio output device is not loaded yet or the system failed to
+ * load it.
+ */
+ data object Unavailable : AudioOutputDevice {
+ override val name: String
+ get() = error("Unsupported for unavailable device")
+
+ override val icon: Drawable
+ get() = error("Unsupported for unavailable device")
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
index a270d5f..f94cbda 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputComponentInteractor.kt
@@ -74,34 +74,51 @@
)
private val currentAudioDevice: Flow<AudioOutputDevice> =
- audioOutputInteractor.currentAudioDevice.filter { it !is AudioOutputDevice.Unknown }
+ audioOutputInteractor.currentAudioDevice.filter { it !is AudioOutputDevice.Unavailable }
+ /**
+ * Model for the Media Output component in the Volume Panel. It's guaranteed to have an
+ * available device if it's loaded.
+ */
val mediaOutputModel: StateFlow<Result<MediaOutputComponentModel>> =
- audioModeInteractor.isOngoingCall
- .flatMapLatest { isOngoingCall ->
- audioSharingInteractor.isInAudioSharing.flatMapLatest { isInAudioSharing ->
- if (isOngoingCall) {
- currentAudioDevice.map {
- MediaOutputComponentModel.Calling(it, isInAudioSharing)
- }
- } else {
- combine(sessionWithPlaybackState.filterData(), currentAudioDevice) {
- sessionWithPlaybackState,
- currentAudioDevice ->
- if (sessionWithPlaybackState == null) {
- MediaOutputComponentModel.Idle(currentAudioDevice, isInAudioSharing)
- } else {
- MediaOutputComponentModel.MediaSession(
- sessionWithPlaybackState.session,
- sessionWithPlaybackState.isPlaybackActive,
- currentAudioDevice,
- isInAudioSharing,
- )
- }
+ combine(
+ audioSharingInteractor.isInAudioSharing,
+ audioModeInteractor.isOngoingCall,
+ currentAudioDevice,
+ ) { isInAudioSharing, isOngoingCall, currentAudioDevice ->
+ if (isOngoingCall) {
+ flowOf(
+ MediaOutputComponentModel.Calling(
+ device = currentAudioDevice,
+ isInAudioSharing = isInAudioSharing,
+ canOpenAudioSwitcher = false,
+ )
+ )
+ } else {
+ sessionWithPlaybackState.filterData().map { sessionWithPlaybackState ->
+ if (sessionWithPlaybackState == null) {
+ MediaOutputComponentModel.Idle(
+ device = currentAudioDevice,
+ isInAudioSharing = isInAudioSharing,
+ canOpenAudioSwitcher =
+ !isInAudioSharing &&
+ currentAudioDevice !is AudioOutputDevice.Unknown,
+ )
+ } else {
+ MediaOutputComponentModel.MediaSession(
+ session = sessionWithPlaybackState.session,
+ isPlaybackActive = sessionWithPlaybackState.isPlaybackActive,
+ device = currentAudioDevice,
+ isInAudioSharing = isInAudioSharing,
+ canOpenAudioSwitcher =
+ !isInAudioSharing &&
+ currentAudioDevice !is AudioOutputDevice.Unknown,
+ )
}
}
}
}
+ .flatMapLatest { it }
.wrapInResult()
.stateIn(coroutineScope, SharingStarted.Eagerly, Result.Loading())
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
index 31a8977..aa07cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/MediaOutputInteractor.kt
@@ -179,9 +179,7 @@
return MediaDeviceSession(
packageName = packageName,
sessionToken = sessionToken,
- canAdjustVolume =
- playbackInfo != null &&
- playbackInfo?.volumeControl != VolumeProvider.VOLUME_CONTROL_FIXED,
+ canAdjustVolume = playbackInfo.volumeControl != VolumeProvider.VOLUME_CONTROL_FIXED,
appLabel = getApplicationLabel(packageName) ?: return null
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaOutputComponentModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaOutputComponentModel.kt
index 220fb2b..6588b44 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaOutputComponentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/domain/model/MediaOutputComponentModel.kt
@@ -24,11 +24,13 @@
val device: AudioOutputDevice
val isInAudioSharing: Boolean
+ val canOpenAudioSwitcher: Boolean
/** There is an ongoing call on the device. */
data class Calling(
override val device: AudioOutputDevice,
override val isInAudioSharing: Boolean,
+ override val canOpenAudioSwitcher: Boolean,
) : MediaOutputComponentModel
/** There is media playing on the device. */
@@ -37,11 +39,13 @@
val isPlaybackActive: Boolean,
override val device: AudioOutputDevice,
override val isInAudioSharing: Boolean,
+ override val canOpenAudioSwitcher: Boolean,
) : MediaOutputComponentModel
/** There is nothing playing on the device. */
data class Idle(
override val device: AudioOutputDevice,
override val isInAudioSharing: Boolean,
+ override val canOpenAudioSwitcher: Boolean,
) : MediaOutputComponentModel
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/ConnectedDeviceViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/ConnectedDeviceViewModel.kt
index 8ba672d..42f88b4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/ConnectedDeviceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/ConnectedDeviceViewModel.kt
@@ -16,11 +16,15 @@
package com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel
+import com.android.systemui.common.shared.model.Color
+
/**
* Models part of the Media Session Volume Panel component that displays connected device
* information.
*/
data class ConnectedDeviceViewModel(
val label: CharSequence,
+ val labelColor: Color,
val deviceName: CharSequence?,
+ val deviceNameColor: Color,
)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
index 36b42f2..e565de5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt
@@ -75,12 +75,25 @@
}
}
ConnectedDeviceViewModel(
- label,
- if (mediaOutputModel.isInAudioSharing) {
- context.getString(R.string.audio_sharing_description)
- } else {
- mediaOutputModel.device.name
- },
+ label = label,
+ labelColor =
+ Color.Attribute(com.android.internal.R.attr.materialColorOnSurfaceVariant),
+ deviceName =
+ if (mediaOutputModel.isInAudioSharing) {
+ context.getString(R.string.audio_sharing_description)
+ } else {
+ mediaOutputModel.device
+ .takeIf { it !is AudioOutputDevice.Unknown }
+ ?.name ?: context.getString(R.string.media_seamless_other_device)
+ },
+ deviceNameColor =
+ if (mediaOutputModel.canOpenAudioSwitcher) {
+ Color.Attribute(com.android.internal.R.attr.materialColorOnSurface)
+ } else {
+ Color.Attribute(
+ com.android.internal.R.attr.materialColorOnSurfaceVariant
+ )
+ },
)
}
.stateIn(
@@ -107,19 +120,39 @@
DeviceIconViewModel.IsPlaying(
icon = icon,
iconColor =
- Color.Attribute(com.android.internal.R.attr.materialColorSurface),
+ if (mediaOutputModel.canOpenAudioSwitcher) {
+ Color.Attribute(com.android.internal.R.attr.materialColorSurface)
+ } else {
+ Color.Attribute(
+ com.android.internal.R.attr.materialColorSurfaceContainerHighest
+ )
+ },
backgroundColor =
- Color.Attribute(com.android.internal.R.attr.materialColorSecondary),
+ if (mediaOutputModel.canOpenAudioSwitcher) {
+ Color.Attribute(com.android.internal.R.attr.materialColorSecondary)
+ } else {
+ Color.Attribute(com.android.internal.R.attr.materialColorOutline)
+ },
)
} else {
DeviceIconViewModel.IsNotPlaying(
icon = icon,
iconColor =
- Color.Attribute(
- com.android.internal.R.attr.materialColorOnSurfaceVariant
- ),
+ if (mediaOutputModel.canOpenAudioSwitcher) {
+ Color.Attribute(
+ com.android.internal.R.attr.materialColorOnSurfaceVariant
+ )
+ } else {
+ Color.Attribute(com.android.internal.R.attr.materialColorOutline)
+ },
backgroundColor =
- Color.Attribute(com.android.internal.R.attr.materialColorSurface),
+ if (mediaOutputModel.canOpenAudioSwitcher) {
+ Color.Attribute(com.android.internal.R.attr.materialColorSurface)
+ } else {
+ Color.Attribute(
+ com.android.internal.R.attr.materialColorSurfaceContainerHighest
+ )
+ },
)
}
}
@@ -132,7 +165,7 @@
val enabled: StateFlow<Boolean> =
mediaOutputComponentInteractor.mediaOutputModel
.filterData()
- .map { !it.isInAudioSharing }
+ .map { it.canOpenAudioSwitcher }
.stateIn(
coroutineScope,
SharingStarted.Eagerly,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
index cfcd6b1..56d0bce 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
@@ -63,13 +63,7 @@
private val changes = MutableSharedFlow<Unit>()
private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> =
audioOutputInteractor.currentAudioDevice
- .map { audioDevice ->
- if (audioDevice is AudioOutputDevice.Unknown) {
- builtinSpeaker
- } else {
- audioDevice.getAudioDeviceAttributes()
- }
- }
+ .map { audioDevice -> audioDevice.getAudioDeviceAttributes() }
.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), builtinSpeaker)
/**
@@ -185,7 +179,10 @@
.firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) }
}
}
- else -> null
+ is AudioOutputDevice.Wired -> null
+ is AudioOutputDevice.Remote -> null
+ is AudioOutputDevice.Unknown -> builtinSpeaker
+ is AudioOutputDevice.Unavailable -> builtinSpeaker
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 113a8c0..5e37d4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.hardware.display.DisplayManager;
+import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.TestableLooper;
@@ -80,6 +81,7 @@
private AccessibilityManager mAccessibilityManager;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private AccessibilityFloatingMenuController mController;
+ private TestableLooper mTestableLooper;
@Mock
private AccessibilityButtonTargetsObserver mTargetsObserver;
@Mock
@@ -108,6 +110,7 @@
mViewCaptureAwareWindowManager = new ViewCaptureAwareWindowManager(mWindowManager,
mLazyViewCapture, /* isViewCaptureEnabled= */ false);
mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
+ mTestableLooper = TestableLooper.get(this);
when(mTargetsObserver.getCurrentAccessibilityButtonTargets())
.thenReturn(Settings.Secure.getStringForUser(mContextWrapper.getContentResolver(),
@@ -231,7 +234,8 @@
mKeyguardCallback.onKeyguardVisibilityChanged(false);
mKeyguardCallback.onUserSwitching(fakeUserId);
- mKeyguardCallback.onUserSwitchComplete(fakeUserId);
+ mController.mUserInitializationCompleteCallback.onUserInitializationComplete(1);
+ mTestableLooper.processAllMessages();
assertThat(mController.mFloatingMenu).isNotNull();
}
@@ -346,7 +350,8 @@
new AccessibilityFloatingMenuController(mContextWrapper, windowManager,
viewCaptureAwareWindowManager, displayManager, mAccessibilityManager,
mTargetsObserver, mModeObserver, mKeyguardUpdateMonitor, mSecureSettings,
- displayTracker, mNavigationModeController);
+ displayTracker, mNavigationModeController, new Handler(
+ mTestableLooper.getLooper()));
controller.init();
return controller;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
index 6aecc0e..4883d1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
@@ -63,6 +63,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -365,7 +366,7 @@
testScope.runTest {
underTest.start()
- underTest.onQsExpansionStared()
+ underTest.onQsExpansionStarted()
runCurrent()
assertThat(faceAuthRepository.runningAuthRequest.value)
@@ -373,6 +374,79 @@
}
@Test
+ @EnableSceneContainer
+ fun faceAuthIsRequestedWhenQuickSettingsIsExpandedToTheShade() =
+ testScope.runTest {
+ underTest.start()
+ faceAuthRepository.canRunFaceAuth.value = true
+ kosmos.sceneInteractor.snapToScene(toScene = Scenes.QuickSettings, "for-test")
+ runCurrent()
+
+ kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "for-test")
+ kosmos.sceneInteractor.setTransitionState(
+ MutableStateFlow(
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.QuickSettings,
+ toScene = Scenes.Shade,
+ currentScene = flowOf(Scenes.QuickSettings),
+ progress = MutableStateFlow(0.2f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+ )
+
+ runCurrent()
+ assertThat(faceAuthRepository.runningAuthRequest.value)
+ .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED, true))
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun faceAuthIsRequestedOnlyOnceWhenQuickSettingsIsExpandedToTheShade() =
+ testScope.runTest {
+ underTest.start()
+ faceAuthRepository.canRunFaceAuth.value = true
+ kosmos.sceneInteractor.snapToScene(toScene = Scenes.QuickSettings, "for-test")
+ runCurrent()
+
+ kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "for-test")
+ kosmos.sceneInteractor.setTransitionState(
+ MutableStateFlow(
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.QuickSettings,
+ toScene = Scenes.Shade,
+ currentScene = flowOf(Scenes.QuickSettings),
+ progress = MutableStateFlow(0.2f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+ )
+
+ runCurrent()
+ assertThat(faceAuthRepository.runningAuthRequest.value)
+ .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED, true))
+ faceAuthRepository.runningAuthRequest.value = null
+
+ // expansion progress shouldn't trigger face auth again
+ kosmos.sceneInteractor.setTransitionState(
+ MutableStateFlow(
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.QuickSettings,
+ toScene = Scenes.Shade,
+ currentScene = flowOf(Scenes.QuickSettings),
+ progress = MutableStateFlow(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+ )
+ )
+
+ assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+ }
+
+ @Test
fun faceAuthIsRequestedWhenNotificationPanelClicked() =
testScope.runTest {
underTest.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 0ac04b6..76539d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -467,6 +467,16 @@
assertThat(values.toIdSets()).containsExactly(setOf(0, 1, 2))
}
+ @Test
+ fun displayFlow_onlyDefaultDisplayAvailable_neverEmitsEmptySet() =
+ testScope.runTest {
+ setDisplays(0)
+
+ val values: List<Set<Display>> by collectValues(displayRepository.displays)
+
+ assertThat(values.toIdSets()).containsExactly(setOf(0))
+ }
+
private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }
private fun Iterable<Set<Display>>.toIdSets(): List<Set<Int>> = map { it.ids().toSet() }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 4e1b12f..43c7ed6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -21,7 +21,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -44,7 +44,8 @@
@Mock private lateinit var activityTaskManagerService: IActivityTaskManager
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier
- @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ @Mock
+ private lateinit var keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor
@Before
fun setUp() {
@@ -57,7 +58,7 @@
activityTaskManagerService = activityTaskManagerService,
keyguardStateController = keyguardStateController,
keyguardSurfaceBehindAnimator = keyguardSurfaceBehindAnimator,
- keyguardTransitionInteractor = keyguardTransitionInteractor,
+ keyguardDismissTransitionInteractor = keyguardDismissTransitionInteractor,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
index 9eccd9f..3459645 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
@@ -1835,10 +1835,6 @@
assertThat(userEntries).hasSize(1)
val secondSemanticActions = userEntries?.values?.toList()?.get(0)?.semanticActions!!
- assertThat(secondSemanticActions.playOrPause?.icon)
- .isEqualTo(firstSemanticActions.playOrPause?.icon)
- assertThat(secondSemanticActions.playOrPause?.background)
- .isEqualTo(firstSemanticActions.playOrPause?.background)
assertThat(secondSemanticActions.nextOrCustom?.icon)
.isEqualTo(firstSemanticActions.nextOrCustom?.icon)
assertThat(secondSemanticActions.prevOrCustom?.icon)
@@ -1873,11 +1869,6 @@
assertThat(userEntries).hasSize(1)
val secondSemanticActions = userEntries?.values?.toList()?.get(0)?.semanticActions!!
-
- assertThat(secondSemanticActions.playOrPause?.icon)
- .isNotEqualTo(firstSemanticActions.playOrPause?.icon)
- assertThat(secondSemanticActions.playOrPause?.background)
- .isNotEqualTo(firstSemanticActions.playOrPause?.background)
assertThat(secondSemanticActions.nextOrCustom?.icon)
.isNotEqualTo(firstSemanticActions.nextOrCustom?.icon)
assertThat(secondSemanticActions.prevOrCustom?.icon)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
index 19735e2..8435b1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ModesTileTest.kt
@@ -25,9 +25,10 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
-import com.android.settingslib.notification.data.repository.FakeZenModeRepository
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
@@ -41,16 +42,15 @@
import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.res.R
-import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
-import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
+import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
+import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
import com.android.systemui.statusbar.policy.ui.dialog.ModesDialogDelegate
+import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.After
@@ -59,7 +59,6 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@@ -68,6 +67,9 @@
@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
class ModesTileTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val testDispatcher = kosmos.testDispatcher
@Mock private lateinit var qsHost: QSHost
@@ -85,17 +87,10 @@
@Mock private lateinit var dialogDelegate: ModesDialogDelegate
- private val testDispatcher = UnconfinedTestDispatcher()
- private val testScope = TestScope(testDispatcher)
-
private val inputHandler = FakeQSTileIntentUserInputHandler()
- private val zenModeRepository = FakeZenModeRepository()
+ private val zenModeRepository = kosmos.zenModeRepository
private val tileDataInteractor =
- ModesTileDataInteractor(
- context,
- ZenModeInteractor(context, zenModeRepository, mock<NotificationSettingsRepository>()),
- testDispatcher
- )
+ ModesTileDataInteractor(context, kosmos.zenModeInteractor, testDispatcher)
private val mapper =
ModesTileMapper(
context.orCreateTestableResources
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
index a8d5008..eb1a04d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -308,6 +308,40 @@
assertThat(backlinksData.getCompoundDrawablesRelative()[2]).isNotNull();
}
+ @Test
+ @EnableFlags(Flags.FLAG_APP_CLIPS_BACKLINKS)
+ public void appClipsLaunched_backlinks_multipleBacklinksAvailable_duplicateName()
+ throws RemoteException {
+ // Set up mocking for multiple backlinks.
+ ResolveInfo resolveInfo1 = createBacklinksTaskResolveInfo();
+
+ ResolveInfo resolveInfo2 = createBacklinksTaskResolveInfo();
+ RunningTaskInfo runningTaskInfo2 = createTaskInfoForBacklinksTask();
+ int taskId2 = BACKLINKS_TASK_ID + 2;
+ runningTaskInfo2.taskId = taskId2;
+
+ when(mAtmService.getTasks(eq(Integer.MAX_VALUE), eq(false), eq(false),
+ mDisplayIdCaptor.capture()))
+ .thenReturn(List.of(TASK_THAT_SUPPORTS_BACKLINKS, runningTaskInfo2));
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(resolveInfo1,
+ resolveInfo1, resolveInfo1, resolveInfo2, resolveInfo2, resolveInfo2);
+ when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
+
+ // Using same AssistContent data for both tasks.
+ mockForAssistContent(ASSIST_CONTENT_FOR_BACKLINKS_TASK, BACKLINKS_TASK_ID);
+ mockForAssistContent(ASSIST_CONTENT_FOR_BACKLINKS_TASK, taskId2);
+
+ // Mocking complete, trigger backlinks.
+ launchActivity();
+ waitForIdleSync();
+
+ // Verify default backlink shown to user has the numerical suffix.
+ TextView backlinksData = mActivity.findViewById(R.id.backlinks_data);
+ assertThat(backlinksData.getText().toString()).isEqualTo(
+ mContext.getString(R.string.backlinks_duplicate_label_format,
+ BACKLINKS_TASK_APP_NAME, 1));
+ }
+
private void setUpMocksForBacklinks() throws RemoteException {
when(mAtmService.getTasks(eq(Integer.MAX_VALUE), eq(false), eq(false),
mDisplayIdCaptor.capture()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 5a5cdcd..3ba1447e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -61,7 +61,6 @@
import com.android.systemui.media.controls.controller.keyguardMediaController
import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.sceneDataSourceDelegator
-import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.lockscreen.lockscreenSmartspaceController
import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController
@@ -417,13 +416,17 @@
// Communal is open.
goToScene(CommunalScenes.Communal)
- // Shade shows up.
- shadeTestUtil.setQsExpansion(0.5f)
- testableLooper.processAllMessages()
+ // Touch starts and ends.
assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
assertThat(underTest.onTouchEvent(CANCEL_EVENT)).isTrue()
+
+ // Up event is no longer processed
assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse()
+
+ // Move event can still be processed
assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
}
}
@@ -702,7 +705,7 @@
verify(containerView).onTouchEvent(DOWN_EVENT)
// User is interacting with shade on lockscreen.
- fakeShadeRepository.setLegacyLockscreenShadeTracking(true)
+ shadeTestUtil.setLockscreenShadeTracking(true)
testableLooper.processAllMessages()
// A move event is ignored while the user is already interacting.
@@ -716,6 +719,30 @@
}
@Test
+ fun onTouchEvent_shadeExpanding_touchesNotDispatched() =
+ with(kosmos) {
+ testScope.runTest {
+ // On lockscreen.
+ goToScene(CommunalScenes.Blank)
+ whenever(
+ notificationStackScrollLayoutController.isBelowLastNotification(
+ any(),
+ any()
+ )
+ )
+ .thenReturn(true)
+
+ // Shade is open slightly.
+ shadeTestUtil.setShadeExpansion(0.01f)
+ testableLooper.processAllMessages()
+
+ // Touches are not consumed.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ verify(containerView, never()).onTouchEvent(DOWN_EVENT)
+ }
+ }
+
+ @Test
fun onTouchEvent_bouncerInteracting_movesNotDispatched() =
with(kosmos) {
testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 523d15c..9481e5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -155,7 +155,6 @@
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
import com.android.systemui.statusbar.notification.data.repository.NotificationsKeyguardViewStateRepository;
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor;
-import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor;
import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.AmbientState;
@@ -163,7 +162,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
-import com.android.systemui.statusbar.notification.stack.data.repository.FakeHeadsUpNotificationRepository;
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
@@ -365,13 +363,6 @@
protected TestScope mTestScope = mKosmos.getTestScope();
protected ShadeInteractor mShadeInteractor;
protected PowerInteractor mPowerInteractor;
- protected FakeHeadsUpNotificationRepository mFakeHeadsUpNotificationRepository =
- new FakeHeadsUpNotificationRepository();
- protected NotificationsKeyguardViewStateRepository mNotificationsKeyguardViewStateRepository =
- new NotificationsKeyguardViewStateRepository();
- protected NotificationsKeyguardInteractor mNotificationsKeyguardInteractor =
- new NotificationsKeyguardInteractor(mNotificationsKeyguardViewStateRepository);
- protected HeadsUpNotificationInteractor mHeadsUpNotificationInteractor;
protected NotificationPanelViewController.TouchHandler mTouchHandler;
protected ConfigurationController mConfigurationController;
protected SysuiStatusBarStateController mStatusBarStateController;
@@ -689,12 +680,6 @@
when(longPressHandlingView.getResources()).thenReturn(longPressHandlingViewRes);
when(longPressHandlingViewRes.getString(anyInt())).thenReturn("");
-
- mHeadsUpNotificationInteractor =
- new HeadsUpNotificationInteractor(mFakeHeadsUpNotificationRepository,
- mDeviceEntryFaceAuthInteractor, mKeyguardTransitionInteractor,
- mNotificationsKeyguardInteractor, mShadeInteractor);
-
mNotificationPanelViewController = new NotificationPanelViewController(
mView,
mMainHandler,
@@ -769,7 +754,6 @@
mActivityStarter,
mSharedNotificationContainerInteractor,
mActiveNotificationsInteractor,
- mHeadsUpNotificationInteractor,
mShadeAnimationInteractor,
mKeyguardViewConfigurator,
mDeviceEntryFaceAuthInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarSignalPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarSignalPolicyTest.kt
new file mode 100644
index 0000000..593f873
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarSignalPolicyTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2024 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.statusbar
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.Flags.FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testCase
+import com.android.systemui.statusbar.connectivity.IconState
+import com.android.systemui.statusbar.connectivity.NetworkController
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
+import com.android.systemui.statusbar.phone.StatusBarSignalPolicy_Factory
+import com.android.systemui.statusbar.phone.ui.StatusBarIconController
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.airplaneModeInteractor
+import com.android.systemui.statusbar.policy.SecurityController
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.kotlin.JavaAdapter
+import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.verifyZeroInteractions
+import kotlin.test.Test
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class StatusBarSignalPolicyTest : SysuiTestCase() {
+ private val kosmos = Kosmos().also { it.testCase = this }
+
+ private lateinit var underTest: StatusBarSignalPolicy
+
+ private val testScope = TestScope()
+
+ private val javaAdapter = JavaAdapter(testScope.backgroundScope)
+ private val airplaneModeInteractor = kosmos.airplaneModeInteractor
+
+ private val securityController = mock<SecurityController>()
+ private val tunerService = mock<TunerService>()
+ private val statusBarIconController = mock<StatusBarIconController>()
+ private val networkController = mock<NetworkController>()
+ private val carrierConfigTracker = mock<CarrierConfigTracker>()
+
+ private var slotAirplane: String? = null
+
+ @Before
+ fun setup() {
+ underTest =
+ StatusBarSignalPolicy_Factory.newInstance(
+ mContext,
+ statusBarIconController,
+ carrierConfigTracker,
+ networkController,
+ securityController,
+ tunerService,
+ javaAdapter,
+ airplaneModeInteractor,
+ )
+
+ slotAirplane = mContext.getString(R.string.status_bar_airplane)
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR)
+ fun airplaneModeViaInteractor_statusBarSignalPolicyRefactorFlagEnabled_iconUpdated() =
+ testScope.runTest {
+ underTest.start()
+ airplaneModeInteractor.setIsAirplaneMode(true)
+ runCurrent()
+ verify(statusBarIconController).setIconVisibility(slotAirplane, true)
+
+ airplaneModeInteractor.setIsAirplaneMode(false)
+ runCurrent()
+ verify(statusBarIconController).setIconVisibility(slotAirplane, false)
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR)
+ fun airplaneModeViaSignalCallback_statusBarSignalPolicyRefactorFlagEnabled_iconNotUpdated() =
+ testScope.runTest {
+ underTest.start()
+ runCurrent()
+ clearInvocations(statusBarIconController)
+
+ // Make sure the legacy code path does not change airplane mode when the refactor
+ // flag is enabled.
+ underTest.setIsAirplaneMode(IconState(true, TelephonyIcons.FLIGHT_MODE_ICON, ""))
+ runCurrent()
+ verifyZeroInteractions(statusBarIconController)
+
+ underTest.setIsAirplaneMode(IconState(false, TelephonyIcons.FLIGHT_MODE_ICON, ""))
+ runCurrent()
+ verifyZeroInteractions(statusBarIconController)
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR)
+ fun statusBarSignalPolicyInitialization_statusBarSignalPolicyRefactorFlagEnabled_initNoOp() =
+ testScope.runTest {
+ // Make sure StatusBarSignalPolicy.init does no initialization when
+ // the refactor flag is disabled.
+ underTest.init()
+ verifyZeroInteractions(securityController, networkController, tunerService)
+ }
+
+ @Test
+ @DisableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR)
+ fun airplaneModeViaSignalCallback_statusBarSignalPolicyRefactorFlagDisabled_iconUpdated() =
+ testScope.runTest {
+ underTest.init()
+
+ underTest.setIsAirplaneMode(IconState(true, TelephonyIcons.FLIGHT_MODE_ICON, ""))
+ runCurrent()
+ verify(statusBarIconController).setIconVisibility(slotAirplane, true)
+
+ underTest.setIsAirplaneMode(IconState(false, TelephonyIcons.FLIGHT_MODE_ICON, ""))
+ runCurrent()
+ verify(statusBarIconController).setIconVisibility(slotAirplane, false)
+ }
+
+ @Test
+ @DisableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR)
+ fun airplaneModeViaInteractor_statusBarSignalPolicyRefactorFlagDisabled_iconNotUpdated() =
+ testScope.runTest {
+ underTest.init()
+
+ // Make sure changing airplane mode from airplaneModeRepository does nothing
+ // if the StatusBarSignalPolicyRefactor is not enabled.
+ airplaneModeInteractor.setIsAirplaneMode(true)
+ runCurrent()
+ verifyZeroInteractions(statusBarIconController)
+
+ airplaneModeInteractor.setIsAirplaneMode(false)
+ runCurrent()
+ verifyZeroInteractions(statusBarIconController)
+ }
+
+ @Test
+ @DisableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR)
+ fun statusBarSignalPolicyInitialization_statusBarSignalPolicyRefactorFlagDisabled_startNoOp() =
+ testScope.runTest {
+ // Make sure StatusBarSignalPolicy.start does no initialization when
+ // the refactor flag is disabled.
+ underTest.start()
+ verifyZeroInteractions(securityController, networkController, tunerService)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index e4945fc..1a1af2e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -342,7 +342,7 @@
val stackTop = 200f
val stackHeight = 800f
whenever(ambientState.stackTop).thenReturn(stackTop)
- whenever(ambientState.stackHeight).thenReturn(stackHeight)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(stackHeight)
val shelfTop = stackTop + stackHeight - shelf.height
val stackScrollAlgorithmState = StackScrollAlgorithmState()
val viewInShelf = mock(ExpandableView::class.java)
@@ -378,7 +378,7 @@
val stackTop = 200f
val stackHeight = 800f
whenever(ambientState.stackTop).thenReturn(stackTop)
- whenever(ambientState.stackHeight).thenReturn(stackHeight)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(stackHeight)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
whenever(ambientState.isShadeExpanded).thenReturn(true)
@@ -404,7 +404,7 @@
fun updateState_withNullLastVisibleBackgroundChild_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
- whenever(ambientState.stackHeight).thenReturn(100f)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(100f)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
val endOfStack = 200f + paddingBetweenElements
@@ -433,7 +433,7 @@
val stackTop = 200f
val stackHeight = 800f
whenever(ambientState.stackTop).thenReturn(stackTop)
- whenever(ambientState.stackHeight).thenReturn(stackHeight)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(stackHeight)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
whenever(ambientState.isShadeExpanded).thenReturn(true)
@@ -459,7 +459,7 @@
fun updateState_withNullFirstViewInShelf_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
- whenever(ambientState.stackHeight).thenReturn(100f)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(100f)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
val endOfStack = 200f + paddingBetweenElements
@@ -488,7 +488,7 @@
val stackTop = 200f
val stackHeight = 800f
whenever(ambientState.stackTop).thenReturn(stackTop)
- whenever(ambientState.stackHeight).thenReturn(stackHeight)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(stackHeight)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
val lastVisibleBackgroundChild = mock<ExpandableView>()
@@ -514,7 +514,7 @@
fun updateState_withCollapsedShade_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
- whenever(ambientState.stackHeight).thenReturn(100f)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(100f)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
val endOfStack = 200f + paddingBetweenElements
@@ -543,7 +543,7 @@
val stackTop = 200f
val stackHeight = 800f
whenever(ambientState.stackTop).thenReturn(stackTop)
- whenever(ambientState.stackHeight).thenReturn(stackHeight)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(stackHeight)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
whenever(ambientState.isShadeExpanded).thenReturn(true)
@@ -583,7 +583,7 @@
fun updateState_withHiddenSectionBeforeShelf_hideShelf() {
// GIVEN
whenever(ambientState.stackY).thenReturn(100f)
- whenever(ambientState.stackHeight).thenReturn(100f)
+ whenever(ambientState.interpolatedStackHeight).thenReturn(100f)
val paddingBetweenElements =
context.resources.getDimensionPixelSize(R.dimen.notification_divider_height)
val endOfStack = 200f + paddingBetweenElements
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 8d1228c..a18de68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -245,26 +245,12 @@
when(mStackSizeCalculator.computeHeight(eq(mStackScroller), anyInt(), anyFloat()))
.thenReturn((float) stackHeight);
- mStackScroller.updateContentHeight();
+ mStackScroller.updateStackHeight();
assertThat(mStackScroller.getIntrinsicStackHeight()).isEqualTo(stackHeight);
}
@Test
- @DisableSceneContainer
- public void testIntrinsicStackHeight_includesTopScrimPadding() {
- int stackHeight = 300;
- int topScrimPadding = px(R.dimen.notification_side_paddings);
- when(mStackSizeCalculator.computeHeight(eq(mStackScroller), anyInt(), anyFloat()))
- .thenReturn((float) stackHeight);
-
- mStackScroller.updateContentHeight();
-
- assertThat(mStackScroller.getIntrinsicStackHeight())
- .isEqualTo(stackHeight + topScrimPadding);
- }
-
- @Test
@DisableSceneContainer // TODO(b/312473478): address disabled test
public void testUpdateStackHeight_qsExpansionZero() {
final float expansionFraction = 0.2f;
@@ -289,8 +275,8 @@
endHeight * StackScrollAlgorithm.START_FRACTION,
endHeight, expansionFraction);
- mStackScroller.updateStackHeight(endHeight, expansionFraction);
- assertThat(mAmbientState.getStackHeight()).isEqualTo(expected);
+ mStackScroller.updateInterpolatedStackHeight(endHeight, expansionFraction);
+ assertThat(mAmbientState.getInterpolatedStackHeight()).isEqualTo(expected);
}
@Test
@@ -309,7 +295,7 @@
// THEN stackHeight and stackEndHeight are the same
verify(mAmbientState).setStackEndHeight(stackEndHeight);
- verify(mAmbientState).setStackHeight(stackEndHeight);
+ verify(mAmbientState).setInterpolatedStackHeight(stackEndHeight);
}
@Test
@@ -329,7 +315,7 @@
// THEN stackHeight is changed by the expansion frac
verify(mAmbientState).setStackEndHeight(stackEndHeight);
- verify(mAmbientState).setStackHeight(stackEndHeight * 0.75f);
+ verify(mAmbientState).setInterpolatedStackHeight(stackEndHeight * 0.75f);
}
@Test
@@ -349,7 +335,7 @@
// THEN stackHeight is measured from the stack top
verify(mAmbientState).setStackEndHeight(stackEndHeight);
- verify(mAmbientState).setStackHeight(stackEndHeight);
+ verify(mAmbientState).setInterpolatedStackHeight(stackEndHeight);
}
@Test
@@ -363,7 +349,7 @@
clearInvocations(mAmbientState);
mStackScroller.updateStackEndHeightAndStackHeight(1f);
- verify(mAmbientState).setStackHeight(eq(300f));
+ verify(mAmbientState).setInterpolatedStackHeight(eq(300f));
}
@Test
@@ -376,7 +362,7 @@
clearInvocations(mAmbientState);
mStackScroller.updateStackEndHeightAndStackHeight(expansionFraction);
verify(mAmbientState, never()).setStackEndHeight(anyFloat());
- verify(mAmbientState).setStackHeight(anyFloat());
+ verify(mAmbientState).setInterpolatedStackHeight(anyFloat());
}
@Test
@@ -391,14 +377,14 @@
clearInvocations(mAmbientState);
mStackScroller.updateStackEndHeightAndStackHeight(expansionFraction);
verify(mAmbientState, never()).setStackEndHeight(anyFloat());
- verify(mAmbientState).setStackHeight(anyFloat());
+ verify(mAmbientState).setInterpolatedStackHeight(anyFloat());
// Validate that when the animation ends the stackEndHeight is recalculated immediately
clearInvocations(mAmbientState);
mStackScroller.setPanelFlinging(false);
verify(mAmbientState).setFlinging(eq(false));
verify(mAmbientState).setStackEndHeight(anyFloat());
- verify(mAmbientState).setStackHeight(anyFloat());
+ verify(mAmbientState).setInterpolatedStackHeight(anyFloat());
}
@Test
@@ -440,6 +426,86 @@
}
@Test
+ @EnableSceneContainer
+ public void setExpandFraction_fullyCollapsed() {
+ // Given: NSSL has a height
+ when(mStackScroller.getHeight()).thenReturn(1200);
+ // And: stack bounds are set
+ float expandFraction = 0.0f;
+ float stackTop = 100;
+ float stackCutoff = 1100;
+ float stackHeight = stackCutoff - stackTop;
+ mStackScroller.setStackTop(stackTop);
+ mStackScroller.setStackCutoff(stackCutoff);
+
+ // When: panel is fully collapsed
+ mStackScroller.setExpandFraction(expandFraction);
+
+ // Then
+ assertThat(mAmbientState.getExpansionFraction()).isEqualTo(expandFraction);
+ assertThat(mAmbientState.isExpansionChanging()).isFalse();
+ assertThat(mAmbientState.getStackEndHeight()).isEqualTo(stackHeight);
+ assertThat(mAmbientState.getInterpolatedStackHeight()).isEqualTo(
+ stackHeight * StackScrollAlgorithm.START_FRACTION);
+ assertThat(mAmbientState.isShadeExpanded()).isFalse();
+ assertThat(mStackScroller.getExpandedHeight()).isZero();
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void setExpandFraction_expanding() {
+ // Given: NSSL has a height
+ when(mStackScroller.getHeight()).thenReturn(1200);
+ // And: stack bounds are set
+ float expandFraction = 0.6f;
+ float stackTop = 100;
+ float stackCutoff = 1100;
+ float stackHeight = stackCutoff - stackTop;
+ mStackScroller.setStackTop(stackTop);
+ mStackScroller.setStackCutoff(stackCutoff);
+
+ // When: panel is expanding
+ mStackScroller.setExpandFraction(expandFraction);
+
+ // Then
+ assertThat(mAmbientState.getExpansionFraction()).isEqualTo(expandFraction);
+ assertThat(mAmbientState.isExpansionChanging()).isTrue();
+ assertThat(mAmbientState.getStackEndHeight()).isEqualTo(stackHeight);
+ assertThat(mAmbientState.getInterpolatedStackHeight()).isGreaterThan(
+ stackHeight * StackScrollAlgorithm.START_FRACTION);
+ assertThat(mAmbientState.getInterpolatedStackHeight()).isLessThan(stackHeight);
+ assertThat(mStackScroller.getExpandedHeight()).isGreaterThan(0f);
+ assertThat(mAmbientState.isShadeExpanded()).isTrue();
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void setExpandFraction_fullyExpanded() {
+ // Given: NSSL has a height
+ int viewHeight = 1200;
+ when(mStackScroller.getHeight()).thenReturn(viewHeight);
+ // And: stack bounds are set
+ float expandFraction = 1.0f;
+ float stackTop = 100;
+ float stackCutoff = 1100;
+ float stackHeight = stackCutoff - stackTop;
+ mStackScroller.setStackTop(stackTop);
+ mStackScroller.setStackCutoff(stackCutoff);
+
+ // When: panel is fully expanded
+ mStackScroller.setExpandFraction(expandFraction);
+
+ // Then
+ assertThat(mAmbientState.getExpansionFraction()).isEqualTo(expandFraction);
+ assertThat(mAmbientState.isExpansionChanging()).isFalse();
+ assertThat(mAmbientState.getStackEndHeight()).isEqualTo(stackHeight);
+ assertThat(mAmbientState.getInterpolatedStackHeight()).isEqualTo(stackHeight);
+ assertThat(mStackScroller.getExpandedHeight()).isEqualTo(viewHeight);
+ assertThat(mAmbientState.isShadeExpanded()).isTrue();
+ }
+
+ @Test
+ @DisableSceneContainer
public void testSetExpandedHeight_listenerReceivedCallbacks() {
final float expectedHeight = 0f;
@@ -466,6 +532,7 @@
}
@Test
+ @DisableSceneContainer
public void testSetExpandedHeight_withSplitShade_doesntInterpolateStackHeight() {
mTestableResources
.addOverride(R.bool.config_use_split_notification_shade, /* value= */ true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 7e79019..3e8bf47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -1114,6 +1114,7 @@
}
@Test
+ @DisableSceneContainer
fun shadeOpened_hunDoesNotOverlapQQS_hunShouldHaveNoShadow() {
// Given: shade is opened, yTranslation of HUN is equal to QQS Panel's height,
// the height of HUN is equal to the height of QQS Panel,
@@ -1144,6 +1145,7 @@
}
@Test
+ @DisableSceneContainer
fun shadeClosed_hunShouldHaveFullShadow() {
// Given: shade is closed, ambientState.stackTranslation == -ambientState.topPadding,
// the height of HUN is equal to the height of QQS Panel,
@@ -1172,6 +1174,7 @@
}
@Test
+ @DisableSceneContainer
fun draggingHunToOpenShade_hunShouldHavePartialShadow() {
// Given: shade is closed when HUN pops up,
// now drags down the HUN to open shade
@@ -1447,7 +1450,7 @@
// set stackEndHeight and stackHeight
// ExpansionFractionWithoutShelf == stackHeight / stackEndHeight
ambientState.stackEndHeight = 100f
- ambientState.stackHeight = ambientState.stackEndHeight * fraction
+ ambientState.interpolatedStackHeight = ambientState.stackEndHeight * fraction
}
private fun resetViewStates_hunYTranslationIs(expected: Float) {
@@ -1531,7 +1534,7 @@
// shade is fully open
ambientState.expansionFraction = 1.0f
with(fullStackHeight) {
- ambientState.stackHeight = this
+ ambientState.interpolatedStackHeight = this
ambientState.stackEndHeight = this
}
stackScrollAlgorithm.setIsExpanded(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index 76dc65c..2ed3473 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -34,6 +34,7 @@
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.statusbar.StatusBarIcon
import com.android.settingslib.notification.modes.TestModeBuilder
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
@@ -41,6 +42,7 @@
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
+import com.android.systemui.kosmos.testScope
import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.screenrecord.RecordingController
@@ -71,9 +73,7 @@
import com.android.systemui.util.time.FakeSystemClock
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -145,7 +145,7 @@
private lateinit var alarmCallbackCaptor:
ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
- private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val testScope = kosmos.testScope
private val fakeConnectedDisplayStateProvider = FakeConnectedDisplayStateProvider()
private val zenModeController = FakeZenModeController()
@@ -249,7 +249,7 @@
statusBarPolicy.init()
clearInvocations(iconController)
- fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
+ fakeConnectedDisplayStateProvider.setState(State.CONNECTED)
runCurrent()
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
@@ -261,7 +261,8 @@
statusBarPolicy.init()
clearInvocations(iconController)
- fakeConnectedDisplayStateProvider.emit(State.DISCONNECTED)
+ fakeConnectedDisplayStateProvider.setState(State.DISCONNECTED)
+ runCurrent()
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, false)
}
@@ -272,9 +273,12 @@
statusBarPolicy.init()
clearInvocations(iconController)
- fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
- fakeConnectedDisplayStateProvider.emit(State.DISCONNECTED)
- fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
+ fakeConnectedDisplayStateProvider.setState(State.CONNECTED)
+ runCurrent()
+ fakeConnectedDisplayStateProvider.setState(State.DISCONNECTED)
+ runCurrent()
+ fakeConnectedDisplayStateProvider.setState(State.CONNECTED)
+ runCurrent()
inOrder(iconController).apply {
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
@@ -289,7 +293,8 @@
statusBarPolicy.init()
clearInvocations(iconController)
- fakeConnectedDisplayStateProvider.emit(State.CONNECTED_SECURE)
+ fakeConnectedDisplayStateProvider.setState(State.CONNECTED_SECURE)
+ runCurrent()
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
}
@@ -390,7 +395,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_UI_ICONS)
+ @EnableFlags(android.app.Flags.FLAG_MODES_UI, android.app.Flags.FLAG_MODES_UI_ICONS)
fun zenModeInteractorActiveModeChanged_showsModeIcon() =
testScope.runTest {
statusBarPolicy.init()
@@ -403,8 +408,8 @@
.setName("Bedtime Mode")
.setType(AutomaticZenRule.TYPE_BEDTIME)
.setActive(true)
- .setPackage("some.package")
- .setIconResId(123)
+ .setPackage(mContext.packageName)
+ .setIconResId(android.R.drawable.ic_lock_lock)
.build(),
TestModeBuilder()
.setId("other")
@@ -412,7 +417,7 @@
.setType(AutomaticZenRule.TYPE_OTHER)
.setActive(true)
.setPackage(SystemZenRules.PACKAGE_ANDROID)
- .setIconResId(456)
+ .setIconResId(android.R.drawable.ic_media_play)
.build(),
)
)
@@ -422,17 +427,25 @@
verify(iconController)
.setResourceIcon(
eq(ZEN_SLOT),
- eq("some.package"),
- eq(123),
- eq(null),
- eq("Bedtime Mode")
+ eq(mContext.packageName),
+ eq(android.R.drawable.ic_lock_lock),
+ any(), // non-null
+ eq("Bedtime Mode"),
+ eq(StatusBarIcon.Shape.FIXED_SPACE)
)
zenModeRepository.deactivateMode("bedtime")
runCurrent()
verify(iconController)
- .setResourceIcon(eq(ZEN_SLOT), eq(null), eq(456), eq(null), eq("Other Mode"))
+ .setResourceIcon(
+ eq(ZEN_SLOT),
+ eq(null),
+ eq(android.R.drawable.ic_media_play),
+ any(), // non-null
+ eq("Other Mode"),
+ eq(StatusBarIcon.Shape.FIXED_SPACE)
+ )
zenModeRepository.deactivateMode("other")
runCurrent()
@@ -441,7 +454,7 @@
}
@Test
- @EnableFlags(android.app.Flags.FLAG_MODES_UI_ICONS)
+ @EnableFlags(android.app.Flags.FLAG_MODES_UI, android.app.Flags.FLAG_MODES_UI_ICONS)
fun zenModeControllerOnGlobalZenChanged_doesNotUpdateDndIcon() {
statusBarPolicy.init()
reset(iconController)
@@ -450,7 +463,8 @@
verify(iconController, never()).setIconVisibility(eq(ZEN_SLOT), any())
verify(iconController, never()).setIcon(eq(ZEN_SLOT), anyInt(), any())
- verify(iconController, never()).setResourceIcon(eq(ZEN_SLOT), any(), any(), any(), any())
+ verify(iconController, never())
+ .setResourceIcon(eq(ZEN_SLOT), any(), any(), any(), any(), any())
}
@Test
@@ -466,7 +480,7 @@
verify(iconController, never()).setIconVisibility(eq(ZEN_SLOT), any())
verify(iconController, never()).setIcon(eq(ZEN_SLOT), anyInt(), any())
verify(iconController, never())
- .setResourceIcon(eq(ZEN_SLOT), any(), any(), any(), any())
+ .setResourceIcon(eq(ZEN_SLOT), any(), any(), any(), any(), any())
}
@Test
@@ -529,9 +543,11 @@
}
private class FakeConnectedDisplayStateProvider : ConnectedDisplayInteractor {
- private val flow = MutableSharedFlow<State>()
+ private val flow = MutableStateFlow(State.DISCONNECTED)
- suspend fun emit(value: State) = flow.emit(value)
+ fun setState(value: State) {
+ flow.value = value
+ }
override val connectedDisplayState: Flow<State>
get() = flow
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 54c03e8..3e3c046 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -84,10 +84,9 @@
import com.android.systemui.flags.DisableSceneContainer;
import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.keyguard.domain.interactor.KeyguardDismissTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;
-import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -235,11 +234,10 @@
mUdfpsOverlayInteractor,
mActivityStarter,
mKeyguardTransitionInteractor,
+ mock(KeyguardDismissTransitionInteractor.class),
StandardTestDispatcher(null, null),
- () -> mock(WindowManagerLockscreenVisibilityInteractor.class),
() -> mock(KeyguardDismissActionInteractor.class),
mSelectedUserInteractor,
- () -> mock(KeyguardSurfaceBehindInteractor.class),
mock(JavaAdapter.class),
() -> mSceneInteractor,
mock(StatusBarKeyguardViewManagerInteractor.class),
@@ -759,11 +757,10 @@
mUdfpsOverlayInteractor,
mActivityStarter,
mock(KeyguardTransitionInteractor.class),
+ mock(KeyguardDismissTransitionInteractor.class),
StandardTestDispatcher(null, null),
- () -> mock(WindowManagerLockscreenVisibilityInteractor.class),
() -> mock(KeyguardDismissActionInteractor.class),
mSelectedUserInteractor,
- () -> mock(KeyguardSurfaceBehindInteractor.class),
mock(JavaAdapter.class),
() -> mSceneInteractor,
mock(StatusBarKeyguardViewManagerInteractor.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
new file mode 100644
index 0000000..90732d01
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/IconManagerTest.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2024 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.statusbar.phone.ui
+
+import android.app.Flags
+import android.graphics.drawable.Icon
+import android.os.UserHandle
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.statusbar.StatusBarIcon
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
+import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter
+import com.android.systemui.util.Assert
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.RETURNS_DEEP_STUBS
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconManagerTest : SysuiTestCase() {
+
+ private lateinit var underTest: IconManager
+ private lateinit var viewGroup: ViewGroup
+
+ @Before
+ fun setUp() {
+ Assert.setTestThread(Thread.currentThread())
+ viewGroup = LinearLayout(context)
+ underTest =
+ IconManager(
+ viewGroup,
+ StatusBarLocation.HOME,
+ mock<WifiUiAdapter>(defaultAnswer = RETURNS_DEEP_STUBS),
+ mock<MobileUiAdapter>(defaultAnswer = RETURNS_DEEP_STUBS),
+ mock<MobileContextProvider>(defaultAnswer = RETURNS_DEEP_STUBS),
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
+ fun addIcon_shapeWrapContent_addsIconViewWithVariableWidth() {
+ val sbIcon = newStatusBarIcon(StatusBarIcon.Shape.WRAP_CONTENT)
+
+ underTest.addIcon(0, "slot", false, sbIcon)
+
+ assertThat(viewGroup.childCount).isEqualTo(1)
+ val iconView = viewGroup.getChildAt(0) as StatusBarIconView
+ assertThat(iconView).isNotNull()
+
+ assertThat(iconView.layoutParams.width).isEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT)
+ assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_UI, Flags.FLAG_MODES_UI_ICONS)
+ fun addIcon_shapeFixedSpace_addsIconViewWithFixedWidth() {
+ val sbIcon = newStatusBarIcon(StatusBarIcon.Shape.FIXED_SPACE)
+
+ underTest.addIcon(0, "slot", false, sbIcon)
+
+ assertThat(viewGroup.childCount).isEqualTo(1)
+ val iconView = viewGroup.getChildAt(0) as StatusBarIconView
+ assertThat(iconView).isNotNull()
+
+ assertThat(iconView.layoutParams.width).isNotEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT)
+ assertThat(iconView.layoutParams.width).isEqualTo(iconView.layoutParams.height)
+ assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.FIT_CENTER)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MODES_UI_ICONS)
+ fun addIcon_iconsFlagOff_addsIconViewWithVariableWidth() {
+ val sbIcon = newStatusBarIcon(StatusBarIcon.Shape.FIXED_SPACE)
+
+ underTest.addIcon(0, "slot", false, sbIcon)
+
+ assertThat(viewGroup.childCount).isEqualTo(1)
+ val iconView = viewGroup.getChildAt(0) as StatusBarIconView
+ assertThat(iconView).isNotNull()
+
+ assertThat(iconView.layoutParams.width).isEqualTo(ViewGroup.LayoutParams.WRAP_CONTENT)
+ assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER)
+ }
+
+ private fun newStatusBarIcon(shape: StatusBarIcon.Shape) =
+ StatusBarIcon(
+ UserHandle.CURRENT,
+ context.packageName,
+ Icon.createWithResource(context, android.R.drawable.ic_media_next),
+ 0,
+ 0,
+ "",
+ StatusBarIcon.Type.ResourceIcon,
+ shape,
+ )
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
index 26a57e4..50a13b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImplTest.kt
@@ -424,7 +424,14 @@
@EnableFlags(android.app.Flags.FLAG_MODES_UI, android.app.Flags.FLAG_MODES_UI_ICONS)
fun setResourceIcon_setsIconAndPreloadedIconInHolder() {
val drawable = ColorDrawable(1)
- underTest.setResourceIcon("slot", "some.package", 123, drawable, "description")
+ underTest.setResourceIcon(
+ "slot",
+ "some.package",
+ 123,
+ drawable,
+ "description",
+ StatusBarIcon.Shape.FIXED_SPACE
+ )
val iconHolder = iconList.getIconHolder("slot", 0)
assertThat(iconHolder).isNotNull()
@@ -432,6 +439,7 @@
assertThat(iconHolder?.icon?.icon?.resId).isEqualTo(123)
assertThat(iconHolder?.icon?.icon?.resPackage).isEqualTo("some.package")
assertThat(iconHolder?.icon?.contentDescription).isEqualTo("description")
+ assertThat(iconHolder?.icon?.shape).isEqualTo(StatusBarIcon.Shape.FIXED_SPACE)
assertThat(iconHolder?.icon?.preloadedIcon).isEqualTo(drawable)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 76982ae..6de2caa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -28,7 +28,6 @@
import android.net.vcn.VcnTransportInfo
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
-import android.os.Bundle
import android.os.ParcelUuid
import android.telephony.CarrierConfigManager
import android.telephony.ServiceState
@@ -56,7 +55,6 @@
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
-import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
@@ -74,7 +72,6 @@
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.android.wifitrackerlib.MergedCarrierEntry
import com.android.wifitrackerlib.WifiEntry
@@ -98,6 +95,7 @@
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@@ -602,47 +600,85 @@
@SuppressLint("UnspecifiedRegisterReceiverFlag")
@Test
- fun testDeviceServiceStateFromBroadcast_eagerlyWatchesBroadcast() =
+ fun testDeviceEmergencyCallState_eagerlyChecksState() =
testScope.runTest {
- // Value starts out empty (null)
- assertThat(underTest.deviceServiceState.value).isNull()
+ // Value starts out false
+ assertThat(underTest.isDeviceEmergencyCallCapable.value).isFalse()
+ whenever(telephonyManager.activeModemCount).thenReturn(1)
+ whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { _ ->
+ ServiceState().apply { isEmergencyOnly = true }
+ }
// WHEN an appropriate intent gets sent out
- val intent = serviceStateIntent(subId = -1, emergencyOnly = false)
+ val intent = serviceStateIntent(subId = -1)
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
intent,
)
runCurrent()
- // THEN the repo's state is updated
- val expected = ServiceStateModel(isEmergencyOnly = false)
- assertThat(underTest.deviceServiceState.value).isEqualTo(expected)
+ // THEN the repo's state is updated despite no listeners
+ assertThat(underTest.isDeviceEmergencyCallCapable.value).isEqualTo(true)
}
@Test
- fun testDeviceServiceStateFromBroadcast_followsSubIdNegativeOne() =
+ fun testDeviceEmergencyCallState_aggregatesAcrossSlots_oneTrue() =
testScope.runTest {
- // device based state tracks -1
- val intent = serviceStateIntent(subId = -1, emergencyOnly = false)
+ val latest by collectLastValue(underTest.isDeviceEmergencyCallCapable)
+
+ // GIVEN there are multiple slots
+ whenever(telephonyManager.activeModemCount).thenReturn(4)
+ // GIVEN only one of them reports ECM
+ whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { invocation ->
+ when (invocation.getArgument(0) as Int) {
+ 0 -> ServiceState().apply { isEmergencyOnly = false }
+ 1 -> ServiceState().apply { isEmergencyOnly = false }
+ 2 -> ServiceState().apply { isEmergencyOnly = true }
+ 3 -> ServiceState().apply { isEmergencyOnly = false }
+ else -> null
+ }
+ }
+
+ // GIVEN a broadcast goes out for the appropriate subID
+ val intent = serviceStateIntent(subId = -1)
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
intent,
)
runCurrent()
- val deviceBasedState = ServiceStateModel(isEmergencyOnly = false)
- assertThat(underTest.deviceServiceState.value).isEqualTo(deviceBasedState)
+ // THEN the device is in ECM, because one of the service states is
+ assertThat(latest).isTrue()
+ }
- // ... and ignores any other subId
- val intent2 = serviceStateIntent(subId = 1, emergencyOnly = true)
+ @Test
+ fun testDeviceEmergencyCallState_aggregatesAcrossSlots_allFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isDeviceEmergencyCallCapable)
+
+ // GIVEN there are multiple slots
+ whenever(telephonyManager.activeModemCount).thenReturn(4)
+ // GIVEN only one of them reports ECM
+ whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { invocation ->
+ when (invocation.getArgument(0) as Int) {
+ 0 -> ServiceState().apply { isEmergencyOnly = false }
+ 1 -> ServiceState().apply { isEmergencyOnly = false }
+ 2 -> ServiceState().apply { isEmergencyOnly = false }
+ 3 -> ServiceState().apply { isEmergencyOnly = false }
+ else -> null
+ }
+ }
+
+ // GIVEN a broadcast goes out for the appropriate subID
+ val intent = serviceStateIntent(subId = -1)
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
context,
- intent2,
+ intent,
)
runCurrent()
- assertThat(underTest.deviceServiceState.value).isEqualTo(deviceBasedState)
+ // THEN the device is in ECM, because one of the service states is
+ assertThat(latest).isFalse()
}
@Test
@@ -1549,15 +1585,8 @@
*/
private fun serviceStateIntent(
subId: Int,
- emergencyOnly: Boolean = false,
): Intent {
- val serviceState = ServiceState().apply { isEmergencyOnly = emergencyOnly }
-
- val bundle = Bundle()
- serviceState.fillInNotifierBundle(bundle)
-
return Intent(Intent.ACTION_SERVICE_STATE).apply {
- putExtras(bundle)
putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index cc0eae7..e218fba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -29,7 +29,6 @@
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
@@ -897,13 +896,11 @@
testScope.runTest {
val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
- connectionsRepository.deviceServiceState.value =
- ServiceStateModel(isEmergencyOnly = true)
+ connectionsRepository.isDeviceEmergencyCallCapable.value = true
assertThat(latest).isTrue()
- connectionsRepository.deviceServiceState.value =
- ServiceStateModel(isEmergencyOnly = false)
+ connectionsRepository.isDeviceEmergencyCallCapable.value = false
assertThat(latest).isFalse()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
index f486787..0945742 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryImplTest.kt
@@ -21,60 +21,61 @@
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.VpnTransportInfo
import android.net.vcn.VcnTransportInfo
import android.net.wifi.WifiInfo
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS
import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.statusbar.pipeline.shared.ConnectivityInputLogger
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
-import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.DEFAULT_HIDDEN_ICONS_RESOURCE
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.HIDDEN_ICONS_TUNABLE_KEY
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo
+import com.android.systemui.testKosmos
import com.android.systemui.tuner.TunerService
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import kotlinx.coroutines.yield
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class ConnectivityRepositoryImplTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
private lateinit var underTest: ConnectivityRepositoryImpl
- @Mock private lateinit var connectivityManager: ConnectivityManager
- @Mock private lateinit var connectivitySlots: ConnectivitySlots
- @Mock private lateinit var dumpManager: DumpManager
- @Mock private lateinit var logger: ConnectivityInputLogger
- private lateinit var testScope: TestScope
- @Mock private lateinit var tunerService: TunerService
+ private val connectivityManager = mock<ConnectivityManager>()
+ private val connectivitySlots = mock<ConnectivitySlots>()
+ private val dumpManager = kosmos.dumpManager
+ private val logger = ConnectivityInputLogger(FakeLogBuffer.Factory.create())
+ private val testScope = kosmos.testScope
+ private val tunerService = mock<TunerService>()
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
- testScope = TestScope(UnconfinedTestDispatcher())
createAndSetRepo()
}
@@ -89,12 +90,10 @@
// config_statusBarIconsToExclude when it's first constructed
createAndSetRepo()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
-
- job.cancel()
}
@Test
@@ -102,14 +101,12 @@
testScope.runTest {
setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
-
- job.cancel()
}
@Test
@@ -117,19 +114,16 @@
testScope.runTest {
setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
// WHEN onTuningChanged with the wrong key
getTunable().onTuningChanged("wrongKey", SLOT_WIFI)
- yield()
// THEN we didn't update our value and still have the old one
assertThat(latest).containsExactly(ConnectivitySlot.MOBILE)
-
- job.cancel()
}
@Test
@@ -143,8 +137,8 @@
// config_statusBarIconsToExclude when it's first constructed
createAndSetRepo()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
// First, update the slots
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, SLOT_MOBILE)
@@ -152,19 +146,16 @@
// WHEN we update to a null value
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, null)
- yield()
// THEN we go back to our default value
assertThat(latest).containsExactly(ConnectivitySlot.ETHERNET, ConnectivitySlot.WIFI)
-
- job.cancel()
}
@Test
fun forceHiddenSlots_someInvalidSlotNames_flowHasValidSlotsOnly() =
testScope.runTest {
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(ConnectivitySlot.WIFI)
whenever(connectivitySlots.getSlotFromName(SLOT_MOBILE)).thenReturn(null)
@@ -172,8 +163,6 @@
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_MOBILE")
assertThat(latest).containsExactly(ConnectivitySlot.WIFI)
-
- job.cancel()
}
@Test
@@ -181,23 +170,21 @@
testScope.runTest {
setUpEthernetWifiMobileSlotNames()
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
// WHEN there's empty and blank slot names
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_MOBILE, ,,$SLOT_WIFI")
// THEN we skip that slot but still process the other ones
assertThat(latest).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.MOBILE)
-
- job.cancel()
}
@Test
fun forceHiddenSlots_allInvalidOrEmptySlotNames_flowHasEmpty() =
testScope.runTest {
- var latest: Set<ConnectivitySlot>? = null
- val job = underTest.forceHiddenSlots.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
whenever(connectivitySlots.getSlotFromName(SLOT_WIFI)).thenReturn(null)
whenever(connectivitySlots.getSlotFromName(SLOT_ETHERNET)).thenReturn(null)
@@ -210,8 +197,6 @@
)
assertThat(latest).isEmpty()
-
- job.cancel()
}
@Test
@@ -219,29 +204,25 @@
testScope.runTest {
setUpEthernetWifiMobileSlotNames()
- var latest1: Set<ConnectivitySlot>? = null
- val job1 = underTest.forceHiddenSlots.onEach { latest1 = it }.launchIn(this)
+ val latest1 by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
getTunable().onTuningChanged(HIDDEN_ICONS_TUNABLE_KEY, "$SLOT_WIFI,$SLOT_ETHERNET")
assertThat(latest1).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
// WHEN we add a second subscriber after having already emitted a value
- var latest2: Set<ConnectivitySlot>? = null
- val job2 = underTest.forceHiddenSlots.onEach { latest2 = it }.launchIn(this)
+ val latest2 by collectLastValue(underTest.forceHiddenSlots)
+ runCurrent()
// THEN the second subscribe receives the already-emitted value
assertThat(latest2).containsExactly(ConnectivitySlot.WIFI, ConnectivitySlot.ETHERNET)
-
- job1.cancel()
- job2.cancel()
}
@Test
fun defaultConnections_noTransports_nothingIsDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -256,15 +237,12 @@
assertThat(latest!!.wifi.isDefault).isFalse()
assertThat(latest!!.ethernet.isDefault).isFalse()
assertThat(latest!!.carrierMerged.isDefault).isFalse()
-
- job.cancel()
}
@Test
fun defaultConnections_cellularTransport_mobileIsDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -279,15 +257,12 @@
assertThat(latest!!.wifi.isDefault).isFalse()
assertThat(latest!!.ethernet.isDefault).isFalse()
assertThat(latest!!.carrierMerged.isDefault).isFalse()
-
- job.cancel()
}
@Test
fun defaultConnections_wifiTransport_wifiIsDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -302,15 +277,12 @@
assertThat(latest!!.ethernet.isDefault).isFalse()
assertThat(latest!!.carrierMerged.isDefault).isFalse()
assertThat(latest!!.mobile.isDefault).isFalse()
-
- job.cancel()
}
@Test
fun defaultConnections_ethernetTransport_ethernetIsDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -325,15 +297,12 @@
assertThat(latest!!.wifi.isDefault).isFalse()
assertThat(latest!!.carrierMerged.isDefault).isFalse()
assertThat(latest!!.mobile.isDefault).isFalse()
-
- job.cancel()
}
@Test
fun defaultConnections_carrierMergedViaWifi_wifiAndCarrierMergedDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
@@ -350,15 +319,12 @@
assertThat(latest!!.wifi.isDefault).isTrue()
assertThat(latest!!.carrierMerged.isDefault).isTrue()
assertThat(latest!!.mobile.isDefault).isFalse()
-
- job.cancel()
}
@Test
fun defaultConnections_carrierMergedViaMobile_mobileCarrierMergedWifiDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
@@ -375,15 +341,12 @@
assertThat(latest!!.mobile.isDefault).isTrue()
assertThat(latest!!.carrierMerged.isDefault).isTrue()
assertThat(latest!!.wifi.isDefault).isTrue()
-
- job.cancel()
}
@Test
fun defaultConnections_carrierMergedViaWifiWithVcnTransport_wifiAndCarrierMergedDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
@@ -400,15 +363,13 @@
assertThat(latest!!.wifi.isDefault).isTrue()
assertThat(latest!!.carrierMerged.isDefault).isTrue()
assertThat(latest!!.mobile.isDefault).isFalse()
-
- job.cancel()
}
+ /** VCN over W+ (aka VCN over carrier merged). See b/352162710#comment27 scenario #1. */
@Test
fun defaultConnections_carrierMergedViaMobileWithVcnTransport_mobileCarrierMergedWifiDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
@@ -425,15 +386,48 @@
assertThat(latest!!.mobile.isDefault).isTrue()
assertThat(latest!!.carrierMerged.isDefault).isTrue()
assertThat(latest!!.wifi.isDefault).isTrue()
+ }
- job.cancel()
+ /** VPN over W+ (aka VPN over carrier merged). See b/352162710#comment27 scenario #2. */
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS)
+ fun defaultConnections_vpnOverCarrierMerged_carrierMergedDefault() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.defaultConnections)
+
+ // Underlying carrier merged network
+ val underlyingCarrierMergedNetwork = mock<Network>()
+ val carrierMergedInfo =
+ mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+ val underlyingCapabilities =
+ mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(it.transportInfo).thenReturn(carrierMergedInfo)
+ }
+ whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork))
+ .thenReturn(underlyingCapabilities)
+
+ val mainCapabilities =
+ mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(false)
+ // Transports are WIFI|VPN, *not* CELLULAR.
+ whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+ whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
+ whenever(it.transportInfo).thenReturn(VpnTransportInfo(0, null, false, false))
+ whenever(it.underlyingNetworks)
+ .thenReturn(listOf(underlyingCarrierMergedNetwork))
+ }
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
+
+ assertThat(latest!!.carrierMerged.isDefault).isTrue()
}
@Test
fun defaultConnections_notCarrierMergedViaWifi_carrierMergedNotDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(false) }
@@ -448,15 +442,12 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest!!.carrierMerged.isDefault).isFalse()
-
- job.cancel()
}
@Test
fun defaultConnections_notCarrierMergedViaMobile_carrierMergedNotDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val carrierMergedInfo =
mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(false) }
@@ -471,15 +462,12 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest!!.carrierMerged.isDefault).isFalse()
-
- job.cancel()
}
@Test
fun defaultConnections_transportInfoNotWifi_wifiNotDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -492,8 +480,6 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest!!.wifi.isDefault).isFalse()
-
- job.cancel()
}
@Test
@@ -531,8 +517,7 @@
@Test
fun defaultConnections_cellular_underlyingCarrierMergedViaWifi_allDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
// Underlying carrier merged network
val underlyingCarrierMergedNetwork = mock<Network>()
@@ -560,16 +545,17 @@
assertThat(latest!!.mobile.isDefault).isTrue()
assertThat(latest!!.carrierMerged.isDefault).isTrue()
assertThat(latest!!.wifi.isDefault).isTrue()
-
- job.cancel()
}
- /** Test for b/225902574. */
+ /**
+ * Test for b/225902574: VPN over VCN over W+ (aka VPN over VCN over carrier merged).
+ *
+ * Also see b/352162710#comment27 scenario #3 and b/352162710#comment30.
+ */
@Test
fun defaultConnections_cellular_underlyingCarrierMergedViaMobileWithVcnTransport_allDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
// Underlying carrier merged network
val underlyingCarrierMergedNetwork = mock<Network>()
@@ -587,6 +573,7 @@
val mainCapabilities =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
whenever(it.transportInfo).thenReturn(null)
whenever(it.underlyingNetworks)
.thenReturn(listOf(underlyingCarrierMergedNetwork))
@@ -597,15 +584,12 @@
assertThat(latest!!.mobile.isDefault).isTrue()
assertThat(latest!!.carrierMerged.isDefault).isTrue()
assertThat(latest!!.wifi.isDefault).isTrue()
-
- job.cancel()
}
@Test
fun defaultConnections_multipleTransports_multipleDefault() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -619,15 +603,12 @@
assertThat(latest!!.mobile.isDefault).isTrue()
assertThat(latest!!.ethernet.isDefault).isTrue()
assertThat(latest!!.wifi.isDefault).isTrue()
-
- job.cancel()
}
@Test
fun defaultConnections_hasValidated_isValidatedTrue() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -638,14 +619,12 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest!!.isValidated).isTrue()
- job.cancel()
}
@Test
fun defaultConnections_noValidated_isValidatedFalse() =
testScope.runTest {
- var latest: DefaultConnectionModel? = null
- val job = underTest.defaultConnections.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.defaultConnections)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -656,7 +635,6 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest!!.isValidated).isFalse()
- job.cancel()
}
@Test
@@ -669,8 +647,7 @@
testScope.runTest {
val vcnInfo = VcnTransportInfo(SUB_1_ID)
- var latest: Int? = null
- val job = underTest.vcnSubId.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.vcnSubId)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -681,7 +658,6 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest).isEqualTo(SUB_1_ID)
- job.cancel()
}
@Test
@@ -689,8 +665,7 @@
testScope.runTest {
val vcnInfo = VcnTransportInfo(INVALID_SUBSCRIPTION_ID)
- var latest: Int? = null
- val job = underTest.vcnSubId.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.vcnSubId)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -701,14 +676,12 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest).isNull()
- job.cancel()
}
@Test
fun vcnSubId_nullIfNoTransportInfo() =
testScope.runTest {
- var latest: Int? = null
- val job = underTest.vcnSubId.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.vcnSubId)
val capabilities =
mock<NetworkCapabilities>().also {
@@ -719,7 +692,6 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest).isNull()
- job.cancel()
}
@Test
@@ -728,8 +700,7 @@
// If the underlying network of the VCN is a WiFi network, then there is no subId that
// could disagree with telephony's active data subscription id.
- var latest: Int? = null
- val job = underTest.vcnSubId.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.vcnSubId)
val wifiInfo = mock<WifiInfo>()
val vcnInfo = VcnTransportInfo(wifiInfo)
@@ -742,14 +713,12 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest).isNull()
- job.cancel()
}
@Test
fun vcnSubId_changingVcnInfoIsTracked() =
testScope.runTest {
- var latest: Int? = null
- val job = underTest.vcnSubId.onEach { latest = it }.launchIn(this)
+ val latest by collectLastValue(underTest.vcnSubId)
val wifiInfo = mock<WifiInfo>()
val wifiVcnInfo = VcnTransportInfo(wifiInfo)
@@ -788,8 +757,6 @@
getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
assertThat(latest).isNull()
-
- job.cancel()
}
@Test
@@ -862,6 +829,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS)
fun getMainOrUnderlyingWifiInfo_notCellular_underlyingWifi_noInfo() {
val underlyingNetwork = mock<Network>()
val underlyingWifiInfo = mock<WifiInfo>()
@@ -916,6 +884,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_ALWAYS_CHECK_UNDERLYING_NETWORKS)
fun getMainOrUnderlyingWifiInfo_notCellular_underlyingVcnWithWifi_noInfo() {
val underlyingNetwork = mock<Network>()
val underlyingVcnInfo = VcnTransportInfo(mock<WifiInfo>())
@@ -1076,12 +1045,13 @@
testScope.backgroundScope,
tunerService,
)
+ testScope.runCurrent()
}
private fun getTunable(): TunerService.Tunable {
val callbackCaptor = argumentCaptor<TunerService.Tunable>()
verify(tunerService).addTunable(callbackCaptor.capture(), any())
- return callbackCaptor.value!!
+ return callbackCaptor.firstValue
}
private fun setUpEthernetWifiMobileSlotNames() {
@@ -1094,7 +1064,7 @@
private fun getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
- return callbackCaptor.value!!
+ return callbackCaptor.firstValue
}
private companion object {
diff --git a/packages/SystemUI/tests/utils/src/com/android/settingslib/notification/modes/ZenIconLoaderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/settingslib/notification/modes/ZenIconLoaderKosmos.kt
new file mode 100644
index 0000000..8541d77
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/settingslib/notification/modes/ZenIconLoaderKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 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.settingslib.notification.modes
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.google.common.util.concurrent.MoreExecutors
+
+val Kosmos.zenIconLoader by Fixture { ZenIconLoader(MoreExecutors.newDirectExecutorService()) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
index e96aeada..5753c6c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
@@ -27,7 +27,6 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
@SysUISingleton
@@ -37,38 +36,41 @@
private val _authenticationStatus = MutableStateFlow<FaceAuthenticationStatus?>(null)
override val authenticationStatus: Flow<FaceAuthenticationStatus> =
_authenticationStatus.filterNotNull()
+
fun setAuthenticationStatus(status: FaceAuthenticationStatus) {
_authenticationStatus.value = status
}
+
private val _detectionStatus = MutableStateFlow<FaceDetectionStatus?>(null)
override val detectionStatus: Flow<FaceDetectionStatus>
get() = _detectionStatus.filterNotNull()
+
fun setDetectionStatus(status: FaceDetectionStatus) {
_detectionStatus.value = status
}
private val _isLockedOut = MutableStateFlow(false)
override val isLockedOut = _isLockedOut
- private val _runningAuthRequest = MutableStateFlow<Pair<FaceAuthUiEvent, Boolean>?>(null)
- val runningAuthRequest: StateFlow<Pair<FaceAuthUiEvent, Boolean>?> =
- _runningAuthRequest.asStateFlow()
+ val runningAuthRequest: MutableStateFlow<Pair<FaceAuthUiEvent, Boolean>?> =
+ MutableStateFlow(null)
private val _isAuthRunning = MutableStateFlow(false)
override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning
override val isBypassEnabled = MutableStateFlow(false)
+
override fun setLockedOut(isLockedOut: Boolean) {
_isLockedOut.value = isLockedOut
}
override fun requestAuthenticate(uiEvent: FaceAuthUiEvent, fallbackToDetection: Boolean) {
- _runningAuthRequest.value = uiEvent to fallbackToDetection
+ runningAuthRequest.value = uiEvent to fallbackToDetection
_isAuthRunning.value = true
}
override fun cancel() {
_isAuthRunning.value = false
- _runningAuthRequest.value = null
+ runningAuthRequest.value = null
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DismissKeyguardInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DismissKeyguardInteractor.kt
new file mode 100644
index 0000000..82a5311
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DismissKeyguardInteractor.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.keyguard.domain.interactor
+
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor by
+ Kosmos.Fixture {
+ KeyguardDismissTransitionInteractor(
+ repository = keyguardTransitionRepository,
+ fromLockscreenTransitionInteractor = fromLockscreenTransitionInteractor,
+ fromPrimaryBouncerTransitionInteractor = fromPrimaryBouncerTransitionInteractor,
+ fromAodTransitionInteractor = fromAodTransitionInteractor,
+ fromAlternateBouncerTransitionInteractor = fromAlternateBouncerTransitionInteractor,
+ fromDozingTransitionInteractor = fromDozingTransitionInteractor,
+ fromOccludedTransitionInteractor = fromOccludedTransitionInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt
index c6b5ed0..007d229 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractorKosmos.kt
@@ -27,7 +27,7 @@
applicationCoroutineScope,
keyguardRepository,
biometricSettingsRepository,
- keyguardTransitionInteractor,
+ keyguardDismissTransitionInteractor,
internalTransitionInteractor = internalKeyguardTransitionInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
index 8e8f4b6..aa94c36 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.domain.interactor
-import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -27,12 +26,6 @@
KeyguardTransitionInteractor(
scope = applicationCoroutineScope,
repository = keyguardTransitionRepository,
- fromLockscreenTransitionInteractor = { fromLockscreenTransitionInteractor },
- fromPrimaryBouncerTransitionInteractor = { fromPrimaryBouncerTransitionInteractor },
- fromAodTransitionInteractor = { fromAodTransitionInteractor },
- fromAlternateBouncerTransitionInteractor = { fromAlternateBouncerTransitionInteractor },
- fromDozingTransitionInteractor = { fromDozingTransitionInteractor },
- fromOccludedTransitionInteractor = { fromOccludedTransitionInteractor },
sceneInteractor = sceneInteractor
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt
index a05e606..4196e54 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt
@@ -18,6 +18,7 @@
package com.android.systemui.keyguard.ui.viewmodel
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
@@ -25,6 +26,7 @@
val Kosmos.occludedToDozingTransitionViewModel by Fixture {
OccludedToDozingTransitionViewModel(
+ deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
animationFlow = keyguardTransitionAnimationFlow,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
index 7dfe802..7bc2483 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
@@ -1,9 +1,9 @@
package com.android.systemui.scene
-import com.android.compose.animation.scene.OverlayKey
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.scene.shared.model.FakeScene
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.FakeOverlay
@@ -26,8 +26,8 @@
val Kosmos.initialSceneKey by Fixture { Scenes.Lockscreen }
var Kosmos.overlayKeys by Fixture {
- listOf<OverlayKey>(
- // TODO(b/356596436): Add overlays here when we have them.
+ listOf(
+ Overlays.NotificationsShade,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayActionsViewModelKosmos.kt
new file mode 100644
index 0000000..24481bf
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayActionsViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.shade.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+
+val Kosmos.notificationsShadeOverlayActionsViewModel:
+ NotificationsShadeOverlayActionsViewModel by Fixture {
+ NotificationsShadeOverlayActionsViewModel(
+ shadeInteractor = shadeInteractor,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 8229575..e7be639 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -23,7 +23,6 @@
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.log.table.TableLogBuffer
-import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
@@ -94,9 +93,10 @@
private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON)
override val defaultMobileIconGroup = _defaultMobileIconGroup
- override val deviceServiceState = MutableStateFlow<ServiceStateModel?>(null)
+ override val isDeviceEmergencyCallCapable = MutableStateFlow(false)
override val isAnySimSecure = MutableStateFlow(false)
+
override fun getIsAnySimSecure(): Boolean = isAnySimSecure.value
private var isInEcmMode: Boolean = false
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
index 66be7e7..61b53c9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractorKosmos.kt
@@ -17,8 +17,10 @@
package com.android.systemui.statusbar.policy.domain.interactor
import android.content.testableContext
+import com.android.settingslib.notification.modes.zenIconLoader
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.shared.notifications.data.repository.notificationSettingsRepository
import com.android.systemui.statusbar.policy.data.repository.zenModeRepository
@@ -27,5 +29,7 @@
context = testableContext,
zenModeRepository = zenModeRepository,
notificationSettingsRepository = notificationSettingsRepository,
+ bgDispatcher = testDispatcher,
+ iconLoader = zenIconLoader,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index 2dbac67..0089199 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -64,7 +64,8 @@
@Override
public void setResourceIcon(String slot, @Nullable String resPackage, int iconResId,
- @Nullable Drawable preloadedIcon, CharSequence contentDescription) {
+ @Nullable Drawable preloadedIcon, CharSequence contentDescription,
+ StatusBarIcon.Shape shape) {
}
@Override
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
index 83adc79..ad1292e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
@@ -38,6 +38,7 @@
): MediaDevice = mock {
whenever(name).thenReturn(deviceName)
whenever(icon).thenReturn(deviceIcon)
+ whenever(deviceType).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE)
}
fun wiredMediaDevice(
@@ -77,6 +78,18 @@
whenever(name).thenReturn(deviceName)
whenever(icon).thenReturn(deviceIcon)
whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
+ whenever(deviceType).thenReturn(MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE)
+ }
+ }
+
+ fun remoteMediaDevice(
+ deviceName: String = "remote_media",
+ deviceIcon: Drawable? = TestStubDrawable(),
+ ): MediaDevice {
+ return mock<MediaDevice> {
+ whenever(name).thenReturn(deviceName)
+ whenever(icon).thenReturn(deviceIcon)
+ whenever(deviceType).thenReturn(MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE)
}
}
}
diff --git a/ravenwood/.gitignore b/ravenwood/.gitignore
new file mode 100644
index 0000000..751553b
--- /dev/null
+++ b/ravenwood/.gitignore
@@ -0,0 +1 @@
+*.bak
diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING
index 7e2ee3e..469759b 100644
--- a/ravenwood/TEST_MAPPING
+++ b/ravenwood/TEST_MAPPING
@@ -1,17 +1,12 @@
-// Keep the following two TEST_MAPPINGs in sync:
-// frameworks/base/ravenwood/TEST_MAPPING
-// frameworks/base/tools/hoststubgen/TEST_MAPPING
{
"presubmit": [
{ "name": "tiny-framework-dump-test" },
{ "name": "hoststubgentest" },
+ { "name": "hoststubgen-test-tiny-test" },
{ "name": "hoststubgen-invoke-test" },
- {
- "name": "RavenwoodMockitoTest_device"
- },
- {
- "name": "RavenwoodBivalentTest_device"
- },
+ { "name": "RavenwoodMockitoTest_device" },
+ { "name": "RavenwoodBivalentTest_device" },
+
// The sysui tests should match vendor/unbundled_google/packages/SystemUIGoogle/TEST_MAPPING
{
"name": "SystemUIGoogleTests",
@@ -39,6 +34,113 @@
}
],
"ravenwood-presubmit": [
+ // AUTO-GENERATED-START
+ // DO NOT MODIFY MANUALLY
+ // Use scripts/update-test-mapping.sh to update it.
+ {
+ "name": "AdServicesSharedLibrariesUnitTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "android.test.mock.ravenwood.tests",
+ "host": true
+ },
+ {
+ "name": "CarLibHostUnitTest",
+ "host": true
+ },
+ {
+ "name": "CarServiceHostUnitTest",
+ "host": true
+ },
+ {
+ "name": "CarSystemUIRavenTests",
+ "host": true
+ },
+ {
+ "name": "CtsAccountManagerTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsAppTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsContentTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsDatabaseTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsGraphicsTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsIcuTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsInputMethodTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsOsTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsProtoTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsResourcesTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsTextTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "CtsUtilTestCasesRavenwood",
+ "host": true
+ },
+ {
+ "name": "FrameworksCoreSystemPropertiesTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "FrameworksCoreTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "FrameworksInputMethodSystemServerTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "FrameworksMockingServicesTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "FrameworksServicesTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "FrameworksUtilTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "InternalTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "PowerStatsTestsRavenwood",
+ "host": true
+ },
+ {
+ "name": "RavenwoodBivalentTest",
+ "host": true
+ },
{
"name": "RavenwoodMinimumTest",
"host": true
@@ -48,16 +150,21 @@
"host": true
},
{
- "name": "CtsUtilTestCasesRavenwood",
- "host": true
- },
- {
"name": "RavenwoodResApkTest",
"host": true
},
{
- "name": "RavenwoodBivalentTest",
+ "name": "RavenwoodRuntimeTest",
+ "host": true
+ },
+ {
+ "name": "RavenwoodServicesTest",
+ "host": true
+ },
+ {
+ "name": "SystemUiRavenTests",
"host": true
}
+ // AUTO-GENERATED-END
]
}
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/CallTracker.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/CallTracker.java
index 8dadd39..09a0aa8 100644
--- a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/CallTracker.java
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/CallTracker.java
@@ -64,7 +64,7 @@
/**
* Check the number of calls stored in {@link #mNumCalled}.
*/
- protected void assertCalls(Object... methodNameAndCountPairs) {
+ public void assertCalls(Object... methodNameAndCountPairs) {
// Create a local copy
HashMap<String, Integer> counts = new HashMap<>(mNumCalled);
for (int i = 0; i < methodNameAndCountPairs.length - 1; i += 2) {
@@ -95,7 +95,7 @@
* Same as {@link #assertCalls(Object...)} but it kills the process if it fails.
* Only use in @AfterClass.
*/
- protected void assertCallsOrDie(Object... methodNameAndCountPairs) {
+ public void assertCallsOrDie(Object... methodNameAndCountPairs) {
try {
assertCalls(methodNameAndCountPairs);
} catch (Throwable th) {
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodNoRavenizerTest.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodNoRavenizerTest.java
new file mode 100644
index 0000000..9d878f4
--- /dev/null
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodNoRavenizerTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 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.ravenwoodtest.bivalenttest.ravenizer;
+
+import android.platform.test.annotations.NoRavenizer;
+import android.platform.test.ravenwood.RavenwoodAwareTestRunner.RavenwoodTestRunnerInitializing;
+
+import org.junit.Test;
+
+/**
+ * Test for {@link android.platform.test.annotations.NoRavenizer}
+ */
+@NoRavenizer
+public class RavenwoodNoRavenizerTest {
+ public static final String TAG = "RavenwoodNoRavenizerTest";
+
+ private static final CallTracker sCallTracker = new CallTracker();
+
+ /**
+ * With @NoRavenizer, this method shouldn't be called.
+ */
+ @RavenwoodTestRunnerInitializing
+ public static void ravenwoodRunnerInitializing() {
+ sCallTracker.incrementMethodCallCount();
+ }
+
+ /**
+ * Make sure ravenwoodRunnerInitializing() wasn't called.
+ */
+ @Test
+ public void testNotRavenized() {
+ sCallTracker.assertCalls(
+ "ravenwoodRunnerInitializing", 0
+ );
+ }
+}
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodSuiteTest.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodSuiteTest.java
new file mode 100644
index 0000000..7e396c2
--- /dev/null
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/ravenizer/RavenwoodSuiteTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 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.ravenwoodtest.bivalenttest.ravenizer;
+
+import android.util.Log;
+
+import org.junit.AfterClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Test to make sure {@link Suite} works with the ravenwood test runner.
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ RavenwoodSuiteTest.Test1.class,
+ RavenwoodSuiteTest.Test2.class
+})
+public class RavenwoodSuiteTest {
+ public static final String TAG = "RavenwoodSuiteTest";
+
+ private static final CallTracker sCallTracker = new CallTracker();
+
+ @AfterClass
+ public static void afterClass() {
+ Log.i(TAG, "afterClass called");
+
+ sCallTracker.assertCallsOrDie(
+ "test1", 1,
+ "test2", 1
+ );
+ }
+
+ /**
+ * Workaround for the issue where tradefed won't think a class is a test class
+ * if it has a @RunWith but no @Test methods, even if it is a Suite.
+ */
+ @Test
+ public void testEmpty() {
+ }
+
+ public static class Test1 {
+ @Test
+ public void test1() {
+ sCallTracker.incrementMethodCallCount();
+ }
+ }
+
+ public static class Test2 {
+ @Test
+ public void test2() {
+ sCallTracker.incrementMethodCallCount();
+ }
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
index 1da93eb..f237ba9 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
@@ -57,7 +57,8 @@
*/
public static void onRunnerInitializing(Runner runner, TestClass testClass) {
// This log call also ensures the framework JNI is loaded.
- Log.i(TAG, "onRunnerInitializing: testClass=" + testClass + " runner=" + runner);
+ Log.i(TAG, "onRunnerInitializing: testClass=" + testClass.getJavaClass()
+ + " runner=" + runner);
// TODO: Move the initialization code to a better place.
diff --git a/ravenwood/junit-src/android/platform/test/annotations/NoRavenizer.java b/ravenwood/junit-src/android/platform/test/annotations/NoRavenizer.java
new file mode 100644
index 0000000..a84f16f
--- /dev/null
+++ b/ravenwood/junit-src/android/platform/test/annotations/NoRavenizer.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.platform.test.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Disable the ravenizer preprocessor for a class. This should be only used for testing
+ * ravenizer itself, or to workaround issues with the preprocessor. A test class probably won't run
+ * properly if it's not preprocessed.
+ *
+ * @hide
+ */
+@Inherited
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NoRavenizer {
+}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 2b55ac5..7d99166 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -21,10 +21,13 @@
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
+import android.util.Log;
+
import com.android.ravenwood.common.RavenwoodCommonUtils;
import com.android.ravenwood.common.SneakyThrow;
import org.junit.Assume;
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runner.Runner;
@@ -36,8 +39,10 @@
import org.junit.runner.manipulation.Orderer;
import org.junit.runner.manipulation.Sortable;
import org.junit.runner.manipulation.Sorter;
+import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.RunnerBuilder;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
@@ -51,8 +56,6 @@
/**
* A test runner used for Ravenwood.
*
- * TODO: Handle ENABLE_PROBE_IGNORED
- *
* It will delegate to another runner specified with {@link InnerRunner}
* (default = {@link BlockJUnit4ClassRunner}) with the following features.
* - Add a {@link RavenwoodAwareTestRunnerHook#onRunnerInitializing} hook, which is called before
@@ -134,12 +137,15 @@
return runner;
}
- private final TestClass mTestClsas;
- private final Runner mRealRunner;
+ private TestClass mTestClass = null;
+ private Runner mRealRunner = null;
+ private Description mDescription = null;
+ private Throwable mExceptionInConstructor = null;
/** Simple logging method. */
private void log(String message) {
- RavenwoodCommonUtils.log(TAG, "[" + getTestClass() + " @" + this + "] " + message);
+ RavenwoodCommonUtils.log(TAG, "[" + getTestClass().getJavaClass() + " @" + this + "] "
+ + message);
}
private Error logAndFail(String message, Throwable innerException) {
@@ -149,45 +155,76 @@
}
public TestClass getTestClass() {
- return mTestClsas;
+ return mTestClass;
}
/**
* Constructor.
*/
public RavenwoodAwareTestRunner(Class<?> testClass) {
- mTestClsas = new TestClass(testClass);
-
- /*
- * If the class has @DisabledOnRavenwood, then we'll delegate to ClassSkippingTestRunner,
- * which simply skips it.
- */
- if (isOnRavenwood() && !RavenwoodAwareTestRunnerHook.shouldRunClassOnRavenwood(
- mTestClsas.getJavaClass())) {
- mRealRunner = new ClassSkippingTestRunner(mTestClsas);
- return;
- }
-
- // Find the real runner.
- final Class<? extends Runner> realRunner;
- final InnerRunner innerRunnerAnnotation = mTestClsas.getAnnotation(InnerRunner.class);
- if (innerRunnerAnnotation != null) {
- realRunner = innerRunnerAnnotation.value();
- } else {
- // Default runner.
- realRunner = BlockJUnit4ClassRunner.class;
- }
-
- onRunnerInitializing();
-
try {
- log("Initializing the inner runner: " + realRunner);
+ mTestClass = new TestClass(testClass);
- mRealRunner = realRunner.getConstructor(Class.class).newInstance(testClass);
+ /*
+ * If the class has @DisabledOnRavenwood, then we'll delegate to
+ * ClassSkippingTestRunner, which simply skips it.
+ */
+ if (isOnRavenwood() && !RavenwoodAwareTestRunnerHook.shouldRunClassOnRavenwood(
+ mTestClass.getJavaClass())) {
+ mRealRunner = new ClassSkippingTestRunner(mTestClass);
+ mDescription = mRealRunner.getDescription();
+ return;
+ }
- } catch (InstantiationException | IllegalAccessException
- | InvocationTargetException | NoSuchMethodException e) {
- throw logAndFail("Failed to instantiate " + realRunner, e);
+ // Find the real runner.
+ final Class<? extends Runner> realRunnerClass;
+ final InnerRunner innerRunnerAnnotation = mTestClass.getAnnotation(InnerRunner.class);
+ if (innerRunnerAnnotation != null) {
+ realRunnerClass = innerRunnerAnnotation.value();
+ } else {
+ // Default runner.
+ realRunnerClass = BlockJUnit4ClassRunner.class;
+ }
+
+ onRunnerInitializing();
+
+ try {
+ log("Initializing the inner runner: " + realRunnerClass);
+
+ mRealRunner = instantiateRealRunner(realRunnerClass, testClass);
+ mDescription = mRealRunner.getDescription();
+
+ } catch (InstantiationException | IllegalAccessException
+ | InvocationTargetException | NoSuchMethodException e) {
+ throw logAndFail("Failed to instantiate " + realRunnerClass, e);
+ }
+ } catch (Throwable th) {
+ // If we throw in the constructor, Tradefed may not report it and just ignore the class,
+ // so record it and throw it when the test actually started.
+ log("Fatal: Exception detected in constructor: " + th.getMessage() + "\n"
+ + Log.getStackTraceString(th));
+ mExceptionInConstructor = new RuntimeException("Exception detected in constructor",
+ th);
+ mDescription = Description.createTestDescription(testClass, "Constructor");
+
+ // This is for testing if tradefed is fixed.
+ if ("1".equals(System.getenv("RAVENWOOD_THROW_EXCEPTION_IN_TEST_RUNNER"))) {
+ throw th;
+ }
+ }
+ }
+
+ private static Runner instantiateRealRunner(
+ Class<? extends Runner> realRunnerClass,
+ Class<?> testClass)
+ throws NoSuchMethodException, InvocationTargetException, InstantiationException,
+ IllegalAccessException {
+ try {
+ return realRunnerClass.getConstructor(Class.class).newInstance(testClass);
+ } catch (NoSuchMethodException e) {
+ var runnerBuilder = new AllDefaultPossibilitiesBuilder();
+ return realRunnerClass.getConstructor(Class.class,
+ RunnerBuilder.class).newInstance(testClass, runnerBuilder);
}
}
@@ -202,7 +239,7 @@
log("onRunnerInitializing");
- RavenwoodAwareTestRunnerHook.onRunnerInitializing(this, mTestClsas);
+ RavenwoodAwareTestRunnerHook.onRunnerInitializing(this, mTestClass);
// Hook point to allow more customization.
runAnnotatedMethodsOnRavenwood(RavenwoodTestRunnerInitializing.class, null);
@@ -230,7 +267,7 @@
@Override
public Description getDescription() {
- return mRealRunner.getDescription();
+ return mDescription;
}
@Override
@@ -241,6 +278,10 @@
return;
}
+ if (maybeReportExceptionFromConstructor(notifier)) {
+ return;
+ }
+
sCurrentRunner.set(this);
try {
runWithHooks(getDescription(), Scope.Runner, Order.First,
@@ -250,6 +291,18 @@
}
}
+ /** Throw the exception detected in the constructor, if any. */
+ private boolean maybeReportExceptionFromConstructor(RunNotifier notifier) {
+ if (mExceptionInConstructor == null) {
+ return false;
+ }
+ notifier.fireTestStarted(mDescription);
+ notifier.fireTestFailure(new Failure(mDescription, mExceptionInConstructor));
+ notifier.fireTestFinished(mDescription);
+
+ return true;
+ }
+
@Override
public void filter(Filter filter) throws NoTestsRemainException {
if (mRealRunner instanceof Filterable r) {
diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/FP16.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/FP16.java
new file mode 100644
index 0000000..478503b
--- /dev/null
+++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/FP16.java
@@ -0,0 +1,814 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.util;
+
+/**
+ * <p>The {@code FP16} class is a wrapper and a utility class to manipulate half-precision 16-bit
+ * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
+ * floating point data types (also called fp16 or binary16). A half-precision float can be
+ * created from or converted to single-precision floats, and is stored in a short data type.
+ *
+ * <p>The IEEE 754 standard specifies an fp16 as having the following format:</p>
+ * <ul>
+ * <li>Sign bit: 1 bit</li>
+ * <li>Exponent width: 5 bits</li>
+ * <li>Significand: 10 bits</li>
+ * </ul>
+ *
+ * <p>The format is laid out as follows:</p>
+ * <pre>
+ * 1 11111 1111111111
+ * ^ --^-- -----^----
+ * sign | |_______ significand
+ * |
+ * -- exponent
+ * </pre>
+ *
+ * <p>Half-precision floating points can be useful to save memory and/or
+ * bandwidth at the expense of range and precision when compared to single-precision
+ * floating points (fp32).</p>
+ * <p>To help you decide whether fp16 is the right storage type for you need, please
+ * refer to the table below that shows the available precision throughout the range of
+ * possible values. The <em>precision</em> column indicates the step size between two
+ * consecutive numbers in a specific part of the range.</p>
+ *
+ * <table summary="Precision of fp16 across the range">
+ * <tr><th>Range start</th><th>Precision</th></tr>
+ * <tr><td>0</td><td>1 ⁄ 16,777,216</td></tr>
+ * <tr><td>1 ⁄ 16,384</td><td>1 ⁄ 16,777,216</td></tr>
+ * <tr><td>1 ⁄ 8,192</td><td>1 ⁄ 8,388,608</td></tr>
+ * <tr><td>1 ⁄ 4,096</td><td>1 ⁄ 4,194,304</td></tr>
+ * <tr><td>1 ⁄ 2,048</td><td>1 ⁄ 2,097,152</td></tr>
+ * <tr><td>1 ⁄ 1,024</td><td>1 ⁄ 1,048,576</td></tr>
+ * <tr><td>1 ⁄ 512</td><td>1 ⁄ 524,288</td></tr>
+ * <tr><td>1 ⁄ 256</td><td>1 ⁄ 262,144</td></tr>
+ * <tr><td>1 ⁄ 128</td><td>1 ⁄ 131,072</td></tr>
+ * <tr><td>1 ⁄ 64</td><td>1 ⁄ 65,536</td></tr>
+ * <tr><td>1 ⁄ 32</td><td>1 ⁄ 32,768</td></tr>
+ * <tr><td>1 ⁄ 16</td><td>1 ⁄ 16,384</td></tr>
+ * <tr><td>1 ⁄ 8</td><td>1 ⁄ 8,192</td></tr>
+ * <tr><td>1 ⁄ 4</td><td>1 ⁄ 4,096</td></tr>
+ * <tr><td>1 ⁄ 2</td><td>1 ⁄ 2,048</td></tr>
+ * <tr><td>1</td><td>1 ⁄ 1,024</td></tr>
+ * <tr><td>2</td><td>1 ⁄ 512</td></tr>
+ * <tr><td>4</td><td>1 ⁄ 256</td></tr>
+ * <tr><td>8</td><td>1 ⁄ 128</td></tr>
+ * <tr><td>16</td><td>1 ⁄ 64</td></tr>
+ * <tr><td>32</td><td>1 ⁄ 32</td></tr>
+ * <tr><td>64</td><td>1 ⁄ 16</td></tr>
+ * <tr><td>128</td><td>1 ⁄ 8</td></tr>
+ * <tr><td>256</td><td>1 ⁄ 4</td></tr>
+ * <tr><td>512</td><td>1 ⁄ 2</td></tr>
+ * <tr><td>1,024</td><td>1</td></tr>
+ * <tr><td>2,048</td><td>2</td></tr>
+ * <tr><td>4,096</td><td>4</td></tr>
+ * <tr><td>8,192</td><td>8</td></tr>
+ * <tr><td>16,384</td><td>16</td></tr>
+ * <tr><td>32,768</td><td>32</td></tr>
+ * </table>
+ *
+ * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
+ *
+ * @hide
+ */
+
+public final class FP16 {
+ /**
+ * The number of bits used to represent a half-precision float value.
+ *
+ * @hide
+ */
+ public static final int SIZE = 16;
+
+ /**
+ * Epsilon is the difference between 1.0 and the next value representable
+ * by a half-precision floating-point.
+ *
+ * @hide
+ */
+ public static final short EPSILON = (short) 0x1400;
+
+ /**
+ * Maximum exponent a finite half-precision float may have.
+ *
+ * @hide
+ */
+ public static final int MAX_EXPONENT = 15;
+ /**
+ * Minimum exponent a normalized half-precision float may have.
+ *
+ * @hide
+ */
+ public static final int MIN_EXPONENT = -14;
+
+ /**
+ * Smallest negative value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short LOWEST_VALUE = (short) 0xfbff;
+ /**
+ * Maximum positive finite value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short MAX_VALUE = (short) 0x7bff;
+ /**
+ * Smallest positive normal value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short MIN_NORMAL = (short) 0x0400;
+ /**
+ * Smallest positive non-zero value a half-precision float may have.
+ *
+ * @hide
+ */
+ public static final short MIN_VALUE = (short) 0x0001;
+ /**
+ * A Not-a-Number representation of a half-precision float.
+ *
+ * @hide
+ */
+ public static final short NaN = (short) 0x7e00;
+ /**
+ * Negative infinity of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short NEGATIVE_INFINITY = (short) 0xfc00;
+ /**
+ * Negative 0 of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short NEGATIVE_ZERO = (short) 0x8000;
+ /**
+ * Positive infinity of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short POSITIVE_INFINITY = (short) 0x7c00;
+ /**
+ * Positive 0 of type half-precision float.
+ *
+ * @hide
+ */
+ public static final short POSITIVE_ZERO = (short) 0x0000;
+
+ /**
+ * The offset to shift by to obtain the sign bit.
+ *
+ * @hide
+ */
+ public static final int SIGN_SHIFT = 15;
+
+ /**
+ * The offset to shift by to obtain the exponent bits.
+ *
+ * @hide
+ */
+ public static final int EXPONENT_SHIFT = 10;
+
+ /**
+ * The bitmask to AND a number with to obtain the sign bit.
+ *
+ * @hide
+ */
+ public static final int SIGN_MASK = 0x8000;
+
+ /**
+ * The bitmask to AND a number shifted by {@link #EXPONENT_SHIFT} right, to obtain exponent bits.
+ *
+ * @hide
+ */
+ public static final int SHIFTED_EXPONENT_MASK = 0x1f;
+
+ /**
+ * The bitmask to AND a number with to obtain significand bits.
+ *
+ * @hide
+ */
+ public static final int SIGNIFICAND_MASK = 0x3ff;
+
+ /**
+ * The bitmask to AND with to obtain exponent and significand bits.
+ *
+ * @hide
+ */
+ public static final int EXPONENT_SIGNIFICAND_MASK = 0x7fff;
+
+ /**
+ * The offset of the exponent from the actual value.
+ *
+ * @hide
+ */
+ public static final int EXPONENT_BIAS = 15;
+
+ private static final int FP32_SIGN_SHIFT = 31;
+ private static final int FP32_EXPONENT_SHIFT = 23;
+ private static final int FP32_SHIFTED_EXPONENT_MASK = 0xff;
+ private static final int FP32_SIGNIFICAND_MASK = 0x7fffff;
+ private static final int FP32_EXPONENT_BIAS = 127;
+ private static final int FP32_QNAN_MASK = 0x400000;
+ private static final int FP32_DENORMAL_MAGIC = 126 << 23;
+ private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
+
+ /** Hidden constructor to prevent instantiation. */
+ private FP16() {}
+
+ /**
+ * <p>Compares the two specified half-precision float values. The following
+ * conditions apply during the comparison:</p>
+ *
+ * <ul>
+ * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+ * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+ * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+ * {@link #NEGATIVE_ZERO}.</li>
+ * </ul>
+ *
+ * @param x The first half-precision float value to compare.
+ * @param y The second half-precision float value to compare
+ *
+ * @return The value {@code 0} if {@code x} is numerically equal to {@code y}, a
+ * value less than {@code 0} if {@code x} is numerically less than {@code y},
+ * and a value greater than {@code 0} if {@code x} is numerically greater
+ * than {@code y}
+ *
+ * @hide
+ */
+ public static int compare(short x, short y) {
+ if (less(x, y)) return -1;
+ if (greater(x, y)) return 1;
+
+ // Collapse NaNs, akin to halfToIntBits(), but we want to keep
+ // (signed) short value types to preserve the ordering of -0.0
+ // and +0.0
+ short xBits = isNaN(x) ? NaN : x;
+ short yBits = isNaN(y) ? NaN : y;
+
+ return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
+ }
+
+ /**
+ * Returns the closest integral half-precision float value to the specified
+ * half-precision float value. Special values are handled in the
+ * following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The value of the specified half-precision float rounded to the nearest
+ * half-precision float value
+ *
+ * @hide
+ */
+ public static short rint(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ if (abs > 0x3800){
+ result |= 0x3c00;
+ }
+ } else if (abs < 0x6400) {
+ int exp = 25 - (abs >> 10);
+ int mask = (1 << exp) - 1;
+ result += ((1 << (exp - 1)) - (~(abs >> exp) & 1));
+ result &= ~mask;
+ }
+ if (isNaN((short) result)) {
+ // if result is NaN mask with qNaN
+ // (i.e. mask the most significant mantissa bit with 1)
+ // to comply with hardware implementations (ARM64, Intel, etc).
+ result |= NaN;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the smallest half-precision float value toward negative infinity
+ * greater than or equal to the specified half-precision float value.
+ * Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The smallest half-precision float value toward negative infinity
+ * greater than or equal to the specified half-precision float value
+ *
+ * @hide
+ */
+ public static short ceil(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ result |= 0x3c00 & -(~(bits >> 15) & (abs != 0 ? 1 : 0));
+ } else if (abs < 0x6400) {
+ abs = 25 - (abs >> 10);
+ int mask = (1 << abs) - 1;
+ result += mask & ((bits >> 15) - 1);
+ result &= ~mask;
+ }
+ if (isNaN((short) result)) {
+ // if result is NaN mask with qNaN
+ // (i.e. mask the most significant mantissa bit with 1)
+ // to comply with hardware implementations (ARM64, Intel, etc).
+ result |= NaN;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the largest half-precision float value toward positive infinity
+ * less than or equal to the specified half-precision float value.
+ * Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The largest half-precision float value toward positive infinity
+ * less than or equal to the specified half-precision float value
+ *
+ * @hide
+ */
+ public static short floor(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0);
+ } else if (abs < 0x6400) {
+ abs = 25 - (abs >> 10);
+ int mask = (1 << abs) - 1;
+ result += mask & -(bits >> 15);
+ result &= ~mask;
+ }
+ if (isNaN((short) result)) {
+ // if result is NaN mask with qNaN
+ // i.e. (Mask the most significant mantissa bit with 1)
+ result |= NaN;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the truncated half-precision float value of the specified
+ * half-precision float value. Special values are handled in the following ways:
+ * <ul>
+ * <li>If the specified half-precision float is NaN, the result is NaN</li>
+ * <li>If the specified half-precision float is infinity (negative or positive),
+ * the result is infinity (with the same sign)</li>
+ * <li>If the specified half-precision float is zero (negative or positive),
+ * the result is zero (with the same sign)</li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return The truncated half-precision float value of the specified
+ * half-precision float value
+ *
+ * @hide
+ */
+ public static short trunc(short h) {
+ int bits = h & 0xffff;
+ int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+ int result = bits;
+
+ if (abs < 0x3c00) {
+ result &= SIGN_MASK;
+ } else if (abs < 0x6400) {
+ abs = 25 - (abs >> 10);
+ int mask = (1 << abs) - 1;
+ result &= ~mask;
+ }
+
+ return (short) result;
+ }
+
+ /**
+ * Returns the smaller of two half-precision float values (the value closest
+ * to negative infinity). Special values are handled in the following ways:
+ * <ul>
+ * <li>If either value is NaN, the result is NaN</li>
+ * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li>
+ * </ul>
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ * @return The smaller of the two specified half-precision values
+ *
+ * @hide
+ */
+ public static short min(short x, short y) {
+ if (isNaN(x)) return NaN;
+ if (isNaN(y)) return NaN;
+
+ if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+ return (x & SIGN_MASK) != 0 ? x : y;
+ }
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ }
+
+ /**
+ * Returns the larger of two half-precision float values (the value closest
+ * to positive infinity). Special values are handled in the following ways:
+ * <ul>
+ * <li>If either value is NaN, the result is NaN</li>
+ * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li>
+ * </ul>
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return The larger of the two specified half-precision values
+ *
+ * @hide
+ */
+ public static short max(short x, short y) {
+ if (isNaN(x)) return NaN;
+ if (isNaN(y)) return NaN;
+
+ if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+ return (x & SIGN_MASK) != 0 ? y : x;
+ }
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+ }
+
+ /**
+ * Returns true if the first half-precision float value is less (smaller
+ * toward negative infinity) than the second half-precision float value.
+ * If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is less than y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean less(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is less (smaller
+ * toward negative infinity) than or equal to the second half-precision
+ * float value. If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is less than or equal to y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean lessEquals(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is greater (larger
+ * toward positive infinity) than the second half-precision float value.
+ * If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is greater than y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean greater(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the first half-precision float value is greater (larger
+ * toward positive infinity) than or equal to the second half-precision float
+ * value. If either of the values is NaN, the result is false.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is greater than y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean greaterEquals(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
+ ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+ }
+
+ /**
+ * Returns true if the two half-precision float values are equal.
+ * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO}
+ * and {@link #NEGATIVE_ZERO} are considered equal.
+ *
+ * @param x The first half-precision value
+ * @param y The second half-precision value
+ *
+ * @return True if x is equal to y, false otherwise
+ *
+ * @hide
+ */
+ public static boolean equals(short x, short y) {
+ if (isNaN(x)) return false;
+ if (isNaN(y)) return false;
+
+ return x == y || ((x | y) & EXPONENT_SIGNIFICAND_MASK) == 0;
+ }
+
+ /**
+ * Returns true if the specified half-precision float value represents
+ * infinity, false otherwise.
+ *
+ * @param h A half-precision float value
+ * @return True if the value is positive infinity or negative infinity,
+ * false otherwise
+ *
+ * @hide
+ */
+ public static boolean isInfinite(short h) {
+ return (h & EXPONENT_SIGNIFICAND_MASK) == POSITIVE_INFINITY;
+ }
+
+ /**
+ * Returns true if the specified half-precision float value represents
+ * a Not-a-Number, false otherwise.
+ *
+ * @param h A half-precision float value
+ * @return True if the value is a NaN, false otherwise
+ *
+ * @hide
+ */
+ public static boolean isNaN(short h) {
+ return (h & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY;
+ }
+
+ /**
+ * Returns true if the specified half-precision float value is normalized
+ * (does not have a subnormal representation). If the specified value is
+ * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY},
+ * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal
+ * number, this method returns false.
+ *
+ * @param h A half-precision float value
+ * @return True if the value is normalized, false otherwise
+ *
+ * @hide
+ */
+ public static boolean isNormalized(short h) {
+ return (h & POSITIVE_INFINITY) != 0 && (h & POSITIVE_INFINITY) != POSITIVE_INFINITY;
+ }
+
+ /**
+ * <p>Converts the specified half-precision float value into a
+ * single-precision float value. The following special cases are handled:</p>
+ * <ul>
+ * <li>If the input is {@link #NaN}, the returned value is {@link Float#NaN}</li>
+ * <li>If the input is {@link #POSITIVE_INFINITY} or
+ * {@link #NEGATIVE_INFINITY}, the returned value is respectively
+ * {@link Float#POSITIVE_INFINITY} or {@link Float#NEGATIVE_INFINITY}</li>
+ * <li>If the input is 0 (positive or negative), the returned value is +/-0.0f</li>
+ * <li>Otherwise, the returned value is a normalized single-precision float value</li>
+ * </ul>
+ *
+ * @param h The half-precision float value to convert to single-precision
+ * @return A normalized single-precision float value
+ *
+ * @hide
+ */
+ public static float toFloat(short h) {
+ int bits = h & 0xffff;
+ int s = bits & SIGN_MASK;
+ int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+ int m = (bits ) & SIGNIFICAND_MASK;
+
+ int outE = 0;
+ int outM = 0;
+
+ if (e == 0) { // Denormal or 0
+ if (m != 0) {
+ // Convert denorm fp16 into normalized fp32
+ float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m);
+ o -= FP32_DENORMAL_FLOAT;
+ return s == 0 ? o : -o;
+ }
+ } else {
+ outM = m << 13;
+ if (e == 0x1f) { // Infinite or NaN
+ outE = 0xff;
+ if (outM != 0) { // SNaNs are quieted
+ outM |= FP32_QNAN_MASK;
+ }
+ } else {
+ outE = e - EXPONENT_BIAS + FP32_EXPONENT_BIAS;
+ }
+ }
+
+ int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM;
+ return Float.intBitsToFloat(out);
+ }
+
+ /**
+ * <p>Converts the specified single-precision float value into a
+ * half-precision float value. The following special cases are handled:</p>
+ * <ul>
+ * <li>If the input is NaN (see {@link Float#isNaN(float)}), the returned
+ * value is {@link #NaN}</li>
+ * <li>If the input is {@link Float#POSITIVE_INFINITY} or
+ * {@link Float#NEGATIVE_INFINITY}, the returned value is respectively
+ * {@link #POSITIVE_INFINITY} or {@link #NEGATIVE_INFINITY}</li>
+ * <li>If the input is 0 (positive or negative), the returned value is
+ * {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+ * <li>If the input is a less than {@link #MIN_VALUE}, the returned value
+ * is flushed to {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+ * <li>If the input is a less than {@link #MIN_NORMAL}, the returned value
+ * is a denorm half-precision float</li>
+ * <li>Otherwise, the returned value is rounded to the nearest
+ * representable half-precision float value</li>
+ * </ul>
+ *
+ * @param f The single-precision float value to convert to half-precision
+ * @return A half-precision float value
+ *
+ * @hide
+ */
+ public static short toHalf(float f) {
+ int bits = Float.floatToRawIntBits(f);
+ int s = (bits >>> FP32_SIGN_SHIFT );
+ int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_SHIFTED_EXPONENT_MASK;
+ int m = (bits ) & FP32_SIGNIFICAND_MASK;
+
+ int outE = 0;
+ int outM = 0;
+
+ if (e == 0xff) { // Infinite or NaN
+ outE = 0x1f;
+ outM = m != 0 ? 0x200 : 0;
+ } else {
+ e = e - FP32_EXPONENT_BIAS + EXPONENT_BIAS;
+ if (e >= 0x1f) { // Overflow
+ outE = 0x1f;
+ } else if (e <= 0) { // Underflow
+ if (e < -10) {
+ // The absolute fp32 value is less than MIN_VALUE, flush to +/-0
+ } else {
+ // The fp32 value is a normalized float less than MIN_NORMAL,
+ // we convert to a denorm fp16
+ m = m | 0x800000;
+ int shift = 14 - e;
+ outM = m >> shift;
+
+ int lowm = m & ((1 << shift) - 1);
+ int hway = 1 << (shift - 1);
+ // if above halfway or exactly halfway and outM is odd
+ if (lowm + (outM & 1) > hway){
+ // Round to nearest even
+ // Can overflow into exponent bit, which surprisingly is OK.
+ // This increment relies on the +outM in the return statement below
+ outM++;
+ }
+ }
+ } else {
+ outE = e;
+ outM = m >> 13;
+ // if above halfway or exactly halfway and outM is odd
+ if ((m & 0x1fff) + (outM & 0x1) > 0x1000) {
+ // Round to nearest even
+ // Can overflow into exponent bit, which surprisingly is OK.
+ // This increment relies on the +outM in the return statement below
+ outM++;
+ }
+ }
+ }
+ // The outM is added here as the +1 increments for outM above can
+ // cause an overflow in the exponent bit which is OK.
+ return (short) ((s << SIGN_SHIFT) | (outE << EXPONENT_SHIFT) + outM);
+ }
+
+ /**
+ * <p>Returns a hexadecimal string representation of the specified half-precision
+ * float value. If the value is a NaN, the result is <code>"NaN"</code>,
+ * otherwise the result follows this format:</p>
+ * <ul>
+ * <li>If the sign is positive, no sign character appears in the result</li>
+ * <li>If the sign is negative, the first character is <code>'-'</code></li>
+ * <li>If the value is inifinity, the string is <code>"Infinity"</code></li>
+ * <li>If the value is 0, the string is <code>"0x0.0p0"</code></li>
+ * <li>If the value has a normalized representation, the exponent and
+ * significand are represented in the string in two fields. The significand
+ * starts with <code>"0x1."</code> followed by its lowercase hexadecimal
+ * representation. Trailing zeroes are removed unless all digits are 0, then
+ * a single zero is used. The significand representation is followed by the
+ * exponent, represented by <code>"p"</code>, itself followed by a decimal
+ * string of the unbiased exponent</li>
+ * <li>If the value has a subnormal representation, the significand starts
+ * with <code>"0x0."</code> followed by its lowercase hexadecimal
+ * representation. Trailing zeroes are removed unless all digits are 0, then
+ * a single zero is used. The significand representation is followed by the
+ * exponent, represented by <code>"p-14"</code></li>
+ * </ul>
+ *
+ * @param h A half-precision float value
+ * @return A hexadecimal string representation of the specified value
+ *
+ * @hide
+ */
+ public static String toHexString(short h) {
+ StringBuilder o = new StringBuilder();
+
+ int bits = h & 0xffff;
+ int s = (bits >>> SIGN_SHIFT );
+ int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+ int m = (bits ) & SIGNIFICAND_MASK;
+
+ if (e == 0x1f) { // Infinite or NaN
+ if (m == 0) {
+ if (s != 0) o.append('-');
+ o.append("Infinity");
+ } else {
+ o.append("NaN");
+ }
+ } else {
+ if (s == 1) o.append('-');
+ if (e == 0) {
+ if (m == 0) {
+ o.append("0x0.0p0");
+ } else {
+ o.append("0x0.");
+ String significand = Integer.toHexString(m);
+ o.append(significand.replaceFirst("0{2,}$", ""));
+ o.append("p-14");
+ }
+ } else {
+ o.append("0x1.");
+ String significand = Integer.toHexString(m);
+ o.append(significand.replaceFirst("0{2,}$", ""));
+ o.append('p');
+ o.append(Integer.toString(e - EXPONENT_BIAS));
+ }
+ }
+
+ return o.toString();
+ }
+}
diff --git a/ravenwood/scripts/list-ravenwood-tests.sh b/ravenwood/scripts/list-ravenwood-tests.sh
index fb9b823..05f3fdf 100755
--- a/ravenwood/scripts/list-ravenwood-tests.sh
+++ b/ravenwood/scripts/list-ravenwood-tests.sh
@@ -15,4 +15,4 @@
# List all the ravenwood test modules.
-jq -r 'to_entries[] | select( .value.compatibility_suites | index("ravenwood-tests") ) | .key' "$OUT/module-info.json"
+jq -r 'to_entries[] | select( .value.compatibility_suites | index("ravenwood-tests") ) | .key' "$OUT/module-info.json" | sort
diff --git a/ravenwood/scripts/remove-ravenizer-output.sh b/ravenwood/scripts/remove-ravenizer-output.sh
new file mode 100755
index 0000000..be15b71
--- /dev/null
+++ b/ravenwood/scripts/remove-ravenizer-output.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright (C) 2024 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.
+
+# Delete all the ravenizer output jar files from Soong's intermediate directory.
+
+# `-a -prune` is needed because otherwise find would be confused if the directory disappears.
+
+find "${ANDROID_BUILD_TOP:?}/out/soong/.intermediates/" \
+ -type d \
+ -name 'ravenizer' \
+ -print \
+ -exec rm -fr \{\} \; \
+ -a -prune
diff --git a/ravenwood/scripts/update-test-mapping.sh b/ravenwood/scripts/update-test-mapping.sh
new file mode 100755
index 0000000..b6cf5b8
--- /dev/null
+++ b/ravenwood/scripts/update-test-mapping.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+# Copyright (C) 2024 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.
+
+# Update f/b/r/TEST_MAPPING with all the ravenwood tests as presubmit.
+#
+# Note, before running it, make sure module-info.json is up-to-date by running
+# (any) build.
+
+set -e
+
+main() {
+ local script_name="${0##*/}"
+ local script_dir="${0%/*}"
+ local test_mapping="$script_dir/../TEST_MAPPING"
+ local test_mapping_bak="$script_dir/../TEST_MAPPING.bak"
+
+ local header="$(sed -ne '1,/AUTO-GENERATED-START/p' "$test_mapping")"
+ local footer="$(sed -ne '/AUTO-GENERATED-END/,$p' "$test_mapping")"
+
+ echo "Getting all tests"
+ local tests=( $("$script_dir/list-ravenwood-tests.sh") )
+
+ local num_tests="${#tests[@]}"
+
+ if (( $num_tests == 0 )) ; then
+ echo "Something went wrong. No ravenwood tests detected." 1>&2
+ return 1
+ fi
+
+ echo "Tests: ${tests[@]}"
+
+ echo "Creating backup at $test_mapping_bak"
+ cp "$test_mapping" "$test_mapping_bak"
+
+ echo "Updating $test_mapping"
+ {
+ echo "$header"
+
+ echo " // DO NOT MODIFY MANUALLY"
+ echo " // Use scripts/$script_name to update it."
+
+ local i=0
+ while (( $i < $num_tests )) ; do
+ local comma=","
+ if (( $i == ($num_tests - 1) )); then
+ comma=""
+ fi
+ echo " {"
+ echo " \"name\": \"${tests[$i]}\","
+ echo " \"host\": true"
+ echo " }$comma"
+
+ i=$(( $i + 1 ))
+ done
+
+ echo "$footer"
+ } >"$test_mapping"
+
+ if cmp "$test_mapping_bak" "$test_mapping" ; then
+ echo "No change detecetd."
+ return 0
+ fi
+ echo "Updated $test_mapping"
+
+ # `|| true` is needed because of `set -e`.
+ diff -u "$test_mapping_bak" "$test_mapping" || true
+ return 0
+}
+
+main
diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index d8366c5..34239b8 100644
--- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
@@ -46,6 +46,7 @@
android.util.EventLog
android.util.FloatProperty
android.util.FloatMath
+android.util.Half
android.util.IndentingPrintWriter
android.util.IntArray
android.util.IntProperty
@@ -277,7 +278,11 @@
android.graphics.Insets
android.graphics.Interpolator
android.graphics.Matrix
+android.graphics.Matrix44
+android.graphics.Outline
+android.graphics.ParcelableColorSpace
android.graphics.Path
+android.graphics.PixelFormat
android.graphics.Point
android.graphics.PointF
android.graphics.Rect
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Exceptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Exceptions.kt
index 3a7fab3..0dcd271 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Exceptions.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Exceptions.kt
@@ -17,7 +17,14 @@
package com.android.platform.test.ravenwood.ravenizer
+import com.android.hoststubgen.UserErrorException
+
/**
* Use it for internal exception that really shouldn't happen.
*/
class RavenizerInternalException(message: String) : Exception(message)
+
+/**
+ * Thrown when an invalid test is detected in the target jar. (e.g. JUni3 tests)
+ */
+class RavenizerInvalidTestException(message: String) : Exception(message), UserErrorException
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
index e92ef72..a38512e 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
@@ -44,6 +44,9 @@
/** Time took to build [ClasNodes] */
var loadStructureTime: Double = .0,
+ /** Time took to validate the classes */
+ var validationTime: Double = .0,
+
/** Total real time spent for converting the jar file */
var totalProcessTime: Double = .0,
@@ -67,6 +70,7 @@
RavenizerStats{
totalTime=$totalTime,
loadStructureTime=$loadStructureTime,
+ validationTime=$validationTime,
totalProcessTime=$totalProcessTime,
totalConversionTime=$totalConversionTime,
totalCopyTime=$totalCopyTime,
@@ -84,16 +88,44 @@
class Ravenizer(val options: RavenizerOptions) {
fun run() {
val stats = RavenizerStats()
+
+ val fatalValidation = options.fatalValidation.get
+
stats.totalTime = log.nTime {
- process(options.inJar.get, options.outJar.get, stats)
+ process(
+ options.inJar.get,
+ options.outJar.get,
+ options.enableValidation.get,
+ fatalValidation,
+ stats,
+ )
}
log.i(stats.toString())
}
- private fun process(inJar: String, outJar: String, stats: RavenizerStats) {
+ private fun process(
+ inJar: String,
+ outJar: String,
+ enableValidation: Boolean,
+ fatalValidation: Boolean,
+ stats: RavenizerStats,
+ ) {
var allClasses = ClassNodes.loadClassStructures(inJar) {
time -> stats.loadStructureTime = time
}
+ if (enableValidation) {
+ stats.validationTime = log.iTime("Validating classes") {
+ if (!validateClasses(allClasses)) {
+ var message = "Invalid test class(es) detected." +
+ " See error log for details."
+ if (fatalValidation) {
+ throw RavenizerInvalidTestException(message)
+ } else {
+ log.w("Warning: $message")
+ }
+ }
+ }
+ }
stats.totalProcessTime = log.iTime("$executableName processing $inJar") {
ZipFile(inJar).use { inZip ->
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
index e85e3be..e8341e5 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
@@ -27,6 +27,12 @@
/** Output jar file */
var outJar: SetOnce<String> = SetOnce(""),
+
+ /** Whether to enable test validation. */
+ var enableValidation: SetOnce<Boolean> = SetOnce(true),
+
+ /** Whether the validation failure is fatal or not. */
+ var fatalValidation: SetOnce<Boolean> = SetOnce(false),
) {
companion object {
fun parseArgs(args: Array<String>): RavenizerOptions {
@@ -52,6 +58,12 @@
"--in-jar" -> ret.inJar.set(nextArg()).ensureFileExists()
"--out-jar" -> ret.outJar.set(nextArg())
+ "--enable-validation" -> ret.enableValidation.set(true)
+ "--disable-validation" -> ret.enableValidation.set(false)
+
+ "--fatal-validation" -> ret.fatalValidation.set(true)
+ "--no-fatal-validation" -> ret.fatalValidation.set(false)
+
else -> throw ArgumentsException("Unknown option: $arg")
}
} catch (e: SetOnce.SetMoreThanOnceException) {
@@ -74,6 +86,8 @@
RavenizerOptions{
inJar=$inJar,
outJar=$outJar,
+ enableValidation=$enableValidation,
+ fatalValidation=$fatalValidation,
}
""".trimIndent()
}
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt
index e026e7a..1aa70c08 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Utils.kt
@@ -15,10 +15,12 @@
*/
package com.android.platform.test.ravenwood.ravenizer
+import android.platform.test.annotations.NoRavenizer
import android.platform.test.ravenwood.RavenwoodAwareTestRunner
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.findAnyAnnotation
import com.android.hoststubgen.asm.startsWithAny
+import com.android.hoststubgen.asm.toHumanReadableClassName
import org.junit.rules.TestRule
import org.junit.runner.RunWith
import org.objectweb.asm.Type
@@ -30,6 +32,7 @@
val desc = type.descriptor
val descAsSet = setOf<String>(desc)
val internlName = type.internalName
+ val humanReadableName = type.internalName.toHumanReadableClassName()
}
val testAnotType = TypeHolder(org.junit.Test::class.java)
@@ -37,6 +40,7 @@
val classRuleAnotType = TypeHolder(org.junit.ClassRule::class.java)
val runWithAnotType = TypeHolder(RunWith::class.java)
val innerRunnerAnotType = TypeHolder(RavenwoodAwareTestRunner.InnerRunner::class.java)
+val noRavenizerAnotType = TypeHolder(NoRavenizer::class.java)
val testRuleType = TypeHolder(TestRule::class.java)
val ravenwoodTestRunnerType = TypeHolder(RavenwoodAwareTestRunner::class.java)
@@ -87,9 +91,12 @@
return this.startsWithAny(
"java/", // just in case...
"javax/",
+ "junit/",
"org/junit/",
"org/mockito/",
"kotlin/",
+ "androidx/",
+ "android/support/",
// TODO -- anything else?
)
}
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt
new file mode 100644
index 0000000..27092d2
--- /dev/null
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.platform.test.ravenwood.ravenizer
+
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.startsWithAny
+import com.android.hoststubgen.asm.toHumanReadableClassName
+import com.android.hoststubgen.log
+import org.objectweb.asm.tree.ClassNode
+
+fun validateClasses(classes: ClassNodes): Boolean {
+ var allOk = true
+ classes.forEach { allOk = checkClass(it, classes) && allOk }
+
+ return allOk
+}
+
+/**
+ * Validate a class.
+ *
+ * - A test class shouldn't extend
+ *
+ */
+fun checkClass(cn: ClassNode, classes: ClassNodes): Boolean {
+ if (cn.name.shouldByBypassed()) {
+ // Class doesn't need to be checked.
+ return true
+ }
+ var allOk = true
+
+ // See if there's any class that extends a legacy base class.
+ // But ignore the base classes in android.test.
+ if (!cn.name.startsWithAny("android/test/")) {
+ allOk = checkSuperClass(cn, cn, classes) && allOk
+ }
+ return allOk
+}
+
+fun checkSuperClass(targetClass: ClassNode, currentClass: ClassNode, classes: ClassNodes): Boolean {
+ if (currentClass.superName == null || currentClass.superName == "java/lang/Object") {
+ return true // No parent class
+ }
+ if (currentClass.superName.isLegacyTestBaseClass()) {
+ log.e("Error: Class ${targetClass.name.toHumanReadableClassName()} extends"
+ + " a legacy test class ${currentClass.superName.toHumanReadableClassName()}.")
+ return false
+ }
+ classes.findClass(currentClass.superName)?.let {
+ return checkSuperClass(targetClass, it, classes)
+ }
+ // Super class not found.
+ // log.w("Class ${currentClass.superName} not found.")
+ return true
+}
+
+/**
+ * Check if a class internal name is a known legacy test base class.
+ */
+fun String.isLegacyTestBaseClass(): Boolean {
+ return this.startsWithAny(
+ "junit/framework/TestCase",
+
+ // In case the test doesn't statically include JUnit, we need
+ "android/test/AndroidTestCase",
+ "android/test/InstrumentationTestCase",
+ "android/test/InstrumentationTestSuite",
+ )
+}
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
index 25cad02..eaef2cf 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
@@ -30,6 +30,7 @@
import com.android.platform.test.ravenwood.ravenizer.classRuleAnotType
import com.android.platform.test.ravenwood.ravenizer.isTestLookingClass
import com.android.platform.test.ravenwood.ravenizer.innerRunnerAnotType
+import com.android.platform.test.ravenwood.ravenizer.noRavenizerAnotType
import com.android.platform.test.ravenwood.ravenizer.ravenwoodTestRunnerType
import com.android.platform.test.ravenwood.ravenizer.ruleAnotType
import com.android.platform.test.ravenwood.ravenizer.runWithAnotType
@@ -183,7 +184,7 @@
av.visit("value", ravenwoodTestRunnerType.type)
av.visitEnd()
}
- log.d("Processed ${classInternalName.toHumanReadableClassName()}")
+ log.i("Update the @RunWith: ${classInternalName.toHumanReadableClassName()}")
}
/*
@@ -435,7 +436,19 @@
companion object {
fun shouldProcess(classes: ClassNodes, className: String): Boolean {
- return isTestLookingClass(classes, className)
+ if (!isTestLookingClass(classes, className)) {
+ return false
+ }
+ // Don't process a class if it has a @NoRavenizer annotation.
+ classes.findClass(className)?.let { cn ->
+ if (cn.findAnyAnnotation(noRavenizerAnotType.descAsSet) != null) {
+ log.w("Class ${className.toHumanReadableClassName()} has" +
+ " @${noRavenizerAnotType.humanReadableName}. Skipping."
+ )
+ return false
+ }
+ }
+ return true
}
fun maybeApply(
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7cbb97e..f1a8b5a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -163,6 +163,7 @@
import android.view.accessibility.IAccessibilityManager;
import android.view.accessibility.IAccessibilityManagerClient;
import android.view.accessibility.IMagnificationConnection;
+import android.view.accessibility.IUserInitializationCompleteCallback;
import android.view.inputmethod.EditorInfo;
import com.android.internal.R;
@@ -366,6 +367,11 @@
private final List<SendWindowStateChangedEventRunnable> mSendWindowStateChangedEventRunnables =
new ArrayList<>();
+ @VisibleForTesting
+ final HashSet<IUserInitializationCompleteCallback>
+ mUserInitializationCompleteCallbacks =
+ new HashSet<IUserInitializationCompleteCallback>();
+
@GuardedBy("mLock")
private @UserIdInt int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -2034,6 +2040,17 @@
obtainMessage(AccessibilityManagerService::announceNewUserIfNeeded, this),
WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS);
}
+
+ for (IUserInitializationCompleteCallback callback
+ : mUserInitializationCompleteCallbacks) {
+ try {
+ callback.onUserInitializationComplete(mCurrentUserId);
+ } catch (RemoteException re) {
+ Log.e("AccessibilityManagerService",
+ "Error while dispatching userInitializationComplete callback: ",
+ re);
+ }
+ }
}
}
@@ -6251,6 +6268,24 @@
}
@Override
+ @RequiresNoPermission
+ public void registerUserInitializationCompleteCallback(
+ IUserInitializationCompleteCallback callback) {
+ synchronized (mLock) {
+ mUserInitializationCompleteCallbacks.add(callback);
+ }
+ }
+
+ @Override
+ @RequiresNoPermission
+ public void unregisterUserInitializationCompleteCallback(
+ IUserInitializationCompleteCallback callback) {
+ synchronized (mLock) {
+ mUserInitializationCompleteCallbacks.remove(callback);
+ }
+ }
+
+ @Override
@EnforcePermission(INJECT_EVENTS)
public void injectInputEventToInputFilter(InputEvent event) {
injectInputEventToInputFilter_enforcePermission();
diff --git a/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerManager.java b/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerManager.java
index 83f57b2..950246f 100644
--- a/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerManager.java
@@ -87,7 +87,7 @@
public Set<AndroidAccessibilityCheckerResult> maybeRunA11yChecker(
List<AccessibilityNodeInfo> nodes, @Nullable String sourceEventClassName,
ComponentName a11yServiceComponentName, @UserIdInt int userId) {
- if (!shouldRunA11yChecker()) {
+ if (!shouldRunA11yChecker() || nodes.isEmpty()) {
return Set.of();
}
@@ -95,24 +95,33 @@
String defaultBrowserName = mPackageManager.getDefaultBrowserPackageNameAsUser(userId);
try {
+ AndroidAccessibilityCheckerResult.Builder commonResultBuilder =
+ AccessibilityCheckerUtils.getCommonResultBuilder(nodes.getFirst(),
+ sourceEventClassName, mPackageManager, a11yServiceComponentName);
+ if (commonResultBuilder == null) {
+ return Set.of();
+ }
for (AccessibilityNodeInfo nodeInfo : nodes) {
- // Skip browser results because they are mostly related to web content and not the
- // browser app itself.
+ // Skip browser results because they are mostly related to web content and
+ // not the browser app itself.
if (nodeInfo.getPackageName() == null
|| nodeInfo.getPackageName().toString().equals(defaultBrowserName)) {
continue;
}
- List<AccessibilityHierarchyCheckResult> checkResults = runChecksOnNode(nodeInfo);
+ List<AccessibilityHierarchyCheckResult> checkResults = runChecksOnNode(
+ nodeInfo);
Set<AndroidAccessibilityCheckerResult> filteredResults =
AccessibilityCheckerUtils.processResults(nodeInfo, checkResults,
- sourceEventClassName, mPackageManager, a11yServiceComponentName);
+ commonResultBuilder);
allResults.addAll(filteredResults);
}
mCachedResults.addAll(allResults);
+ return allResults;
+
} catch (RuntimeException e) {
Slog.e(LOG_TAG, "An unknown error occurred while running a11y checker.", e);
+ return Set.of();
}
- return allResults;
}
private List<AccessibilityHierarchyCheckResult> runChecksOnNode(
diff --git a/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtils.java b/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtils.java
index eb24b02..a739304 100644
--- a/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtils.java
@@ -91,45 +91,55 @@
AccessibilityCheckClass.TRAVERSAL_ORDER_CHECK));
// LINT.ThenChange(/services/accessibility/java/com/android/server/accessibility/a11ychecker/proto/a11ychecker.proto)
- static Set<AndroidAccessibilityCheckerResult> processResults(
+
+ /**
+ * Returns AccessibilityCheckResultReported.Builder with the common fields for all nodes
+ * belonging in the same cache pre-filled.
+ */
+ static @Nullable AndroidAccessibilityCheckerResult.Builder getCommonResultBuilder(
AccessibilityNodeInfo nodeInfo,
- List<AccessibilityHierarchyCheckResult> checkResults,
@Nullable String activityClassName,
PackageManager packageManager,
ComponentName a11yServiceComponentName) {
- String appPackageName = nodeInfo.getPackageName().toString();
- String nodePath = AccessibilityNodePathBuilder.createNodePath(nodeInfo);
- if (nodePath == null) {
- return Set.of();
+ if (nodeInfo.getPackageName() == null) {
+ return null;
}
- AndroidAccessibilityCheckerResult.Builder commonBuilder;
+ String appPackageName = nodeInfo.getPackageName().toString();
try {
- commonBuilder = AndroidAccessibilityCheckerResult.newBuilder()
+ return AndroidAccessibilityCheckerResult.newBuilder()
.setPackageName(appPackageName)
.setAppVersionCode(getAppVersionCode(packageManager, appPackageName))
- .setUiElementPath(nodePath)
.setActivityName(
getActivityName(packageManager, appPackageName, activityClassName))
.setWindowTitle(getWindowTitle(nodeInfo))
.setSourceComponentName(a11yServiceComponentName)
- .setSourceVersionCode(
- getAppVersionCode(packageManager,
- a11yServiceComponentName.getPackageName()));
+ .setSourceVersionCode(getAppVersionCode(packageManager,
+ a11yServiceComponentName.getPackageName()));
} catch (PackageManager.NameNotFoundException e) {
Slog.e(LOG_TAG, "Unknown package name", e);
+ return null;
+ }
+ }
+
+ static Set<AndroidAccessibilityCheckerResult> processResults(
+ AccessibilityNodeInfo nodeInfo,
+ List<AccessibilityHierarchyCheckResult> checkResults,
+ AndroidAccessibilityCheckerResult.Builder resultBuilder) {
+ String nodePath = AccessibilityNodePathBuilder.createNodePath(nodeInfo);
+ if (resultBuilder == null || nodePath == null) {
return Set.of();
}
-
return checkResults.stream()
.filter(checkResult -> checkResult.getType()
== AccessibilityCheckResult.AccessibilityCheckResultType.ERROR
|| checkResult.getType()
== AccessibilityCheckResult.AccessibilityCheckResultType.WARNING)
- .map(checkResult -> new AndroidAccessibilityCheckerResult.Builder(
- commonBuilder).setResultCheckClass(
- getCheckClass(checkResult)).setResultType(
- getCheckResultType(checkResult)).setResultId(
- checkResult.getResultId()).build())
+ .map(checkResult -> new AndroidAccessibilityCheckerResult.Builder(resultBuilder)
+ .setUiElementPath(nodePath)
+ .setResultCheckClass(getCheckClass(checkResult))
+ .setResultType(getCheckResultType(checkResult))
+ .setResultId(checkResult.getResultId())
+ .build())
.collect(Collectors.toUnmodifiableSet());
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
index 954651d..a2d467c 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
@@ -16,8 +16,7 @@
package com.android.server.appfunctions;
-import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
-
+import android.app.appfunctions.AppFunctionManagerConfiguration;
import android.content.Context;
import com.android.server.SystemService;
@@ -35,7 +34,7 @@
@Override
public void onStart() {
- if (enableAppFunctionManager()) {
+ if (AppFunctionManagerConfiguration.isSupported(getContext())) {
publishBinderService(Context.APP_FUNCTION_SERVICE, mServiceImpl);
}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index 53885fc..f5d07ef 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -94,36 +94,39 @@
targetUser = mCallerValidator.verifyTargetUserHandle(
requestInternal.getUserHandle(), validatedCallingPackage);
} catch (SecurityException exception) {
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse
- .Builder(ExecuteAppFunctionResponse.RESULT_DENIED,
- getExceptionMessage(exception)).build());
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
+ .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED,
+ exception.getMessage(),
+ /*extras=*/ null));
return;
}
// TODO(b/354956319): Add and honor the new enterprise policies.
if (mCallerValidator.isUserOrganizationManaged(targetUser)) {
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder(
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
- "Cannot run on a device with a device owner or from the managed profile."
- ).build());
+ "Cannot run on a device with a device owner or from the managed profile.",
+ /*extras=*/ null
+ ));
return;
}
String targetPackageName = requestInternal.getClientRequest().getTargetPackageName();
if (TextUtils.isEmpty(targetPackageName)) {
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder(
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT,
- "Target package name cannot be empty."
- ).build());
+ "Target package name cannot be empty.",
+ /*extras=*/ null
+ ));
return;
}
if (!mCallerValidator.verifyCallerCanExecuteAppFunction(
validatedCallingPackage, targetPackageName)) {
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse
- .Builder(ExecuteAppFunctionResponse.RESULT_DENIED,
- "Caller does not have permission to execute the appfunction")
- .build());
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
+ .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED,
+ "Caller does not have permission to execute the appfunction",
+ /*extras=*/ null));
return;
}
@@ -131,10 +134,11 @@
targetPackageName,
targetUser);
if (serviceIntent == null) {
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder(
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
- "Cannot find the target service."
- ).build());
+ "Cannot find the target service.",
+ /*extras=*/ null
+ ));
return;
}
bindAppFunctionServiceUnchecked(requestInternal, serviceIntent, targetUser,
@@ -171,9 +175,10 @@
}
);
} catch (Exception e) {
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse
- .Builder(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
- getExceptionMessage(e)).build());
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
+ .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
+ e.getMessage(),
+ /*extras=*/ null));
serviceUsageCompleteListener.onCompleted();
}
}
@@ -181,33 +186,32 @@
@Override
public void onFailedToConnect() {
Slog.e(TAG, "Failed to connect to service");
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse
- .Builder(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
- "Failed to connect to AppFunctionService").build());
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
+ .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
+ "Failed to connect to AppFunctionService",
+ /*extras=*/ null));
}
@Override
public void onTimedOut() {
Slog.e(TAG, "Timed out");
safeExecuteAppFunctionCallback.onResult(
- new ExecuteAppFunctionResponse.Builder(
+ ExecuteAppFunctionResponse.newFailure(
ExecuteAppFunctionResponse.RESULT_TIMED_OUT,
- "Binding to AppFunctionService timed out."
- ).build());
+ "Binding to AppFunctionService timed out.",
+ /*extras=*/ null
+ ));
}
}
);
if (!bindServiceResult) {
Slog.e(TAG, "Failed to bind to the AppFunctionService");
- safeExecuteAppFunctionCallback.onResult(new ExecuteAppFunctionResponse.Builder(
+ safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
ExecuteAppFunctionResponse.RESULT_TIMED_OUT,
- "Failed to bind the AppFunctionService."
- ).build());
+ "Failed to bind the AppFunctionService.",
+ /*extras=*/ null
+ ));
}
}
-
- private String getExceptionMessage(Exception exception) {
- return exception.getMessage() == null ? "" : exception.getMessage();
- }
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/SyncAppSearchCallHelper.java b/services/appfunctions/java/com/android/server/appfunctions/SyncAppSearchCallHelper.java
new file mode 100644
index 0000000..c01fe31
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/SyncAppSearchCallHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 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.appfunctions;
+
+import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchManager.SearchContext;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.GetSchemaResponse;
+import android.app.appsearch.SetSchemaRequest;
+import android.app.appsearch.SetSchemaResponse;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Helper class for interacting with a system server local appsearch session synchronously.
+ */
+@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+public class SyncAppSearchCallHelper implements Closeable {
+ private static final String TAG = SyncAppSearchCallHelper.class.getSimpleName();
+ private final Executor mExecutor;
+ private final AppSearchManager mAppSearchManager;
+ private final AndroidFuture<AppSearchResult<AppSearchSession>> mSettableSessionFuture;
+
+ public SyncAppSearchCallHelper(@NonNull AppSearchManager appSearchManager,
+ @NonNull Executor executor,
+ @NonNull SearchContext appSearchContext) {
+ Objects.requireNonNull(appSearchManager);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(appSearchContext);
+
+ mExecutor = executor;
+ mAppSearchManager = appSearchManager;
+ mSettableSessionFuture = new AndroidFuture<>();
+ mAppSearchManager.createSearchSession(
+ appSearchContext, mExecutor, mSettableSessionFuture::complete);
+ }
+
+ /**
+ * Converts a failed app search result codes into an exception.
+ */
+ @NonNull
+ private static Exception failedResultToException(@NonNull AppSearchResult appSearchResult) {
+ return switch (appSearchResult.getResultCode()) {
+ case AppSearchResult.RESULT_INVALID_ARGUMENT -> new IllegalArgumentException(
+ appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_IO_ERROR -> new IOException(
+ appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_SECURITY_ERROR -> new SecurityException(
+ appSearchResult.getErrorMessage());
+ default -> new IllegalStateException(appSearchResult.getErrorMessage());
+ };
+ }
+
+ private AppSearchSession getSession() throws Exception {
+ AppSearchResult<AppSearchSession> sessionResult = mSettableSessionFuture.get();
+ if (!sessionResult.isSuccess()) {
+ throw failedResultToException(sessionResult);
+ }
+ return sessionResult.getResultValue();
+ }
+
+ /**
+ * Gets the schema for a given app search session.
+ */
+ @WorkerThread
+ public GetSchemaResponse getSchema() throws Exception {
+ AndroidFuture<AppSearchResult<GetSchemaResponse>> settableSchemaResponse =
+ new AndroidFuture<>();
+ getSession().getSchema(mExecutor, settableSchemaResponse::complete);
+ AppSearchResult<GetSchemaResponse> schemaResponse = settableSchemaResponse.get();
+ if (schemaResponse.isSuccess()) {
+ return schemaResponse.getResultValue();
+ } else {
+ throw failedResultToException(schemaResponse);
+ }
+ }
+
+ /**
+ * Sets the schema for a given app search session.
+ */
+ @WorkerThread
+ public SetSchemaResponse setSchema(
+ @NonNull SetSchemaRequest setSchemaRequest) throws Exception {
+ AndroidFuture<AppSearchResult<SetSchemaResponse>> settableSchemaResponse =
+ new AndroidFuture<>();
+ getSession().setSchema(
+ setSchemaRequest, mExecutor, mExecutor, settableSchemaResponse::complete);
+ AppSearchResult<SetSchemaResponse> schemaResponse = settableSchemaResponse.get();
+ if (schemaResponse.isSuccess()) {
+ return schemaResponse.getResultValue();
+ } else {
+ throw failedResultToException(schemaResponse);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ getSession().close();
+ } catch (Exception ex) {
+ Slog.e(TAG, "Failed to close app search session", ex);
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/devicepresence/ObservableUuidStore.java b/services/companion/java/com/android/server/companion/devicepresence/ObservableUuidStore.java
index 4678a16..5fd282d 100644
--- a/services/companion/java/com/android/server/companion/devicepresence/ObservableUuidStore.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/ObservableUuidStore.java
@@ -190,7 +190,7 @@
}
mCachedPerUser.set(userId, cachedObservableUuids);
}
- return cachedObservableUuids;
+ return cachedObservableUuids == null ? new ArrayList<>() : cachedObservableUuids;
}
/**
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 47203fb..fbe593f 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -20,6 +20,8 @@
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+import static com.android.server.crashrecovery.CrashRecoveryUtils.dumpCrashRecoveryEvents;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
@@ -44,6 +46,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.IndentingPrintWriter;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.Xml;
@@ -51,7 +54,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -72,6 +74,7 @@
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -1265,18 +1268,21 @@
/** Dump status of every observer in mAllObservers. */
- public void dump(IndentingPrintWriter pw) {
- pw.println("Package Watchdog status");
- pw.increaseIndent();
+ public void dump(PrintWriter pw) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println("Package Watchdog status");
+ ipw.increaseIndent();
synchronized (mLock) {
for (String observerName : mAllObservers.keySet()) {
- pw.println("Observer name: " + observerName);
- pw.increaseIndent();
+ ipw.println("Observer name: " + observerName);
+ ipw.increaseIndent();
ObserverInternal observerInternal = mAllObservers.get(observerName);
- observerInternal.dump(pw);
- pw.decreaseIndent();
+ observerInternal.dump(ipw);
+ ipw.decreaseIndent();
}
}
+ ipw.decreaseIndent();
+ dumpCrashRecoveryEvents(ipw);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index bba97fa..cadceb5 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -18,7 +18,7 @@
import static android.provider.DeviceConfig.Properties;
-import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.crashrecovery.CrashRecoveryUtils.logCrashRecoveryEvent;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -291,13 +291,13 @@
Properties properties = new Properties.Builder(namespaceToReset).build();
try {
if (!DeviceConfig.setProperties(properties)) {
- logCriticalInfo(Log.ERROR, "Failed to clear properties under "
+ logCrashRecoveryEvent(Log.ERROR, "Failed to clear properties under "
+ namespaceToReset
+ ". Running `device_config get_sync_disabled_for_tests` will confirm"
+ " if config-bulk-update is enabled.");
}
} catch (DeviceConfig.BadConfigException exception) {
- logCriticalInfo(Log.WARN, "namespace " + namespaceToReset
+ logCrashRecoveryEvent(Log.WARN, "namespace " + namespaceToReset
+ " is already banned, skip reset.");
}
}
@@ -528,7 +528,7 @@
if (!TextUtils.isEmpty(failedPackage)) {
successMsg += " for package " + failedPackage;
}
- logCriticalInfo(Log.DEBUG, successMsg);
+ logCrashRecoveryEvent(Log.DEBUG, successMsg);
} catch (Throwable t) {
logRescueException(level, failedPackage, t);
}
@@ -687,7 +687,7 @@
if (!TextUtils.isEmpty(failedPackageName)) {
failureMsg += " for package " + failedPackageName;
}
- logCriticalInfo(Log.ERROR, failureMsg + ": " + msg);
+ logCrashRecoveryEvent(Log.ERROR, failureMsg + ": " + msg);
}
private static int mapRescueLevelToUserImpact(int rescueLevel) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 07e5f2e..d86bae1 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -224,6 +224,9 @@
/** Extended timeout for the system server watchdog for vold#partition operation. */
private static final int PARTITION_OPERATION_WATCHDOG_TIMEOUT_MS = 3 * 60 * 1000;
+ private static final Pattern OBB_FILE_PATH = Pattern.compile(
+ "(?i)(^/storage/[^/]+/(?:([0-9]+)/)?Android/obb/)([^/]+)/([^/]+\\.obb)");
+
@GuardedBy("mLock")
private final Set<Integer> mFuseMountedUser = new ArraySet<>();
@@ -3144,7 +3147,9 @@
Objects.requireNonNull(rawPath, "rawPath cannot be null");
Objects.requireNonNull(canonicalPath, "canonicalPath cannot be null");
Objects.requireNonNull(token, "token cannot be null");
- Objects.requireNonNull(obbInfo, "obbIfno cannot be null");
+ Objects.requireNonNull(obbInfo, "obbInfo cannot be null");
+
+ validateObbInfo(obbInfo, rawPath);
final int callingUid = Binder.getCallingUid();
final ObbState obbState = new ObbState(rawPath, canonicalPath,
@@ -3156,6 +3161,34 @@
Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
+ private void validateObbInfo(ObbInfo obbInfo, String rawPath) {
+ String obbFilePath;
+ try {
+ obbFilePath = new File(rawPath).getCanonicalPath();
+ } catch (IOException ex) {
+ throw new RuntimeException("Failed to resolve path" + rawPath + " : " + ex);
+ }
+
+ Matcher matcher = OBB_FILE_PATH.matcher(obbFilePath);
+
+ if (matcher.matches()) {
+ int userId = UserHandle.getUserId(Binder.getCallingUid());
+ String pathUserId = matcher.group(2);
+ String pathPackageName = matcher.group(3);
+ if ((pathUserId != null && Integer.parseInt(pathUserId) != userId)
+ || (pathUserId == null && userId != mCurrentUserId)) {
+ throw new SecurityException(
+ "Path " + obbFilePath + "does not correspond to calling userId " + userId);
+ }
+ if (obbInfo != null && !obbInfo.packageName.equals(pathPackageName)) {
+ throw new SecurityException("Path " + obbFilePath
+ + " does not contain package name " + pathPackageName);
+ }
+ } else {
+ throw new SecurityException("Invalid path to Obb file : " + obbFilePath);
+ }
+ }
+
@Override
public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
Objects.requireNonNull(rawPath, "rawPath cannot be null");
diff --git a/services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java b/services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
new file mode 100644
index 0000000..3eb3380
--- /dev/null
+++ b/services/core/java/com/android/server/crashrecovery/CrashRecoveryUtils.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 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.crashrecovery;
+
+import android.os.Environment;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+/**
+ * Class containing helper methods for the CrashRecoveryModule.
+ *
+ * @hide
+ */
+public class CrashRecoveryUtils {
+ private static final String TAG = "CrashRecoveryUtils";
+ private static final long MAX_CRITICAL_INFO_DUMP_SIZE = 1000 * 1000; // ~1MB
+ private static final Object sFileLock = new Object();
+
+ /** Persist recovery related events in crashrecovery events file.**/
+ public static void logCrashRecoveryEvent(int priority, String msg) {
+ Slog.println(priority, TAG, msg);
+ try {
+ File fname = getCrashRecoveryEventsFile();
+ synchronized (sFileLock) {
+ FileOutputStream out = new FileOutputStream(fname, true);
+ PrintWriter pw = new PrintWriter(out);
+ String dateString = LocalDateTime.now(ZoneId.systemDefault()).toString();
+ pw.println(dateString + ": " + msg);
+ pw.close();
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to log CrashRecoveryEvents " + e.getMessage());
+ }
+ }
+
+ /** Dump recovery related events from crashrecovery events file.**/
+ public static void dumpCrashRecoveryEvents(IndentingPrintWriter pw) {
+ pw.println("CrashRecovery Events: ");
+ pw.increaseIndent();
+ final File file = getCrashRecoveryEventsFile();
+ final long skipSize = file.length() - MAX_CRITICAL_INFO_DUMP_SIZE;
+ synchronized (sFileLock) {
+ try (BufferedReader in = new BufferedReader(new FileReader(file))) {
+ if (skipSize > 0) {
+ in.skip(skipSize);
+ }
+ String line;
+ while ((line = in.readLine()) != null) {
+ pw.println(line);
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to dump CrashRecoveryEvents " + e.getMessage());
+ }
+ }
+ pw.decreaseIndent();
+ }
+
+ private static File getCrashRecoveryEventsFile() {
+ File systemDir = new File(Environment.getDataDirectory(), "system");
+ return new File(systemDir, "crashrecovery-events.txt");
+ }
+}
diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java
index dc611fc..334dda0 100644
--- a/services/core/java/com/android/server/display/DisplayBrightnessState.java
+++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import android.hardware.display.BrightnessInfo;
import android.text.TextUtils;
import com.android.server.display.brightness.BrightnessEvent;
@@ -50,6 +51,8 @@
private final boolean mIsUserInitiatedChange;
+ private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason;
+
private DisplayBrightnessState(Builder builder) {
mBrightness = builder.getBrightness();
mHdrBrightness = builder.getHdrBrightness();
@@ -64,6 +67,7 @@
mBrightnessEvent = builder.getBrightnessEvent();
mBrightnessAdjustmentFlag = builder.getBrightnessAdjustmentFlag();
mIsUserInitiatedChange = builder.isUserInitiatedChange();
+ mBrightnessMaxReason = builder.getBrightnessMaxReason();
}
/**
@@ -159,6 +163,13 @@
return mIsUserInitiatedChange;
}
+ /**
+ * Gets reason for max brightness restriction
+ */
+ public @BrightnessInfo.BrightnessMaxReason int getBrightnessMaxReason() {
+ return mBrightnessMaxReason;
+ }
+
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder("DisplayBrightnessState:");
@@ -180,6 +191,8 @@
.append(Objects.toString(mBrightnessEvent, "null"));
stringBuilder.append("\n mBrightnessAdjustmentFlag:").append(mBrightnessAdjustmentFlag);
stringBuilder.append("\n mIsUserInitiatedChange:").append(mIsUserInitiatedChange);
+ stringBuilder.append("\n mBrightnessMaxReason:")
+ .append(BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason));
return stringBuilder.toString();
}
@@ -212,7 +225,8 @@
== otherState.shouldUpdateScreenBrightnessSetting()
&& Objects.equals(mBrightnessEvent, otherState.getBrightnessEvent())
&& mBrightnessAdjustmentFlag == otherState.getBrightnessAdjustmentFlag()
- && mIsUserInitiatedChange == otherState.isUserInitiatedChange();
+ && mIsUserInitiatedChange == otherState.isUserInitiatedChange()
+ && mBrightnessMaxReason == otherState.getBrightnessMaxReason();
}
@Override
@@ -221,7 +235,7 @@
mShouldUseAutoBrightness, mIsSlowChange, mMaxBrightness, mMinBrightness,
mCustomAnimationRate,
mShouldUpdateScreenBrightnessSetting, mBrightnessEvent, mBrightnessAdjustmentFlag,
- mIsUserInitiatedChange);
+ mIsUserInitiatedChange, mBrightnessMaxReason);
}
/**
@@ -245,12 +259,11 @@
private float mMinBrightness;
private float mCustomAnimationRate = CUSTOM_ANIMATION_RATE_NOT_SET;
private boolean mShouldUpdateScreenBrightnessSetting;
-
private BrightnessEvent mBrightnessEvent;
-
- public int mBrightnessAdjustmentFlag = 0;
-
+ private int mBrightnessAdjustmentFlag = 0;
private boolean mIsUserInitiatedChange;
+ private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason =
+ BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
/**
* Create a builder starting with the values from the specified {@link
@@ -274,6 +287,7 @@
builder.setBrightnessEvent(state.getBrightnessEvent());
builder.setBrightnessAdjustmentFlag(state.getBrightnessAdjustmentFlag());
builder.setIsUserInitiatedChange(state.isUserInitiatedChange());
+ builder.setBrightnessMaxReason(state.getBrightnessMaxReason());
return builder;
}
@@ -506,5 +520,21 @@
mIsUserInitiatedChange = isUserInitiatedChange;
return this;
}
+
+ /**
+ * Gets reason for max brightness restriction
+ */
+ public @BrightnessInfo.BrightnessMaxReason int getBrightnessMaxReason() {
+ return mBrightnessMaxReason;
+ }
+
+ /**
+ * Sets reason for max brightness restriction
+ */
+ public Builder setBrightnessMaxReason(
+ @BrightnessInfo.BrightnessMaxReason int brightnessMaxReason) {
+ mBrightnessMaxReason = brightnessMaxReason;
+ return this;
+ }
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index a887f6d..047eb29 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1588,7 +1588,7 @@
// brightness sources (such as an app override) are not saved to the setting, but should be
// reflected in HBM calculations.
mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState,
- mBrightnessClamperController.getBrightnessMaxReason());
+ clampedState.getBrightnessMaxReason());
// Animate the screen brightness when the screen is on or dozing.
// Skip the animation when the screen is off or suspended.
@@ -1804,7 +1804,7 @@
if (userSetBrightnessChanged
|| newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) {
- logBrightnessEvent(newEvent, unthrottledBrightnessState);
+ logBrightnessEvent(newEvent, unthrottledBrightnessState, clampedState);
}
if (mBrightnessEventRingBuffer != null) {
mBrightnessEventRingBuffer.append(newEvent);
@@ -1997,6 +1997,9 @@
synchronized (mCachedBrightnessInfo) {
float stateMax = state != null ? state.getMaxBrightness() : PowerManager.BRIGHTNESS_MAX;
float stateMin = state != null ? state.getMinBrightness() : PowerManager.BRIGHTNESS_MAX;
+ @BrightnessInfo.BrightnessMaxReason int maxReason =
+ state != null ? state.getBrightnessMaxReason()
+ : BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
final float minBrightness = Math.max(stateMin, Math.min(
mBrightnessRangeController.getCurrentBrightnessMin(), stateMax));
final float maxBrightness = Math.min(
@@ -2023,7 +2026,7 @@
mBrightnessRangeController.getTransitionPoint());
changed |=
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason,
- mBrightnessClamperController.getBrightnessMaxReason());
+ maxReason);
return changed;
}
}
@@ -2926,7 +2929,8 @@
return FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_UNKNOWN;
}
- private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) {
+ private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness,
+ DisplayBrightnessState brightnessState) {
int modifier = event.getReason().getModifier();
int flags = event.getFlags();
// It's easier to check if the brightness is at maximum level using the brightness
@@ -2963,7 +2967,7 @@
event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT,
event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR,
(modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0,
- mBrightnessClamperController.getBrightnessMaxReason(),
+ brightnessState.getBrightnessMaxReason(),
// TODO: (flc) add brightnessMinReason here too.
(modifier & BrightnessReason.MODIFIER_DIMMED) > 0,
event.isRbcEnabled(),
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index 59fffe7..8ee7085 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -161,6 +161,7 @@
builder.setBrightness(cappedBrightness);
builder.setMaxBrightness(mBrightnessCap);
builder.setCustomAnimationRate(mCustomAnimationRate);
+ builder.setBrightnessMaxReason(getBrightnessMaxReason());
if (mClamperType != null) {
builder.getBrightnessReason().addModifier(BrightnessReason.MODIFIER_THROTTLED);
@@ -185,19 +186,8 @@
return builder.build();
}
- /**
- * See BrightnessThrottler.getBrightnessMaxReason:
- * used in:
- * 1) DPC2.CachedBrightnessInfo to determine changes
- * 2) DPC2.logBrightnessEvent
- * 3) HBMController - for logging
- * Method is called in mHandler thread (DisplayControllerHandler), in the same thread
- * recalculateBrightnessCap and DPC2.updatePowerStateInternal are called.
- * Should be moved to DisplayBrightnessState OR derived from DisplayBrightnessState
- * TODO: b/263362199
- */
@BrightnessInfo.BrightnessMaxReason
- public int getBrightnessMaxReason() {
+ private int getBrightnessMaxReason() {
if (mClamperType == null) {
return BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
} else if (mClamperType == Type.THERMAL) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index bbe7b2b..3c7b9d3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -4328,6 +4328,7 @@
HdmiCecLocalDevicePlayback playback = playback();
HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
if (playback != null) {
+ playback.dismissUiOnActiveSourceStatusRecovered();
playback.setActiveSource(playback.getDeviceInfo().getLogicalAddress(), physicalAddress,
caller);
playback.wakeUpIfActiveSource();
diff --git a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
index e3061a7..4135161 100644
--- a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
+++ b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
@@ -69,6 +69,7 @@
mUserManager = mSystemUserContext.getSystemService(UserManager.class);
NotificationChannel channel = new NotificationChannel(BUSN_CHANNEL_ID, BUSN_CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH);
+ channel.setSound(null, null);
mNotificationManager.createNotificationChannel(channel);
setupFocusControlAudioPolicy();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2124ff6..ff9c3e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -60,6 +60,7 @@
import android.app.ApplicationPackageManager;
import android.app.BroadcastOptions;
import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
@@ -3372,8 +3373,10 @@
// TODO(b/261957226): centralise this logic in DPM
boolean isPackageDeviceAdmin(String packageName, int userId) {
final IDevicePolicyManager dpm = getDevicePolicyManager();
+ final DevicePolicyManagerInternal dpmi =
+ mInjector.getLocalService(DevicePolicyManagerInternal.class);
try {
- if (dpm != null) {
+ if (dpm != null && dpmi != null) {
final ComponentName deviceOwnerComponentName = dpm.getDeviceOwnerComponent(
/* callingUserOnly =*/ false);
final String deviceOwnerPackageName = deviceOwnerComponentName == null ? null
@@ -3396,7 +3399,8 @@
if (dpm.packageHasActiveAdmins(packageName, users[i])) {
return true;
}
- if (isDeviceManagementRoleHolder(packageName, users[i])) {
+ if (isDeviceManagementRoleHolder(packageName, users[i])
+ && dpmi.isUserOrganizationManaged(users[i])) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a683a8c..13901c1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1194,11 +1194,11 @@
// Avoid marking pre-created users for removal.
return;
}
- if (ui.lastLoggedInTime == 0 && ui.isGuest() && Resources.getSystem().getBoolean(
- com.android.internal.R.bool.config_guestUserAutoCreated)) {
- // Avoid marking auto-created but not-yet-logged-in guest user for removal. Because a
- // new one will be created anyway, and this one doesn't have any personal data in it yet
- // due to not being logged in.
+ if (ui.lastLoggedInTime == 0) {
+ // Avoid marking a not-yet-logged-in ephemeral user for removal, since it doesn't have
+ // any personal data in it yet due to not being logged in.
+ // This will also avoid marking an auto-created not-yet-logged-in ephemeral guest user
+ // for removal, which would be recreated again later in the boot anyway.
return;
}
// Mark the user for removal.
diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
index f518769..e9cb279 100644
--- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
+++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
@@ -375,24 +375,34 @@
@Nullable String message, boolean shouldCollectMessage, boolean skiProxyOperation,
@NonNull HexFunction<Integer, AttributionSource, Boolean, String, Boolean,
Boolean, SyncNotedAppOp> superImpl) {
- if (attributionSource.getUid() == mDelegateAndOwnerUid && isDelegateOp(code)) {
- final int shellUid = UserHandle.getUid(
- UserHandle.getUserId(attributionSource.getUid()), Process.SHELL_UID);
- final long identity = Binder.clearCallingIdentity();
- try {
- return superImpl.apply(code,
- new AttributionSource(shellUid, Process.INVALID_PID, SHELL_PKG,
- attributionSource.getAttributionTag(),
- attributionSource.getToken(), /*renouncedPermissions*/ null,
- attributionSource.getDeviceId(), attributionSource.getNext()),
- shouldCollectAsyncNotedOp, message, shouldCollectMessage,
- skiProxyOperation);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ if (!isDelegateOp(code)) {
+ return superImpl.apply(code, attributionSource, shouldCollectAsyncNotedOp,
+ message, shouldCollectMessage, skiProxyOperation);
}
- return superImpl.apply(code, attributionSource, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage, skiProxyOperation);
+
+ final int shellUid = UserHandle.getUid(
+ UserHandle.getUserId(attributionSource.getUid()), Process.SHELL_UID);
+ AttributionSource next = attributionSource.getNext();
+ if (next != null && next.getUid() == mDelegateAndOwnerUid) {
+ next = new AttributionSource(shellUid, Process.INVALID_PID, SHELL_PKG,
+ next.getAttributionTag(), next.getToken(), /*renouncedPermissions*/ null,
+ next.getDeviceId(), next.getNext());
+ attributionSource = new AttributionSource(attributionSource, next);
+ }
+ if (attributionSource.getUid() == mDelegateAndOwnerUid) {
+ attributionSource = new AttributionSource(shellUid, Process.INVALID_PID, SHELL_PKG,
+ attributionSource.getAttributionTag(),
+ attributionSource.getToken(), /*renouncedPermissions*/ null,
+ attributionSource.getDeviceId(), attributionSource.getNext());
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return superImpl.apply(code, attributionSource,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+ skiProxyOperation);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index 7ed8972..027e69c 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -17,7 +17,9 @@
package com.android.server.policy;
import static com.android.server.flags.Flags.modifierShortcutManagerMultiuser;
+import static com.android.hardware.input.Flags.modifierShortcutManagerRefactor;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.role.RoleManager;
@@ -37,6 +39,7 @@
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.LongSparseArray;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
@@ -81,8 +84,8 @@
private static final String ATTRIBUTE_SHIFT = "shift";
private static final String ATTRIBUTE_ROLE = "role";
- private final SparseArray<Intent> mIntentShortcuts = new SparseArray<>();
- private final SparseArray<Intent> mShiftShortcuts = new SparseArray<>();
+ private final SparseArray<Intent> mCategoryShortcuts = new SparseArray<>();
+ private final SparseArray<Intent> mShiftCategoryShortcuts = new SparseArray<>();
private final SparseArray<String> mRoleShortcuts = new SparseArray<String>();
private final SparseArray<String> mShiftRoleShortcuts = new SparseArray<String>();
private final Map<String, Intent> mRoleIntents = new HashMap<String, Intent>();
@@ -127,6 +130,7 @@
private boolean mSearchKeyShortcutPending = false;
private boolean mConsumeSearchKeyUp = true;
private UserHandle mCurrentUser;
+ private final Map<Pair<Character, Boolean>, Bookmark> mBookmarks = new HashMap<>();
ModifierShortcutManager(Context context, Handler handler, UserHandle currentUser) {
mContext = context;
@@ -134,7 +138,14 @@
RoleManager rm = mContext.getSystemService(RoleManager.class);
rm.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(),
(String roleName, UserHandle user) -> {
- mRoleIntents.remove(roleName);
+ if (modifierShortcutManagerRefactor()) {
+ mBookmarks.values().stream().filter(b ->
+ b instanceof RoleBookmark
+ && ((RoleBookmark) b).getRole().equals(roleName))
+ .forEach(Bookmark::clearIntent);
+ } else {
+ mRoleIntents.remove(roleName);
+ }
}, UserHandle.ALL);
mCurrentUser = currentUser;
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
@@ -146,8 +157,26 @@
// Role based shortcuts may resolve to different apps for different users
// so clear the cache.
- mRoleIntents.clear();
- mComponentIntents.clear();
+ clearRoleIntents();
+ clearComponentIntents();
+ }
+
+ void clearRoleIntents() {
+ if (modifierShortcutManagerRefactor()) {
+ mBookmarks.values().stream().filter(b ->
+ b instanceof RoleBookmark).forEach(Bookmark::clearIntent);
+ } else {
+ mRoleIntents.clear();
+ }
+ }
+
+ void clearComponentIntents() {
+ if (modifierShortcutManagerRefactor()) {
+ mBookmarks.values().stream().filter(b ->
+ b instanceof ComponentBookmark).forEach(Bookmark::clearIntent);
+ } else {
+ mComponentIntents.clear();
+ }
}
/**
@@ -176,77 +205,111 @@
Intent shortcutIntent = null;
- // If the Shift key is pressed, then search for the shift shortcuts.
- SparseArray<Intent> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts;
-
// First try the exact keycode (with modifiers).
int shortcutChar = kcm.get(keyCode, metaState);
if (shortcutChar == 0) {
return null;
}
- shortcutIntent = shortcutMap.get(shortcutChar);
- if (shortcutIntent == null) {
- // Next try the primary character on that key.
- shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
- if (shortcutChar == 0) {
- return null;
+ if (modifierShortcutManagerRefactor()) {
+ Bookmark bookmark = mBookmarks.get(new Pair<>((char) shortcutChar, isShiftOn));
+ if (bookmark == null) {
+ // Next try the primary character on that key.
+ shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+ if (shortcutChar == 0) {
+ return null;
+ }
+ bookmark = mBookmarks.get(new Pair<>((char) shortcutChar, isShiftOn));
}
+
+ if (bookmark != null) {
+ Context context = modifierShortcutManagerMultiuser()
+ ? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
+ shortcutIntent = bookmark.getIntent(context);
+ } else {
+ Log.d(TAG, "No bookmark found for "
+ + (isShiftOn ? "SHIFT+" : "") + (char) shortcutChar);
+ }
+ } else {
+ // If the Shift key is pressed, then search for the shift shortcuts.
+ SparseArray<Intent> shortcutMap = isShiftOn
+ ? mShiftCategoryShortcuts : mCategoryShortcuts;
shortcutIntent = shortcutMap.get(shortcutChar);
- }
- if (shortcutIntent == null) {
- // Next check for role based shortcut with primary character.
- String role = isShiftOn ? mShiftRoleShortcuts.get(shortcutChar)
- : mRoleShortcuts.get(shortcutChar);
- if (role != null) {
- shortcutIntent = getRoleLaunchIntent(role);
- }
- }
-
- if (modifierShortcutManagerMultiuser()) {
if (shortcutIntent == null) {
- // Next check component based shortcuts with primary character.
- ComponentName component = isShiftOn
- ? mShiftComponentShortcuts.get(shortcutChar)
- : mComponentShortcuts.get(shortcutChar);
- if (component != null) {
- shortcutIntent = resolveComponentNameIntent(component);
+ // Next try the primary character on that key.
+ shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+ if (shortcutChar == 0) {
+ return null;
+ }
+ shortcutIntent = shortcutMap.get(shortcutChar);
+ }
+
+ if (shortcutIntent == null) {
+ // Next check for role based shortcut with primary character.
+ String role = isShiftOn ? mShiftRoleShortcuts.get(shortcutChar)
+ : mRoleShortcuts.get(shortcutChar);
+ if (role != null) {
+ shortcutIntent = getRoleLaunchIntent(role);
+ }
+ }
+
+ if (modifierShortcutManagerMultiuser()) {
+ if (shortcutIntent == null) {
+ // Next check component based shortcuts with primary character.
+ ComponentName component = isShiftOn
+ ? mShiftComponentShortcuts.get(shortcutChar)
+ : mComponentShortcuts.get(shortcutChar);
+ if (component != null) {
+ shortcutIntent = resolveComponentNameIntent(component);
+ }
}
}
}
return shortcutIntent;
}
+ @Nullable
+ private static Intent getRoleLaunchIntent(Context context, String role) {
+ Intent intent = null;
+ RoleManager rm = context.getSystemService(RoleManager.class);
+ PackageManager pm = context.getPackageManager();
+ if (rm.isRoleAvailable(role)) {
+ String rolePackage = rm.getDefaultApplication(role);
+ if (rolePackage != null) {
+ intent = pm.getLaunchIntentForPackage(rolePackage);
+ if (intent != null) {
+ intent.putExtra(EXTRA_ROLE, role);
+
+ } else {
+ Log.w(TAG, "No launch intent for role " + role);
+ }
+ } else {
+ Log.w(TAG, "No default application for role "
+ + role + " user=" + context.getUser());
+ }
+ } else {
+ Log.w(TAG, "Role " + role + " is not available.");
+ }
+ return intent;
+ }
+
+ @Nullable
private Intent getRoleLaunchIntent(String role) {
Intent intent = mRoleIntents.get(role);
if (intent == null) {
Context context = modifierShortcutManagerMultiuser()
? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
- RoleManager rm = context.getSystemService(RoleManager.class);
- PackageManager pm = context.getPackageManager();
- if (rm.isRoleAvailable(role)) {
- String rolePackage = rm.getDefaultApplication(role);
- if (rolePackage != null) {
- intent = pm.getLaunchIntentForPackage(rolePackage);
- if (intent != null) {
- intent.putExtra(EXTRA_ROLE, role);
- mRoleIntents.put(role, intent);
- } else {
- Log.w(TAG, "No launch intent for role " + role);
- }
- } else {
- Log.w(TAG, "No default application for role " + role);
- }
- } else {
- Log.w(TAG, "Role " + role + " is not available.");
+ intent = getRoleLaunchIntent(context, role);
+ if (intent != null) {
+ mRoleIntents.put(role, intent);
}
}
+
return intent;
}
private void loadShortcuts() {
-
try {
XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks);
XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
@@ -276,57 +339,84 @@
continue;
}
- final int shortcutChar = shortcutName.charAt(0);
final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));
- final Intent intent;
- if (packageName != null && className != null) {
- if (roleName != null || categoryName != null) {
- Log.w(TAG, "Cannot specify role or category when package and class"
- + " are present for bookmark packageName=" + packageName
- + " className=" + className + " shortcutChar=" + shortcutChar);
- continue;
+
+ if (modifierShortcutManagerRefactor()) {
+ final char shortcutChar = shortcutName.charAt(0);
+ Bookmark bookmark = null;
+ if (packageName != null && className != null) {
+ bookmark = new ComponentBookmark(
+ shortcutChar, isShiftShortcut, packageName, className);
+ } else if (categoryName != null) {
+ bookmark = new CategoryBookmark(
+ shortcutChar, isShiftShortcut, categoryName);
+ } else if (roleName != null) {
+ bookmark = new RoleBookmark(shortcutChar, isShiftShortcut, roleName);
}
- if (modifierShortcutManagerMultiuser()) {
- ComponentName componentName = new ComponentName(packageName, className);
- if (isShiftShortcut) {
- mShiftComponentShortcuts.put(shortcutChar, componentName);
+ if (bookmark != null) {
+ Log.d(TAG, "adding shortcut " + bookmark + "shift="
+ + isShiftShortcut + " char=" + shortcutChar);
+ mBookmarks.put(new Pair<>(shortcutChar, isShiftShortcut), bookmark);
+ }
+ } else {
+ final int shortcutChar = shortcutName.charAt(0);
+ if (packageName != null && className != null) {
+ if (roleName != null || categoryName != null) {
+ Log.w(TAG, "Cannot specify role or category when package and class"
+ + " are present for bookmark packageName=" + packageName
+ + " className=" + className + " shortcutChar=" + shortcutChar);
+ continue;
+ }
+ if (modifierShortcutManagerMultiuser()) {
+ ComponentName componentName =
+ new ComponentName(packageName, className);
+ if (isShiftShortcut) {
+ mShiftComponentShortcuts.put(shortcutChar, componentName);
+ } else {
+ mComponentShortcuts.put(shortcutChar, componentName);
+ }
} else {
- mComponentShortcuts.put(shortcutChar, componentName);
+ Intent intent = resolveComponentNameIntent(packageName, className);
+ if (isShiftShortcut) {
+ mShiftCategoryShortcuts.put(shortcutChar, intent);
+ } else {
+ mCategoryShortcuts.put(shortcutChar, intent);
+ }
+ }
+ continue;
+ } else if (categoryName != null) {
+ if (roleName != null) {
+ Log.w(TAG, "Cannot specify role bookmark when category is present for"
+ + " bookmark shortcutChar=" + shortcutChar
+ + " category= " + categoryName);
+ continue;
+ }
+ Intent intent = Intent.makeMainSelectorActivity(
+ Intent.ACTION_MAIN, categoryName);
+ if (intent == null) {
+ Log.w(TAG, "Null selector intent for " + categoryName);
+ } else {
+ if (isShiftShortcut) {
+ mShiftCategoryShortcuts.put(shortcutChar, intent);
+ } else {
+ mCategoryShortcuts.put(shortcutChar, intent);
+ }
+ }
+ continue;
+ } else if (roleName != null) {
+ // We can't resolve the role at the time of this file being parsed as the
+ // device hasn't finished booting, so we will look it up lazily.
+ if (isShiftShortcut) {
+ mShiftRoleShortcuts.put(shortcutChar, roleName);
+ } else {
+ mRoleShortcuts.put(shortcutChar, roleName);
}
continue;
} else {
- intent = resolveComponentNameIntent(packageName, className);
- }
- } else if (categoryName != null) {
- if (roleName != null) {
- Log.w(TAG, "Cannot specify role bookmark when category is present for"
- + " bookmark shortcutChar=" + shortcutChar
- + " category= " + categoryName);
+ Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
+ + ": missing package/class, category or role attributes");
continue;
}
- intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
- if (intent == null) {
- Log.w(TAG, "Null selector intent for " + categoryName);
- }
- } else if (roleName != null) {
- // We can't resolve the role at the time of this file being parsed as the
- // device hasn't finished booting, so we will look it up lazily.
- if (isShiftShortcut) {
- mShiftRoleShortcuts.put(shortcutChar, roleName);
- } else {
- mRoleShortcuts.put(shortcutChar, roleName);
- }
- continue;
- } else {
- Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
- + ": missing package/class, category or role attributes");
- continue;
- }
-
- if (isShiftShortcut) {
- mShiftShortcuts.put(shortcutChar, intent);
- } else {
- mIntentShortcuts.put(shortcutChar, intent);
}
}
} catch (XmlPullParserException | IOException e) {
@@ -336,21 +426,35 @@
@Nullable
private Intent resolveComponentNameIntent(ComponentName componentName) {
- Intent intent = mComponentIntents.get(componentName);
- if (intent == null) {
- intent = resolveComponentNameIntent(
- componentName.getPackageName(), componentName.getClassName());
- if (intent != null) {
- mComponentIntents.put(componentName, intent);
+ if (modifierShortcutManagerRefactor()) {
+ return null;
+ } else {
+ Intent intent = mComponentIntents.get(componentName);
+ if (intent == null) {
+ intent = resolveComponentNameIntent(
+ componentName.getPackageName(), componentName.getClassName());
+ if (intent != null) {
+ mComponentIntents.put(componentName, intent);
+ }
}
+ return intent;
}
- return intent;
}
@Nullable
private Intent resolveComponentNameIntent(String packageName, String className) {
- Context context = modifierShortcutManagerMultiuser()
- ? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
+ if (modifierShortcutManagerRefactor()) {
+ return null;
+ } else {
+ Context context = modifierShortcutManagerMultiuser()
+ ? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
+ return resolveComponentNameIntent(context, packageName, className);
+ }
+ }
+
+ @Nullable
+ private static Intent resolveComponentNameIntent(
+ Context context, String packageName, String className) {
PackageManager pm = context.getPackageManager();
int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
if (!modifierShortcutManagerMultiuser()) {
@@ -562,64 +666,81 @@
*/
public KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId) {
List<KeyboardShortcutInfo> shortcuts = new ArrayList();
- for (int i = 0; i < mIntentShortcuts.size(); i++) {
- KeyboardShortcutInfo info = shortcutInfoFromIntent(
- (char) (mIntentShortcuts.keyAt(i)), mIntentShortcuts.valueAt(i), false);
- if (info != null) {
- shortcuts.add(info);
- }
- }
-
- for (int i = 0; i < mShiftShortcuts.size(); i++) {
- KeyboardShortcutInfo info = shortcutInfoFromIntent(
- (char) (mShiftShortcuts.keyAt(i)), mShiftShortcuts.valueAt(i), true);
- if (info != null) {
- shortcuts.add(info);
- }
- }
-
- for (int i = 0; i < mRoleShortcuts.size(); i++) {
- String role = mRoleShortcuts.valueAt(i);
- KeyboardShortcutInfo info = shortcutInfoFromIntent(
- (char) (mRoleShortcuts.keyAt(i)), getRoleLaunchIntent(role), false);
- if (info != null) {
- shortcuts.add(info);
- }
- }
-
- for (int i = 0; i < mShiftRoleShortcuts.size(); i++) {
- String role = mShiftRoleShortcuts.valueAt(i);
- KeyboardShortcutInfo info = shortcutInfoFromIntent(
- (char) (mShiftRoleShortcuts.keyAt(i)), getRoleLaunchIntent(role), true);
- if (info != null) {
- shortcuts.add(info);
- }
- }
-
- if (modifierShortcutManagerMultiuser()) {
- for (int i = 0; i < mComponentShortcuts.size(); i++) {
- ComponentName component = mComponentShortcuts.valueAt(i);
+ if (modifierShortcutManagerRefactor()) {
+ for (Bookmark b : mBookmarks.values()) {
KeyboardShortcutInfo info = shortcutInfoFromIntent(
- (char) (mComponentShortcuts.keyAt(i)),
- resolveComponentNameIntent(component),
+ b.getShortcutChar(), b.getIntent(mContext), b.isShift());
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+ } else {
+ for (int i = 0; i < mCategoryShortcuts.size(); i++) {
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mCategoryShortcuts.keyAt(i)),
+ mCategoryShortcuts.valueAt(i),
false);
if (info != null) {
shortcuts.add(info);
}
}
- for (int i = 0; i < mShiftComponentShortcuts.size(); i++) {
- ComponentName component = mShiftComponentShortcuts.valueAt(i);
+ for (int i = 0; i < mShiftCategoryShortcuts.size(); i++) {
KeyboardShortcutInfo info = shortcutInfoFromIntent(
- (char) (mShiftComponentShortcuts.keyAt(i)),
- resolveComponentNameIntent(component),
+ (char) (mShiftCategoryShortcuts.keyAt(i)),
+ mShiftCategoryShortcuts.valueAt(i),
true);
if (info != null) {
shortcuts.add(info);
}
}
- }
+ for (int i = 0; i < mRoleShortcuts.size(); i++) {
+ String role = mRoleShortcuts.valueAt(i);
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mRoleShortcuts.keyAt(i)),
+ getRoleLaunchIntent(role),
+ false);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+
+ for (int i = 0; i < mShiftRoleShortcuts.size(); i++) {
+ String role = mShiftRoleShortcuts.valueAt(i);
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mShiftRoleShortcuts.keyAt(i)),
+ getRoleLaunchIntent(role),
+ true);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+
+ if (modifierShortcutManagerMultiuser()) {
+ for (int i = 0; i < mComponentShortcuts.size(); i++) {
+ ComponentName component = mComponentShortcuts.valueAt(i);
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mComponentShortcuts.keyAt(i)),
+ resolveComponentNameIntent(component),
+ false);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+
+ for (int i = 0; i < mShiftComponentShortcuts.size(); i++) {
+ ComponentName component = mShiftComponentShortcuts.valueAt(i);
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(
+ (char) (mShiftComponentShortcuts.keyAt(i)),
+ resolveComponentNameIntent(component),
+ true);
+ if (info != null) {
+ shortcuts.add(info);
+ }
+ }
+ }
+ }
return new KeyboardShortcutGroup(
mContext.getString(R.string.keyboard_shortcut_group_applications),
shortcuts);
@@ -800,57 +921,171 @@
void dump(String prefix, PrintWriter pw) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", prefix);
ipw.println("ModifierShortcutManager shortcuts:");
-
- ipw.increaseIndent();
- ipw.println("Roles");
- ipw.increaseIndent();
- for (int i = 0; i < mRoleShortcuts.size(); i++) {
- String role = mRoleShortcuts.valueAt(i);
- char shortcutChar = (char) mRoleShortcuts.keyAt(i);
- Intent intent = getRoleLaunchIntent(role);
- ipw.println(shortcutChar + " " + role + " " + intent);
- }
-
- for (int i = 0; i < mShiftRoleShortcuts.size(); i++) {
- String role = mShiftRoleShortcuts.valueAt(i);
- char shortcutChar = (char) mShiftRoleShortcuts.keyAt(i);
- Intent intent = getRoleLaunchIntent(role);
- ipw.println("SHIFT+" + shortcutChar + " " + role + " " + intent);
- }
-
- ipw.decreaseIndent();
- ipw.println("Selectors");
- ipw.increaseIndent();
- for (int i = 0; i < mIntentShortcuts.size(); i++) {
- char shortcutChar = (char) mIntentShortcuts.keyAt(i);
- Intent intent = mIntentShortcuts.valueAt(i);
- ipw.println(shortcutChar + " " + intent);
- }
-
- for (int i = 0; i < mShiftShortcuts.size(); i++) {
- char shortcutChar = (char) mShiftShortcuts.keyAt(i);
- Intent intent = mShiftShortcuts.valueAt(i);
- ipw.println("SHIFT+" + shortcutChar + " " + intent);
-
- }
-
- if (modifierShortcutManagerMultiuser()) {
- ipw.decreaseIndent();
- ipw.println("ComponentNames");
+ if (modifierShortcutManagerRefactor()) {
ipw.increaseIndent();
- for (int i = 0; i < mComponentShortcuts.size(); i++) {
- char shortcutChar = (char) mComponentShortcuts.keyAt(i);
- ComponentName component = mComponentShortcuts.valueAt(i);
- Intent intent = resolveComponentNameIntent(component);
- ipw.println(shortcutChar + " " + component + " " + intent);
+ for (Bookmark b : mBookmarks.values()) {
+ boolean isShift = b.isShift();
+ char shortcutChar = b.getShortcutChar();
+ Context context = modifierShortcutManagerMultiuser()
+ ? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
+
+ Intent intent = b.getIntent(context);
+ ipw.print(isShift ? "SHIFT+" : "");
+ ipw.println(shortcutChar + " " + intent);
+ ipw.increaseIndent();
+ ipw.increaseIndent();
+ KeyboardShortcutInfo info = shortcutInfoFromIntent(shortcutChar, intent, isShift);
+ if (info != null) {
+ ipw.println("Resolves to: " + info.getLabel());
+ } else {
+ ipw.println("<No KeyboardShortcutInfo available for this shortcut>");
+ }
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ }
+ } else {
+ ipw.increaseIndent();
+ ipw.println("Roles");
+ ipw.increaseIndent();
+ for (int i = 0; i < mRoleShortcuts.size(); i++) {
+ String role = mRoleShortcuts.valueAt(i);
+ char shortcutChar = (char) mRoleShortcuts.keyAt(i);
+ Intent intent = getRoleLaunchIntent(role);
+ ipw.println(shortcutChar + " " + role + " " + intent);
}
- for (int i = 0; i < mShiftComponentShortcuts.size(); i++) {
- char shortcutChar = (char) mShiftComponentShortcuts.keyAt(i);
- ComponentName component = mShiftComponentShortcuts.valueAt(i);
- Intent intent = resolveComponentNameIntent(component);
- ipw.println("SHIFT+" + shortcutChar + " " + component + " " + intent);
+ for (int i = 0; i < mShiftRoleShortcuts.size(); i++) {
+ String role = mShiftRoleShortcuts.valueAt(i);
+ char shortcutChar = (char) mShiftRoleShortcuts.keyAt(i);
+ Intent intent = getRoleLaunchIntent(role);
+ ipw.println("SHIFT+" + shortcutChar + " " + role + " " + intent);
}
+
+ ipw.decreaseIndent();
+ ipw.println("Selectors");
+ ipw.increaseIndent();
+ for (int i = 0; i < mCategoryShortcuts.size(); i++) {
+ char shortcutChar = (char) mCategoryShortcuts.keyAt(i);
+ Intent intent = mCategoryShortcuts.valueAt(i);
+ ipw.println(shortcutChar + " " + intent);
+ }
+
+ for (int i = 0; i < mShiftCategoryShortcuts.size(); i++) {
+ char shortcutChar = (char) mShiftCategoryShortcuts.keyAt(i);
+ Intent intent = mShiftCategoryShortcuts.valueAt(i);
+ ipw.println("SHIFT+" + shortcutChar + " " + intent);
+
+ }
+
+ if (modifierShortcutManagerMultiuser()) {
+ ipw.decreaseIndent();
+ ipw.println("ComponentNames");
+ ipw.increaseIndent();
+ for (int i = 0; i < mComponentShortcuts.size(); i++) {
+ char shortcutChar = (char) mComponentShortcuts.keyAt(i);
+ ComponentName component = mComponentShortcuts.valueAt(i);
+ Intent intent = resolveComponentNameIntent(component);
+ ipw.println(shortcutChar + " " + component + " " + intent);
+ }
+
+ for (int i = 0; i < mShiftComponentShortcuts.size(); i++) {
+ char shortcutChar = (char) mShiftComponentShortcuts.keyAt(i);
+ ComponentName component = mShiftComponentShortcuts.valueAt(i);
+ Intent intent = resolveComponentNameIntent(component);
+ ipw.println("SHIFT+" + shortcutChar + " " + component + " " + intent);
+ }
+ }
+ }
+ }
+
+ private abstract static class Bookmark {
+ private final char mShortcutChar;
+ private final boolean mShift;
+ protected Intent mIntent;
+
+ Bookmark(char shortcutChar, boolean shift) {
+ mShortcutChar = shortcutChar;
+ mShift = shift;
+ }
+
+ public char getShortcutChar() {
+ return mShortcutChar;
+ }
+
+ public boolean isShift() {
+ return mShift;
+ }
+
+ public abstract Intent getIntent(Context context);
+
+ public void clearIntent() {
+ mIntent = null;
+ }
+
+ }
+
+ private static final class RoleBookmark extends Bookmark {
+ private final String mRole;
+
+ RoleBookmark(char shortcutChar, boolean shift, String role) {
+ super(shortcutChar, shift);
+ mRole = role;
+ }
+
+ public String getRole() {
+ return mRole;
+ }
+
+ @Nullable
+ @Override
+ public Intent getIntent(Context context) {
+ if (mIntent != null) {
+ return mIntent;
+ }
+ mIntent = getRoleLaunchIntent(context, mRole);
+ return mIntent;
+ }
+ }
+
+ private static final class CategoryBookmark extends Bookmark {
+ private final String mCategory;
+
+ CategoryBookmark(char shortcutChar, boolean shift, String category) {
+ super(shortcutChar, shift);
+ mCategory = category;
+ }
+
+ @NonNull
+ @Override
+ public Intent getIntent(Context context) {
+ if (mIntent != null) {
+ return mIntent;
+ }
+
+ mIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, mCategory);
+ return mIntent;
+ }
+ }
+
+ private static final class ComponentBookmark extends Bookmark {
+ private final String mPackageName;
+ private final String mClassName;
+
+ ComponentBookmark(
+ char shortcutChar, boolean shift, String packageName, String className) {
+ super(shortcutChar, shift);
+ mPackageName = packageName;
+ mClassName = className;
+ }
+
+ @Nullable
+ @Override
+ public Intent getIntent(Context context) {
+ if (mIntent != null) {
+ return mIntent;
+ }
+ mIntent = resolveComponentNameIntent(context, mPackageName, mClassName);
+ return mIntent;
}
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 1c786e6..68026ea 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -18,6 +18,8 @@
import static android.content.pm.Flags.provideInfoOfApkInApex;
+import static com.android.server.crashrecovery.CrashRecoveryUtils.logCrashRecoveryEvent;
+
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,6 +42,7 @@
import android.os.SystemProperties;
import android.sysprop.CrashRecoveryProperties;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -532,11 +535,13 @@
private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
@FailureReasons int rollbackReason) {
assertInWorkerThread();
+ String failedPackageName = (failedPackage == null ? null : failedPackage.getPackageName());
Slog.i(TAG, "Rolling back package. RollbackId: " + rollback.getRollbackId()
- + " failedPackage: "
- + (failedPackage == null ? null : failedPackage.getPackageName())
+ + " failedPackage: " + failedPackageName
+ " rollbackReason: " + rollbackReason);
+ logCrashRecoveryEvent(Log.DEBUG, String.format("Rolling back %s. Reason: %s",
+ failedPackageName, rollbackReason));
final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
final String failedPackageToLog;
@@ -724,6 +729,7 @@
}
Slog.i(TAG, "Rolling back all available low impact rollbacks");
+ logCrashRecoveryEvent(Log.DEBUG, "Rolling back all available. Reason: " + rollbackReason);
// Add all rollback ids to mPendingStagedRollbackIds, so that we do not reboot before all
// pending staged rollbacks are handled.
for (RollbackInfo rollback : lowImpactRollbacks) {
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
index 440d251..eb5361c 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/CasResource.java
@@ -26,6 +26,11 @@
* @hide
*/
public class CasResource {
+ /**
+ * Handle of the current resource. Should not be changed and should be aligned with the driver
+ * level implementation.
+ */
+ final int mHandle;
private final int mSystemId;
@@ -39,11 +44,16 @@
private Map<Integer, Integer> mOwnerClientIdsToSessionNum = new HashMap<>();
CasResource(Builder builder) {
+ this.mHandle = builder.mHandle;
this.mSystemId = builder.mSystemId;
this.mMaxSessionNum = builder.mMaxSessionNum;
this.mAvailableSessionNum = builder.mMaxSessionNum;
}
+ public int getHandle() {
+ return mHandle;
+ }
+
public int getSystemId() {
return mSystemId;
}
@@ -136,10 +146,12 @@
*/
public static class Builder {
+ private final int mHandle;
private int mSystemId;
protected int mMaxSessionNum;
- Builder(int systemId) {
+ Builder(int handle, int systemId) {
+ this.mHandle = handle;
this.mSystemId = systemId;
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java b/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java
index 31149f3..5cef729 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/CiCamResource.java
@@ -42,8 +42,8 @@
* Builder class for {@link CiCamResource}.
*/
public static class Builder extends CasResource.Builder {
- Builder(int systemId) {
- super(systemId);
+ Builder(int handle, int systemId) {
+ super(handle, systemId);
}
/**
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 0afb049..9229f7f 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -203,13 +203,7 @@
@Override
public void unregisterClientProfile(int clientId) throws RemoteException {
enforceTrmAccessPermission("unregisterClientProfile");
- synchronized (mLock) {
- if (!checkClientExists(clientId)) {
- Slog.e(TAG, "Unregistering non exists client:" + clientId);
- return;
- }
- unregisterClientProfileInternal(clientId);
- }
+ unregisterClientProfileInternal(clientId);
}
@Override
@@ -291,20 +285,7 @@
Slog.e(TAG, "frontendHandle can't be null");
return false;
}
- synchronized (mLock) {
- if (!checkClientExists(request.clientId)) {
- Slog.e(TAG, "Request frontend from unregistered client: "
- + request.clientId);
- return false;
- }
- // If the request client is holding or sharing a frontend, throw an exception.
- if (!getClientProfile(request.clientId).getInUseFrontendHandles().isEmpty()) {
- Slog.e(TAG, "Release frontend before requesting another one. Client id: "
- + request.clientId);
- return false;
- }
- return requestFrontendInternal(request, frontendHandle);
- }
+ return requestFrontendInternal(request, frontendHandle);
}
@Override
@@ -376,13 +357,7 @@
if (demuxHandle == null) {
throw new RemoteException("demuxHandle can't be null");
}
- synchronized (mLock) {
- if (!checkClientExists(request.clientId)) {
- throw new RemoteException("Request demux from unregistered client:"
- + request.clientId);
- }
- return requestDemuxInternal(request, demuxHandle);
- }
+ return requestDemuxInternal(request, demuxHandle);
}
@Override
@@ -409,13 +384,7 @@
if (casSessionHandle == null) {
throw new RemoteException("casSessionHandle can't be null");
}
- synchronized (mLock) {
- if (!checkClientExists(request.clientId)) {
- throw new RemoteException("Request cas from unregistered client:"
- + request.clientId);
- }
- return requestCasSessionInternal(request, casSessionHandle);
- }
+ return requestCasSessionInternal(request, casSessionHandle);
}
@Override
@@ -425,13 +394,7 @@
if (ciCamHandle == null) {
throw new RemoteException("ciCamHandle can't be null");
}
- synchronized (mLock) {
- if (!checkClientExists(request.clientId)) {
- throw new RemoteException("Request ciCam from unregistered client:"
- + request.clientId);
- }
- return requestCiCamInternal(request, ciCamHandle);
- }
+ return requestCiCamInternal(request, ciCamHandle);
}
@Override
@@ -442,42 +405,14 @@
if (lnbHandle == null) {
throw new RemoteException("lnbHandle can't be null");
}
- synchronized (mLock) {
- if (!checkClientExists(request.clientId)) {
- throw new RemoteException("Request lnb from unregistered client:"
- + request.clientId);
- }
- return requestLnbInternal(request, lnbHandle);
- }
+ return requestLnbInternal(request, lnbHandle);
}
@Override
public void releaseFrontend(int frontendHandle, int clientId) throws RemoteException {
enforceTunerAccessPermission("releaseFrontend");
enforceTrmAccessPermission("releaseFrontend");
- if (!validateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND,
- frontendHandle)) {
- throw new RemoteException("frontendHandle can't be invalid");
- }
- synchronized (mLock) {
- if (!checkClientExists(clientId)) {
- throw new RemoteException("Release frontend from unregistered client:"
- + clientId);
- }
- FrontendResource fe = getFrontendResource(frontendHandle);
- if (fe == null) {
- throw new RemoteException("Releasing frontend does not exist.");
- }
- int ownerClientId = fe.getOwnerClientId();
- ClientProfile ownerProfile = getClientProfile(ownerClientId);
- if (ownerClientId != clientId
- && (ownerProfile != null
- && !ownerProfile.getShareFeClientIds().contains(clientId))) {
- throw new RemoteException(
- "Client is not the current owner of the releasing fe.");
- }
- releaseFrontendInternal(fe, clientId);
- }
+ releaseFrontendInternal(frontendHandle, clientId);
}
@Override
@@ -746,17 +681,23 @@
@VisibleForTesting
protected void unregisterClientProfileInternal(int clientId) {
- if (DEBUG) {
- Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
- }
- removeClientProfile(clientId);
- // Remove the Media Resource Manager callingPid to tvAppId mapping
- if (mMediaResourceManager != null) {
- try {
- mMediaResourceManager.overridePid(Binder.getCallingPid(), -1);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not overridePid in resourceManagerSercice when unregister,"
- + " remote exception: " + e);
+ synchronized (mLock) {
+ if (!checkClientExists(clientId)) {
+ Slog.e(TAG, "Unregistering non exists client:" + clientId);
+ return;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
+ }
+ removeClientProfile(clientId);
+ // Remove the Media Resource Manager callingPid to tvAppId mapping
+ if (mMediaResourceManager != null) {
+ try {
+ mMediaResourceManager.overridePid(Binder.getCallingPid(), -1);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not overridePid in resourceManagerSercice when unregister,"
+ + " remote exception: " + e);
+ }
}
}
}
@@ -992,10 +933,14 @@
return;
}
// Add the new Cas Resource.
- cas = new CasResource.Builder(casSystemId)
+ int casSessionHandle = generateResourceHandle(
+ TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, casSystemId);
+ cas = new CasResource.Builder(casSessionHandle, casSystemId)
.maxSessionNum(maxSessionNum)
.build();
- ciCam = new CiCamResource.Builder(casSystemId)
+ int ciCamHandle = generateResourceHandle(
+ TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, casSystemId);
+ ciCam = new CiCamResource.Builder(ciCamHandle, casSystemId)
.maxSessionNum(maxSessionNum)
.build();
addCasResource(cas);
@@ -1007,86 +952,120 @@
if (DEBUG) {
Slog.d(TAG, "requestFrontend(request=" + request + ")");
}
-
- frontendHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- ClientProfile requestClient = getClientProfile(request.clientId);
- // TODO: check if this is really needed
- if (requestClient == null) {
+ int[] reclaimOwnerId = new int[1];
+ if (!claimFrontend(request, frontendHandle, reclaimOwnerId)) {
return false;
}
- clientPriorityUpdateOnRequest(requestClient);
- int grantingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- int inUseLowestPriorityFrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- // Priority max value is 1000
- int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
- boolean isRequestFromSameProcess = false;
- // If the desired frontend id was specified, we only need to check the frontend.
- boolean hasDesiredFrontend = request.desiredId != TunerFrontendRequest.DEFAULT_DESIRED_ID;
- for (FrontendResource fr : getFrontendResources().values()) {
- int frontendId = getResourceIdFromHandle(fr.getHandle());
- if (fr.getType() == request.frontendType
- && (!hasDesiredFrontend || frontendId == request.desiredId)) {
- if (!fr.isInUse()) {
- // Unused resource cannot be acquired if the max is already reached, but
- // TRM still has to look for the reclaim candidate
- if (isFrontendMaxNumUseReached(request.frontendType)) {
- continue;
- }
- // Grant unused frontend with no exclusive group members first.
- if (fr.getExclusiveGroupMemberFeHandles().isEmpty()) {
- grantingFrontendHandle = fr.getHandle();
- break;
- } else if (grantingFrontendHandle
- == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
- // Grant the unused frontend with lower id first if all the unused
- // frontends have exclusive group members.
- grantingFrontendHandle = fr.getHandle();
- }
- } else if (grantingFrontendHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
- // Record the frontend id with the lowest client priority among all the
- // in use frontends when no available frontend has been found.
- int priority = getFrontendHighestClientPriority(fr.getOwnerClientId());
- if (currentLowestPriority > priority) {
- // we need to check the max used num if the target frontend type is not
- // currently in primary use (and simply blocked due to exclusive group)
- ClientProfile targetOwnerProfile = getClientProfile(fr.getOwnerClientId());
- int primaryFeId = targetOwnerProfile.getPrimaryFrontend();
- FrontendResource primaryFe = getFrontendResource(primaryFeId);
- if (fr.getType() != primaryFe.getType()
- && isFrontendMaxNumUseReached(fr.getType())) {
+ if (frontendHandle[0] == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ return false;
+ }
+ if (reclaimOwnerId[0] != INVALID_CLIENT_ID) {
+ if (!reclaimResource(reclaimOwnerId[0], TunerResourceManager
+ .TUNER_RESOURCE_TYPE_FRONTEND)) {
+ return false;
+ }
+ synchronized (mLock) {
+ if (getFrontendResource(frontendHandle[0]).isInUse()) {
+ Slog.e(TAG, "Reclaimed frontend still in use");
+ return false;
+ }
+ updateFrontendClientMappingOnNewGrant(frontendHandle[0], request.clientId);
+ }
+ }
+ return true;
+ }
+
+ protected boolean claimFrontend(
+ TunerFrontendRequest request,
+ int[] frontendHandle,
+ int[] reclaimOwnerId
+ ) {
+ frontendHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ reclaimOwnerId[0] = INVALID_CLIENT_ID;
+ synchronized (mLock) {
+ if (!checkClientExists(request.clientId)) {
+ Slog.e(TAG, "Request frontend from unregistered client: "
+ + request.clientId);
+ return false;
+ }
+ // If the request client is holding or sharing a frontend, throw an exception.
+ if (!getClientProfile(request.clientId).getInUseFrontendHandles().isEmpty()) {
+ Slog.e(TAG, "Release frontend before requesting another one. Client id: "
+ + request.clientId);
+ return false;
+ }
+ ClientProfile requestClient = getClientProfile(request.clientId);
+ clientPriorityUpdateOnRequest(requestClient);
+ FrontendResource grantingFrontend = null;
+ FrontendResource inUseLowestPriorityFrontend = null;
+ // Priority max value is 1000
+ int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
+ boolean isRequestFromSameProcess = false;
+ // If the desired frontend id was specified, we only need to check the frontend.
+ boolean hasDesiredFrontend = request.desiredId != TunerFrontendRequest
+ .DEFAULT_DESIRED_ID;
+ for (FrontendResource fr : getFrontendResources().values()) {
+ int frontendId = getResourceIdFromHandle(fr.getHandle());
+ if (fr.getType() == request.frontendType
+ && (!hasDesiredFrontend || frontendId == request.desiredId)) {
+ if (!fr.isInUse()) {
+ // Unused resource cannot be acquired if the max is already reached, but
+ // TRM still has to look for the reclaim candidate
+ if (isFrontendMaxNumUseReached(request.frontendType)) {
continue;
}
- // update the target frontend
- inUseLowestPriorityFrHandle = fr.getHandle();
- currentLowestPriority = priority;
- isRequestFromSameProcess = (requestClient.getProcessId()
- == (getClientProfile(fr.getOwnerClientId())).getProcessId());
+ // Grant unused frontend with no exclusive group members first.
+ if (fr.getExclusiveGroupMemberFeHandles().isEmpty()) {
+ grantingFrontend = fr;
+ break;
+ } else if (grantingFrontend == null) {
+ // Grant the unused frontend with lower id first if all the unused
+ // frontends have exclusive group members.
+ grantingFrontend = fr;
+ }
+ } else if (grantingFrontend == null) {
+ // Record the frontend id with the lowest client priority among all the
+ // in use frontends when no available frontend has been found.
+ int priority = getFrontendHighestClientPriority(fr.getOwnerClientId());
+ if (currentLowestPriority > priority) {
+ // we need to check the max used num if the target frontend type is not
+ // currently in primary use (and simply blocked due to exclusive group)
+ ClientProfile targetOwnerProfile =
+ getClientProfile(fr.getOwnerClientId());
+ int primaryFeId = targetOwnerProfile.getPrimaryFrontend();
+ FrontendResource primaryFe = getFrontendResource(primaryFeId);
+ if (fr.getType() != primaryFe.getType()
+ && isFrontendMaxNumUseReached(fr.getType())) {
+ continue;
+ }
+ // update the target frontend
+ inUseLowestPriorityFrontend = fr;
+ currentLowestPriority = priority;
+ isRequestFromSameProcess = (requestClient.getProcessId()
+ == (getClientProfile(fr.getOwnerClientId())).getProcessId());
+ }
}
}
}
- }
- // Grant frontend when there is unused resource.
- if (grantingFrontendHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
- frontendHandle[0] = grantingFrontendHandle;
- updateFrontendClientMappingOnNewGrant(grantingFrontendHandle, request.clientId);
- return true;
- }
-
- // When all the resources are occupied, grant the lowest priority resource if the
- // request client has higher priority.
- if (inUseLowestPriorityFrHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE
- && ((requestClient.getPriority() > currentLowestPriority) || (
- (requestClient.getPriority() == currentLowestPriority) && isRequestFromSameProcess))) {
- if (!reclaimResource(
- getFrontendResource(inUseLowestPriorityFrHandle).getOwnerClientId(),
- TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
- return false;
+ // Grant frontend when there is unused resource.
+ if (grantingFrontend != null) {
+ updateFrontendClientMappingOnNewGrant(grantingFrontend.getHandle(),
+ request.clientId);
+ frontendHandle[0] = grantingFrontend.getHandle();
+ return true;
}
- frontendHandle[0] = inUseLowestPriorityFrHandle;
- updateFrontendClientMappingOnNewGrant(
- inUseLowestPriorityFrHandle, request.clientId);
- return true;
+
+ // When all the resources are occupied, grant the lowest priority resource if the
+ // request client has higher priority.
+ if (inUseLowestPriorityFrontend != null
+ && ((requestClient.getPriority() > currentLowestPriority)
+ || ((requestClient.getPriority() == currentLowestPriority)
+ && isRequestFromSameProcess))) {
+ frontendHandle[0] = inUseLowestPriorityFrontend.getHandle();
+ reclaimOwnerId[0] = inUseLowestPriorityFrontend.getOwnerClientId();
+ return true;
+ }
}
return false;
@@ -1192,165 +1171,257 @@
}
@VisibleForTesting
- protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle) {
+ protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle)
+ throws RemoteException {
if (DEBUG) {
Slog.d(TAG, "requestLnb(request=" + request + ")");
}
-
- lnbHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- ClientProfile requestClient = getClientProfile(request.clientId);
- clientPriorityUpdateOnRequest(requestClient);
- int grantingLnbHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- int inUseLowestPriorityLnbHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- // Priority max value is 1000
- int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
- boolean isRequestFromSameProcess = false;
- for (LnbResource lnb : getLnbResources().values()) {
- if (!lnb.isInUse()) {
- // Grant the unused lnb with lower handle first
- grantingLnbHandle = lnb.getHandle();
- break;
- } else {
- // Record the lnb id with the lowest client priority among all the
- // in use lnb when no available lnb has been found.
- int priority = updateAndGetOwnerClientPriority(lnb.getOwnerClientId());
- if (currentLowestPriority > priority) {
- inUseLowestPriorityLnbHandle = lnb.getHandle();
- currentLowestPriority = priority;
- isRequestFromSameProcess = (requestClient.getProcessId()
- == (getClientProfile(lnb.getOwnerClientId())).getProcessId());
- }
- }
+ int[] reclaimOwnerId = new int[1];
+ if (!claimLnb(request, lnbHandle, reclaimOwnerId)) {
+ return false;
}
-
- // Grant Lnb when there is unused resource.
- if (grantingLnbHandle > -1) {
- lnbHandle[0] = grantingLnbHandle;
- updateLnbClientMappingOnNewGrant(grantingLnbHandle, request.clientId);
- return true;
+ if (lnbHandle[0] == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ return false;
}
-
- // When all the resources are occupied, grant the lowest priority resource if the
- // request client has higher priority.
- if (inUseLowestPriorityLnbHandle > TunerResourceManager.INVALID_RESOURCE_HANDLE
- && ((requestClient.getPriority() > currentLowestPriority) || (
- (requestClient.getPriority() == currentLowestPriority) && isRequestFromSameProcess))) {
- if (!reclaimResource(getLnbResource(inUseLowestPriorityLnbHandle).getOwnerClientId(),
+ if (reclaimOwnerId[0] != INVALID_CLIENT_ID) {
+ if (!reclaimResource(reclaimOwnerId[0],
TunerResourceManager.TUNER_RESOURCE_TYPE_LNB)) {
return false;
}
- lnbHandle[0] = inUseLowestPriorityLnbHandle;
- updateLnbClientMappingOnNewGrant(inUseLowestPriorityLnbHandle, request.clientId);
- return true;
+ synchronized (mLock) {
+ if (getLnbResource(lnbHandle[0]).isInUse()) {
+ Slog.e(TAG, "Reclaimed lnb still in use");
+ return false;
+ }
+ updateLnbClientMappingOnNewGrant(lnbHandle[0], request.clientId);
+ }
+ }
+ return true;
+ }
+
+ protected boolean claimLnb(TunerLnbRequest request, int[] lnbHandle, int[] reclaimOwnerId)
+ throws RemoteException {
+ lnbHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ reclaimOwnerId[0] = INVALID_CLIENT_ID;
+ synchronized (mLock) {
+ if (!checkClientExists(request.clientId)) {
+ throw new RemoteException("Request lnb from unregistered client:"
+ + request.clientId);
+ }
+ ClientProfile requestClient = getClientProfile(request.clientId);
+ clientPriorityUpdateOnRequest(requestClient);
+ LnbResource grantingLnb = null;
+ LnbResource inUseLowestPriorityLnb = null;
+ // Priority max value is 1000
+ int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
+ boolean isRequestFromSameProcess = false;
+ for (LnbResource lnb : getLnbResources().values()) {
+ if (!lnb.isInUse()) {
+ // Grant the unused lnb with lower handle first
+ grantingLnb = lnb;
+ break;
+ } else {
+ // Record the lnb id with the lowest client priority among all the
+ // in use lnb when no available lnb has been found.
+ int priority = updateAndGetOwnerClientPriority(lnb.getOwnerClientId());
+ if (currentLowestPriority > priority) {
+ inUseLowestPriorityLnb = lnb;
+ currentLowestPriority = priority;
+ isRequestFromSameProcess = (requestClient.getProcessId()
+ == (getClientProfile(lnb.getOwnerClientId())).getProcessId());
+ }
+ }
+ }
+
+ // Grant Lnb when there is unused resource.
+ if (grantingLnb != null) {
+ updateLnbClientMappingOnNewGrant(grantingLnb.getHandle(), request.clientId);
+ lnbHandle[0] = grantingLnb.getHandle();
+ return true;
+ }
+
+ // When all the resources are occupied, grant the lowest priority resource if the
+ // request client has higher priority.
+ if (inUseLowestPriorityLnb != null
+ && ((requestClient.getPriority() > currentLowestPriority) || (
+ (requestClient.getPriority() == currentLowestPriority)
+ && isRequestFromSameProcess))) {
+ lnbHandle[0] = inUseLowestPriorityLnb.getHandle();
+ reclaimOwnerId[0] = inUseLowestPriorityLnb.getOwnerClientId();
+ return true;
+ }
}
return false;
}
@VisibleForTesting
- protected boolean requestCasSessionInternal(CasSessionRequest request, int[] casSessionHandle) {
+ protected boolean requestCasSessionInternal(CasSessionRequest request, int[] casSessionHandle)
+ throws RemoteException {
if (DEBUG) {
Slog.d(TAG, "requestCasSession(request=" + request + ")");
}
- CasResource cas = getCasResource(request.casSystemId);
- // Unregistered Cas System is treated as having unlimited sessions.
- if (cas == null) {
- cas = new CasResource.Builder(request.casSystemId)
- .maxSessionNum(Integer.MAX_VALUE)
- .build();
- addCasResource(cas);
+ int[] reclaimOwnerId = new int[1];
+ if (!claimCasSession(request, casSessionHandle, reclaimOwnerId)) {
+ return false;
}
- casSessionHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- ClientProfile requestClient = getClientProfile(request.clientId);
- clientPriorityUpdateOnRequest(requestClient);
- int lowestPriorityOwnerId = -1;
- // Priority max value is 1000
- int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
- boolean isRequestFromSameProcess = false;
- if (!cas.isFullyUsed()) {
- casSessionHandle[0] = generateResourceHandle(
- TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, cas.getSystemId());
- updateCasClientMappingOnNewGrant(request.casSystemId, request.clientId);
- return true;
+ if (casSessionHandle[0] == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ return false;
}
- for (int ownerId : cas.getOwnerClientIds()) {
- // Record the client id with lowest priority that is using the current Cas system.
- int priority = updateAndGetOwnerClientPriority(ownerId);
- if (currentLowestPriority > priority) {
- lowestPriorityOwnerId = ownerId;
- currentLowestPriority = priority;
- isRequestFromSameProcess = (requestClient.getProcessId()
- == (getClientProfile(ownerId)).getProcessId());
- }
- }
-
- // When all the Cas sessions are occupied, reclaim the lowest priority client if the
- // request client has higher priority.
- if (lowestPriorityOwnerId > -1 && ((requestClient.getPriority() > currentLowestPriority)
- || ((requestClient.getPriority() == currentLowestPriority) && isRequestFromSameProcess))) {
- if (!reclaimResource(lowestPriorityOwnerId,
+ if (reclaimOwnerId[0] != INVALID_CLIENT_ID) {
+ if (!reclaimResource(reclaimOwnerId[0],
TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION)) {
return false;
}
- casSessionHandle[0] = generateResourceHandle(
- TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, cas.getSystemId());
- updateCasClientMappingOnNewGrant(request.casSystemId, request.clientId);
- return true;
+ synchronized (mLock) {
+ if (getCasResource(request.casSystemId).isFullyUsed()) {
+ Slog.e(TAG, "Reclaimed cas still fully used");
+ return false;
+ }
+ updateCasClientMappingOnNewGrant(request.casSystemId, request.clientId);
+ }
}
+ return true;
+ }
+
+ protected boolean claimCasSession(CasSessionRequest request, int[] casSessionHandle,
+ int[] reclaimOwnerId) throws RemoteException {
+ casSessionHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ reclaimOwnerId[0] = INVALID_CLIENT_ID;
+ synchronized (mLock) {
+ if (!checkClientExists(request.clientId)) {
+ throw new RemoteException("Request cas from unregistered client:"
+ + request.clientId);
+ }
+ CasResource cas = getCasResource(request.casSystemId);
+ // Unregistered Cas System is treated as having unlimited sessions.
+ if (cas == null) {
+ int resourceHandle = generateResourceHandle(
+ TunerResourceManager.TUNER_RESOURCE_TYPE_CAS_SESSION, request.clientId);
+ cas = new CasResource.Builder(resourceHandle, request.casSystemId)
+ .maxSessionNum(Integer.MAX_VALUE)
+ .build();
+ addCasResource(cas);
+ }
+ ClientProfile requestClient = getClientProfile(request.clientId);
+ clientPriorityUpdateOnRequest(requestClient);
+ int lowestPriorityOwnerId = INVALID_CLIENT_ID;
+ // Priority max value is 1000
+ int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
+ boolean isRequestFromSameProcess = false;
+ if (!cas.isFullyUsed()) {
+ updateCasClientMappingOnNewGrant(request.casSystemId, request.clientId);
+ casSessionHandle[0] = cas.getHandle();
+ return true;
+ }
+ for (int ownerId : cas.getOwnerClientIds()) {
+ // Record the client id with lowest priority that is using the current Cas system.
+ int priority = updateAndGetOwnerClientPriority(ownerId);
+ if (currentLowestPriority > priority) {
+ lowestPriorityOwnerId = ownerId;
+ currentLowestPriority = priority;
+ isRequestFromSameProcess = (requestClient.getProcessId()
+ == (getClientProfile(ownerId)).getProcessId());
+ }
+ }
+
+ // When all the Cas sessions are occupied, reclaim the lowest priority client if the
+ // request client has higher priority.
+ if (lowestPriorityOwnerId != INVALID_CLIENT_ID
+ && ((requestClient.getPriority() > currentLowestPriority)
+ || ((requestClient.getPriority() == currentLowestPriority)
+ && isRequestFromSameProcess))) {
+ casSessionHandle[0] = cas.getHandle();
+ reclaimOwnerId[0] = lowestPriorityOwnerId;
+ return true;
+ }
+ }
+
return false;
}
@VisibleForTesting
- protected boolean requestCiCamInternal(TunerCiCamRequest request, int[] ciCamHandle) {
+ protected boolean requestCiCamInternal(TunerCiCamRequest request, int[] ciCamHandle)
+ throws RemoteException {
if (DEBUG) {
Slog.d(TAG, "requestCiCamInternal(TunerCiCamRequest=" + request + ")");
}
- CiCamResource ciCam = getCiCamResource(request.ciCamId);
- // Unregistered Cas System is treated as having unlimited sessions.
- if (ciCam == null) {
- ciCam = new CiCamResource.Builder(request.ciCamId)
- .maxSessionNum(Integer.MAX_VALUE)
- .build();
- addCiCamResource(ciCam);
+ int[] reclaimOwnerId = new int[1];
+ if (!claimCiCam(request, ciCamHandle, reclaimOwnerId)) {
+ return false;
}
- ciCamHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- ClientProfile requestClient = getClientProfile(request.clientId);
- clientPriorityUpdateOnRequest(requestClient);
- int lowestPriorityOwnerId = -1;
- // Priority max value is 1000
- int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
- boolean isRequestFromSameProcess = false;
- if (!ciCam.isFullyUsed()) {
- ciCamHandle[0] = generateResourceHandle(
- TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, ciCam.getCiCamId());
- updateCiCamClientMappingOnNewGrant(request.ciCamId, request.clientId);
- return true;
+ if (ciCamHandle[0] == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ return false;
}
- for (int ownerId : ciCam.getOwnerClientIds()) {
- // Record the client id with lowest priority that is using the current Cas system.
- int priority = updateAndGetOwnerClientPriority(ownerId);
- if (currentLowestPriority > priority) {
- lowestPriorityOwnerId = ownerId;
- currentLowestPriority = priority;
- isRequestFromSameProcess = (requestClient.getProcessId()
- == (getClientProfile(ownerId)).getProcessId());
- }
- }
-
- // When all the CiCam sessions are occupied, reclaim the lowest priority client if the
- // request client has higher priority.
- if (lowestPriorityOwnerId > -1 && ((requestClient.getPriority() > currentLowestPriority)
- || ((requestClient.getPriority() == currentLowestPriority)
- && isRequestFromSameProcess))) {
- if (!reclaimResource(lowestPriorityOwnerId,
+ if (reclaimOwnerId[0] != INVALID_CLIENT_ID) {
+ if (!reclaimResource(reclaimOwnerId[0],
TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM)) {
return false;
}
- ciCamHandle[0] = generateResourceHandle(
- TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, ciCam.getCiCamId());
- updateCiCamClientMappingOnNewGrant(request.ciCamId, request.clientId);
- return true;
+ synchronized (mLock) {
+ if (getCiCamResource(request.ciCamId).isFullyUsed()) {
+ Slog.e(TAG, "Reclaimed ciCam still fully used");
+ return false;
+ }
+ updateCiCamClientMappingOnNewGrant(request.ciCamId, request.clientId);
+ }
}
+ return true;
+ }
+
+ protected boolean claimCiCam(TunerCiCamRequest request, int[] ciCamHandle,
+ int[] reclaimOwnerId) throws RemoteException {
+ ciCamHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ reclaimOwnerId[0] = INVALID_CLIENT_ID;
+ synchronized (mLock) {
+ if (!checkClientExists(request.clientId)) {
+ throw new RemoteException("Request ciCam from unregistered client:"
+ + request.clientId);
+ }
+ CiCamResource ciCam = getCiCamResource(request.ciCamId);
+ // Unregistered CiCam is treated as having unlimited sessions.
+ if (ciCam == null) {
+ int resourceHandle = generateResourceHandle(
+ TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND_CICAM, request.ciCamId);
+ ciCam = new CiCamResource.Builder(resourceHandle, request.ciCamId)
+ .maxSessionNum(Integer.MAX_VALUE)
+ .build();
+ addCiCamResource(ciCam);
+ }
+ ClientProfile requestClient = getClientProfile(request.clientId);
+ clientPriorityUpdateOnRequest(requestClient);
+ int lowestPriorityOwnerId = INVALID_CLIENT_ID;
+ // Priority max value is 1000
+ int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
+ boolean isRequestFromSameProcess = false;
+ if (!ciCam.isFullyUsed()) {
+ updateCiCamClientMappingOnNewGrant(request.ciCamId, request.clientId);
+ ciCamHandle[0] = ciCam.getHandle();
+ return true;
+ }
+ for (int ownerId : ciCam.getOwnerClientIds()) {
+ // Record the client id with lowest priority that is using the current CiCam.
+ int priority = updateAndGetOwnerClientPriority(ownerId);
+ if (currentLowestPriority > priority) {
+ lowestPriorityOwnerId = ownerId;
+ currentLowestPriority = priority;
+ isRequestFromSameProcess = (requestClient.getProcessId()
+ == (getClientProfile(ownerId)).getProcessId());
+ }
+ }
+
+ // When all the CiCam sessions are occupied, reclaim the lowest priority client if the
+ // request client has higher priority.
+ if (lowestPriorityOwnerId != INVALID_CLIENT_ID
+ && ((requestClient.getPriority() > currentLowestPriority)
+ || ((requestClient.getPriority() == currentLowestPriority)
+ && isRequestFromSameProcess))) {
+ ciCamHandle[0] = ciCam.getHandle();
+ reclaimOwnerId[0] = lowestPriorityOwnerId;
+ return true;
+ }
+ }
+
return false;
}
@@ -1383,20 +1454,49 @@
}
@VisibleForTesting
- protected void releaseFrontendInternal(FrontendResource fe, int clientId) {
+ protected void releaseFrontendInternal(int frontendHandle, int clientId)
+ throws RemoteException {
if (DEBUG) {
- Slog.d(TAG, "releaseFrontend(id=" + fe.getHandle() + ", clientId=" + clientId + " )");
+ Slog.d(TAG, "releaseFrontend(id=" + frontendHandle + ", clientId=" + clientId + " )");
}
- if (clientId == fe.getOwnerClientId()) {
- ClientProfile ownerClient = getClientProfile(fe.getOwnerClientId());
- if (ownerClient != null) {
- for (int shareOwnerId : ownerClient.getShareFeClientIds()) {
- reclaimResource(shareOwnerId,
- TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
+ if (!validateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND,
+ frontendHandle)) {
+ throw new RemoteException("frontendHandle can't be invalid");
+ }
+ Set<Integer> reclaimedResourceOwnerIds = unclaimFrontend(frontendHandle, clientId);
+ if (reclaimedResourceOwnerIds != null) {
+ for (int shareOwnerId : reclaimedResourceOwnerIds) {
+ reclaimResource(shareOwnerId,
+ TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
+ }
+ }
+ synchronized (mLock) {
+ clearFrontendAndClientMapping(getClientProfile(clientId));
+ }
+ }
+
+ private Set<Integer> unclaimFrontend(int frontendHandle, int clientId) throws RemoteException {
+ Set<Integer> reclaimedResourceOwnerIds = null;
+ synchronized (mLock) {
+ if (!checkClientExists(clientId)) {
+ throw new RemoteException("Release frontend from unregistered client:"
+ + clientId);
+ }
+ FrontendResource fe = getFrontendResource(frontendHandle);
+ if (fe == null) {
+ throw new RemoteException("Releasing frontend does not exist.");
+ }
+ int ownerClientId = fe.getOwnerClientId();
+ ClientProfile ownerProfile = getClientProfile(ownerClientId);
+ if (ownerClientId == clientId) {
+ reclaimedResourceOwnerIds = ownerProfile.getShareFeClientIds();
+ } else {
+ if (!ownerProfile.getShareFeClientIds().contains(clientId)) {
+ throw new RemoteException("Client is not a sharee of the releasing fe.");
}
}
}
- clearFrontendAndClientMapping(getClientProfile(clientId));
+ return reclaimedResourceOwnerIds;
}
@VisibleForTesting
@@ -1432,103 +1532,129 @@
}
@VisibleForTesting
- protected boolean requestDemuxInternal(TunerDemuxRequest request, int[] demuxHandle) {
+ public boolean requestDemuxInternal(@NonNull TunerDemuxRequest request,
+ @NonNull int[] demuxHandle) throws RemoteException {
if (DEBUG) {
Slog.d(TAG, "requestDemux(request=" + request + ")");
}
-
- // For Tuner 2.0 and below or any HW constraint devices that are unable to support
- // ITuner.openDemuxById(), demux resources are not really managed under TRM and
- // mDemuxResources.size() will be zero
- if (mDemuxResources.size() == 0) {
- // There are enough Demux resources, so we don't manage Demux in R.
- demuxHandle[0] =
- generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, 0);
- return true;
- }
-
- demuxHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- ClientProfile requestClient = getClientProfile(request.clientId);
-
- if (requestClient == null) {
+ int[] reclaimOwnerId = new int[1];
+ if (!claimDemux(request, demuxHandle, reclaimOwnerId)) {
return false;
}
+ if (demuxHandle[0] == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ return false;
+ }
+ if (reclaimOwnerId[0] != INVALID_CLIENT_ID) {
+ if (!reclaimResource(reclaimOwnerId[0],
+ TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX)) {
+ return false;
+ }
+ synchronized (mLock) {
+ if (getDemuxResource(demuxHandle[0]).isInUse()) {
+ Slog.e(TAG, "Reclaimed demux still in use");
+ return false;
+ }
+ updateDemuxClientMappingOnNewGrant(demuxHandle[0], request.clientId);
+ }
+ }
+ return true;
+ }
- clientPriorityUpdateOnRequest(requestClient);
- int grantingDemuxHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- int inUseLowestPriorityDrHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
- // Priority max value is 1000
- int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
- boolean isRequestFromSameProcess = false;
- // If the desired demux id was specified, we only need to check the demux.
- boolean hasDesiredDemuxCap = request.desiredFilterTypes
- != DemuxFilterMainType.UNDEFINED;
- int smallestNumOfSupportedCaps = Integer.SIZE + 1;
- int smallestNumOfSupportedCapsInUse = Integer.SIZE + 1;
- for (DemuxResource dr : getDemuxResources().values()) {
- if (!hasDesiredDemuxCap || dr.hasSufficientCaps(request.desiredFilterTypes)) {
- if (!dr.isInUse()) {
- int numOfSupportedCaps = dr.getNumOfCaps();
+ protected boolean claimDemux(TunerDemuxRequest request, int[] demuxHandle, int[] reclaimOwnerId)
+ throws RemoteException {
+ demuxHandle[0] = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+ reclaimOwnerId[0] = INVALID_CLIENT_ID;
+ synchronized (mLock) {
+ if (!checkClientExists(request.clientId)) {
+ throw new RemoteException("Request demux from unregistered client:"
+ + request.clientId);
+ }
- // look for the demux with minimum caps supporting the desired caps
- if (smallestNumOfSupportedCaps > numOfSupportedCaps) {
- smallestNumOfSupportedCaps = numOfSupportedCaps;
- grantingDemuxHandle = dr.getHandle();
- }
- } else if (grantingDemuxHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) {
- // Record the demux id with the lowest client priority among all the
- // in use demuxes when no availabledemux has been found.
- int priority = updateAndGetOwnerClientPriority(dr.getOwnerClientId());
- if (currentLowestPriority >= priority) {
+ // For Tuner 2.0 and below or any HW constraint devices that are unable to support
+ // ITuner.openDemuxById(), demux resources are not really managed under TRM and
+ // mDemuxResources.size() will be zero
+ if (mDemuxResources.size() == 0) {
+ // There are enough Demux resources, so we don't manage Demux in R.
+ demuxHandle[0] =
+ generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, 0);
+ return true;
+ }
+
+ ClientProfile requestClient = getClientProfile(request.clientId);
+ if (requestClient == null) {
+ return false;
+ }
+ clientPriorityUpdateOnRequest(requestClient);
+ DemuxResource grantingDemux = null;
+ DemuxResource inUseLowestPriorityDemux = null;
+ // Priority max value is 1000
+ int currentLowestPriority = MAX_CLIENT_PRIORITY + 1;
+ boolean isRequestFromSameProcess = false;
+ // If the desired demux id was specified, we only need to check the demux.
+ boolean hasDesiredDemuxCap = request.desiredFilterTypes
+ != DemuxFilterMainType.UNDEFINED;
+ int smallestNumOfSupportedCaps = Integer.SIZE + 1;
+ int smallestNumOfSupportedCapsInUse = Integer.SIZE + 1;
+ for (DemuxResource dr : getDemuxResources().values()) {
+ if (!hasDesiredDemuxCap || dr.hasSufficientCaps(request.desiredFilterTypes)) {
+ if (!dr.isInUse()) {
int numOfSupportedCaps = dr.getNumOfCaps();
- boolean shouldUpdate = false;
- // update lowest priority
- if (currentLowestPriority > priority) {
- currentLowestPriority = priority;
- isRequestFromSameProcess = (requestClient.getProcessId()
- == (getClientProfile(dr.getOwnerClientId())).getProcessId());
- // reset the smallest caps when lower priority resource is found
- smallestNumOfSupportedCapsInUse = numOfSupportedCaps;
-
- shouldUpdate = true;
- } else {
- // This is the case when the priority is the same as previously found
- // one. Update smallest caps when priority.
- if (smallestNumOfSupportedCapsInUse > numOfSupportedCaps) {
- smallestNumOfSupportedCapsInUse = numOfSupportedCaps;
- shouldUpdate = true;
- }
+ // look for the demux with minimum caps supporting the desired caps
+ if (smallestNumOfSupportedCaps > numOfSupportedCaps) {
+ smallestNumOfSupportedCaps = numOfSupportedCaps;
+ grantingDemux = dr;
}
- if (shouldUpdate) {
- inUseLowestPriorityDrHandle = dr.getHandle();
+ } else if (grantingDemux == null) {
+ // Record the demux id with the lowest client priority among all the
+ // in use demuxes when no availabledemux has been found.
+ int priority = updateAndGetOwnerClientPriority(dr.getOwnerClientId());
+ if (currentLowestPriority >= priority) {
+ int numOfSupportedCaps = dr.getNumOfCaps();
+ boolean shouldUpdate = false;
+ // update lowest priority
+ if (currentLowestPriority > priority) {
+ currentLowestPriority = priority;
+ isRequestFromSameProcess = (requestClient.getProcessId()
+ == (getClientProfile(dr.getOwnerClientId())).getProcessId());
+
+ // reset the smallest caps when lower priority resource is found
+ smallestNumOfSupportedCapsInUse = numOfSupportedCaps;
+
+ shouldUpdate = true;
+ } else {
+ // This is the case when the priority is the same as previously
+ // found one. Update smallest caps when priority.
+ if (smallestNumOfSupportedCapsInUse > numOfSupportedCaps) {
+ smallestNumOfSupportedCapsInUse = numOfSupportedCaps;
+ shouldUpdate = true;
+ }
+ }
+ if (shouldUpdate) {
+ inUseLowestPriorityDemux = dr;
+ }
}
}
}
}
- }
- // Grant demux when there is unused resource.
- if (grantingDemuxHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
- demuxHandle[0] = grantingDemuxHandle;
- updateDemuxClientMappingOnNewGrant(grantingDemuxHandle, request.clientId);
- return true;
- }
-
- // When all the resources are occupied, grant the lowest priority resource if the
- // request client has higher priority.
- if (inUseLowestPriorityDrHandle != TunerResourceManager.INVALID_RESOURCE_HANDLE
- && ((requestClient.getPriority() > currentLowestPriority) || (
- (requestClient.getPriority() == currentLowestPriority) && isRequestFromSameProcess))) {
- if (!reclaimResource(
- getDemuxResource(inUseLowestPriorityDrHandle).getOwnerClientId(),
- TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX)) {
- return false;
+ // Grant demux when there is unused resource.
+ if (grantingDemux != null) {
+ updateDemuxClientMappingOnNewGrant(grantingDemux.getHandle(), request.clientId);
+ demuxHandle[0] = grantingDemux.getHandle();
+ return true;
}
- demuxHandle[0] = inUseLowestPriorityDrHandle;
- updateDemuxClientMappingOnNewGrant(
- inUseLowestPriorityDrHandle, request.clientId);
- return true;
+
+ // When all the resources are occupied, grant the lowest priority resource if the
+ // request client has higher priority.
+ if (inUseLowestPriorityDemux != null
+ && ((requestClient.getPriority() > currentLowestPriority) || (
+ (requestClient.getPriority() == currentLowestPriority)
+ && isRequestFromSameProcess))) {
+ demuxHandle[0] = inUseLowestPriorityDemux.getHandle();
+ reclaimOwnerId[0] = inUseLowestPriorityDemux.getOwnerClientId();
+ return true;
+ }
}
return false;
@@ -1792,7 +1918,9 @@
return;
}
- mListeners.put(clientId, record);
+ synchronized (mLock) {
+ mListeners.put(clientId, record);
+ }
}
@VisibleForTesting
@@ -1808,33 +1936,44 @@
// Reclaim all the resources of the share owners of the frontend that is used by the current
// resource reclaimed client.
- ClientProfile profile = getClientProfile(reclaimingClientId);
- // TODO: check if this check is really needed.
- if (profile == null) {
- return true;
- }
- Set<Integer> shareFeClientIds = profile.getShareFeClientIds();
- for (int clientId : shareFeClientIds) {
- try {
- mListeners.get(clientId).getListener().onReclaimResources();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to reclaim resources on client " + clientId, e);
- return false;
+ Set<Integer> shareFeClientIds;
+ synchronized (mLock) {
+ ClientProfile profile = getClientProfile(reclaimingClientId);
+ if (profile == null) {
+ return true;
}
- clearAllResourcesAndClientMapping(getClientProfile(clientId));
+ shareFeClientIds = profile.getShareFeClientIds();
+ }
+ ResourcesReclaimListenerRecord listenerRecord = null;
+ for (int clientId : shareFeClientIds) {
+ synchronized (mLock) {
+ listenerRecord = mListeners.get(clientId);
+ }
+ if (listenerRecord != null) {
+ try {
+ listenerRecord.getListener().onReclaimResources();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to reclaim resources on client " + clientId, e);
+ }
+ }
}
if (DEBUG) {
Slog.d(TAG, "Reclaiming resources because higher priority client request resource type "
+ resourceType + ", clientId:" + reclaimingClientId);
}
- try {
- mListeners.get(reclaimingClientId).getListener().onReclaimResources();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingClientId, e);
- return false;
+
+ synchronized (mLock) {
+ listenerRecord = mListeners.get(reclaimingClientId);
}
- clearAllResourcesAndClientMapping(profile);
+ if (listenerRecord != null) {
+ try {
+ listenerRecord.getListener().onReclaimResources();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingClientId, e);
+ }
+ }
+
return true;
}
@@ -2258,6 +2397,7 @@
addResourcesReclaimListener(clientId, listener);
}
+ @SuppressWarnings("GuardedBy") // Lock is held on mListeners
private void removeClientProfile(int clientId) {
for (int shareOwnerId : getClientProfile(clientId).getShareFeClientIds()) {
clearFrontendAndClientMapping(getClientProfile(shareOwnerId));
@@ -2265,12 +2405,9 @@
clearAllResourcesAndClientMapping(getClientProfile(clientId));
mClientProfiles.remove(clientId);
- // it may be called by unregisterClientProfileInternal under test
- synchronized (mLock) {
- ResourcesReclaimListenerRecord record = mListeners.remove(clientId);
- if (record != null) {
- record.getListener().asBinder().unlinkToDeath(record, 0);
- }
+ ResourcesReclaimListenerRecord record = mListeners.remove(clientId);
+ if (record != null) {
+ record.getListener().asBinder().unlinkToDeath(record, 0);
}
}
@@ -2304,7 +2441,8 @@
profile.releaseFrontend();
}
- private void clearAllResourcesAndClientMapping(ClientProfile profile) {
+ @VisibleForTesting
+ protected void clearAllResourcesAndClientMapping(ClientProfile profile) {
// TODO: check if this check is really needed. Maybe needed for reclaimResource path.
if (profile == null) {
return;
diff --git a/services/core/java/com/android/server/vibrator/ExternalVibrationSession.java b/services/core/java/com/android/server/vibrator/ExternalVibrationSession.java
new file mode 100644
index 0000000..b4d3862
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/ExternalVibrationSession.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 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.vibrator;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.ExternalVibration;
+import android.os.ExternalVibrationScale;
+import android.os.IBinder;
+import android.os.VibrationAttributes;
+import android.os.vibrator.Flags;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+/**
+ * A vibration session holding a single {@link ExternalVibration} request.
+ */
+final class ExternalVibrationSession extends Vibration
+ implements VibrationSession, IBinder.DeathRecipient {
+
+ private final ExternalVibration mExternalVibration;
+ private final ExternalVibrationScale mScale = new ExternalVibrationScale();
+
+ @Nullable
+ private Runnable mBinderDeathCallback;
+
+ ExternalVibrationSession(ExternalVibration externalVibration) {
+ super(externalVibration.getToken(), new CallerInfo(
+ externalVibration.getVibrationAttributes(), externalVibration.getUid(),
+ // TODO(b/249785241): Find a way to link ExternalVibration to a VirtualDevice
+ // instead of using DEVICE_ID_INVALID here and relying on the UID checks.
+ Context.DEVICE_ID_INVALID, externalVibration.getPackage(), null));
+ mExternalVibration = externalVibration;
+ }
+
+ public ExternalVibrationScale getScale() {
+ return mScale;
+ }
+
+ @Override
+ public CallerInfo getCallerInfo() {
+ return callerInfo;
+ }
+
+ @Override
+ public VibrationSession.DebugInfo getDebugInfo() {
+ return new Vibration.DebugInfoImpl(getStatus(), stats, /* playedEffect= */ null,
+ /* originalEffect= */ null, mScale.scaleLevel, mScale.adaptiveHapticsScale,
+ callerInfo);
+ }
+
+ @Override
+ public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
+ return new VibrationStats.StatsInfo(
+ mExternalVibration.getUid(),
+ FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__EXTERNAL,
+ mExternalVibration.getVibrationAttributes().getUsage(), getStatus(), stats,
+ completionUptimeMillis);
+ }
+
+ @Override
+ public boolean isRepeating() {
+ // We don't currently know if the external vibration is repeating, so we just use a
+ // heuristic based on the usage. Ideally this would be propagated in the ExternalVibration.
+ int usage = mExternalVibration.getVibrationAttributes().getUsage();
+ return usage == VibrationAttributes.USAGE_RINGTONE
+ || usage == VibrationAttributes.USAGE_ALARM;
+ }
+
+ @Override
+ public void linkToDeath(Runnable callback) {
+ synchronized (this) {
+ mBinderDeathCallback = callback;
+ }
+ mExternalVibration.linkToDeath(this);
+ }
+
+ @Override
+ public void unlinkToDeath() {
+ mExternalVibration.unlinkToDeath(this);
+ synchronized (this) {
+ mBinderDeathCallback = null;
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (this) {
+ if (mBinderDeathCallback != null) {
+ mBinderDeathCallback.run();
+ }
+ }
+ }
+
+ @Override
+ void end(EndInfo endInfo) {
+ super.end(endInfo);
+ if (stats.hasStarted()) {
+ // External vibration doesn't have feedback from total time the vibrator was playing
+ // with non-zero amplitude, so we use the duration between start and end times of
+ // the vibration as the time the vibrator was ON, since the haptic channels are
+ // open for this duration and can receive vibration waveform data.
+ stats.reportVibratorOn(stats.getEndUptimeMillis() - stats.getStartUptimeMillis());
+ }
+ }
+
+ @Override
+ public void notifyEnded() {
+ // Notify external client that this vibration should stop sending data to the vibrator.
+ mExternalVibration.mute();
+ }
+
+ boolean isHoldingSameVibration(ExternalVibration vib) {
+ return mExternalVibration.equals(vib);
+ }
+
+ void muteScale() {
+ mScale.scaleLevel = ExternalVibrationScale.ScaleLevel.SCALE_MUTE;
+ if (Flags.hapticsScaleV2Enabled()) {
+ mScale.scaleFactor = 0;
+ }
+ }
+
+ void scale(VibrationScaler scaler, int usage) {
+ mScale.scaleLevel = scaler.getScaleLevel(usage);
+ if (Flags.hapticsScaleV2Enabled()) {
+ mScale.scaleFactor = scaler.getScaleFactor(usage);
+ }
+ mScale.adaptiveHapticsScale = scaler.getAdaptiveHapticsScale(usage);
+ stats.reportAdaptiveScale(mScale.adaptiveHapticsScale);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/HalVibration.java b/services/core/java/com/android/server/vibrator/HalVibration.java
index fe0cf59..ea4bd01 100644
--- a/services/core/java/com/android/server/vibrator/HalVibration.java
+++ b/services/core/java/com/android/server/vibrator/HalVibration.java
@@ -51,37 +51,22 @@
@NonNull
private volatile CombinedVibration mEffectToPlay;
- /** Vibration status. */
- private Vibration.Status mStatus;
-
/** Reported scale values applied to the vibration effects. */
private int mScaleLevel;
private float mAdaptiveScale;
HalVibration(@NonNull IBinder token, @NonNull CombinedVibration effect,
- @NonNull CallerInfo callerInfo) {
+ @NonNull VibrationSession.CallerInfo callerInfo) {
super(token, callerInfo);
mOriginalEffect = effect;
mEffectToPlay = effect;
- mStatus = Vibration.Status.RUNNING;
mScaleLevel = VibrationScaler.SCALE_NONE;
mAdaptiveScale = VibrationScaler.ADAPTIVE_SCALE_NONE;
}
- /**
- * Set the {@link Status} of this vibration and reports the current system time as this
- * vibration end time, for debugging purposes.
- *
- * <p>This method will only accept given value if the current status is {@link
- * Status#RUNNING}.
- */
- public void end(EndInfo info) {
- if (hasEnded()) {
- // Vibration already ended, keep first ending status set and ignore this one.
- return;
- }
- mStatus = info.status;
- stats.reportEnded(info.endedBy);
+ @Override
+ public void end(EndInfo endInfo) {
+ super.end(endInfo);
mCompletionLatch.countDown();
}
@@ -144,11 +129,6 @@
// No need to update fallback effects, they are already configured per device.
}
- /** Return true is current status is different from {@link Status#RUNNING}. */
- public boolean hasEnded() {
- return mStatus != Status.RUNNING;
- }
-
@Override
public boolean isRepeating() {
return mOriginalEffect.getDuration() == Long.MAX_VALUE;
@@ -159,16 +139,16 @@
return mEffectToPlay;
}
- /** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
- public Vibration.DebugInfo getDebugInfo() {
+ @Override
+ public VibrationSession.DebugInfo getDebugInfo() {
// Clear the original effect if it's the same as the effect that was played, for simplicity
CombinedVibration originalEffect =
Objects.equals(mOriginalEffect, mEffectToPlay) ? null : mOriginalEffect;
- return new Vibration.DebugInfo(mStatus, stats, mEffectToPlay, originalEffect,
+ return new Vibration.DebugInfoImpl(getStatus(), stats, mEffectToPlay, originalEffect,
mScaleLevel, mAdaptiveScale, callerInfo);
}
- /** Return {@link VibrationStats.StatsInfo} with read-only metrics about this vibration. */
+ @Override
public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
int vibrationType = mEffectToPlay.hasVendorEffects()
? FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__VENDOR
@@ -176,7 +156,7 @@
? FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__REPEATED
: FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE;
return new VibrationStats.StatsInfo(
- callerInfo.uid, vibrationType, callerInfo.attrs.getUsage(), mStatus,
+ callerInfo.uid, vibrationType, callerInfo.attrs.getUsage(), getStatus(),
stats, completionUptimeMillis);
}
diff --git a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
index 4e58b9a..83e05f4 100644
--- a/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
+++ b/services/core/java/com/android/server/vibrator/InputDeviceDelegate.java
@@ -26,6 +26,7 @@
import android.view.InputDevice;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.vibrator.VibrationSession.CallerInfo;
/** Delegates vibrations to all connected {@link InputDevice} with one or more vibrators. */
final class InputDeviceDelegate implements InputManager.InputDeviceListener {
@@ -93,7 +94,7 @@
*
* @return {@link #isAvailable()}
*/
- public boolean vibrateIfAvailable(Vibration.CallerInfo callerInfo, CombinedVibration effect) {
+ public boolean vibrateIfAvailable(CallerInfo callerInfo, CombinedVibration effect) {
synchronized (mLock) {
for (int i = 0; i < mInputDeviceVibrators.size(); i++) {
mInputDeviceVibrators.valueAt(i).vibrate(callerInfo.uid, callerInfo.opPkg, effect,
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index aa4b9f3..9a04793 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -31,7 +31,6 @@
import android.util.IndentingPrintWriter;
import android.util.proto.ProtoOutputStream;
-import java.io.PrintWriter;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
@@ -52,131 +51,69 @@
private static final AtomicInteger sNextVibrationId = new AtomicInteger(1); // 0 = no callback
public final long id;
- public final CallerInfo callerInfo;
+ public final VibrationSession.CallerInfo callerInfo;
public final VibrationStats stats = new VibrationStats();
public final IBinder callerToken;
- /** Vibration status with reference to values from vibratormanagerservice.proto for logging. */
- enum Status {
- UNKNOWN(VibrationProto.UNKNOWN),
- RUNNING(VibrationProto.RUNNING),
- FINISHED(VibrationProto.FINISHED),
- FINISHED_UNEXPECTED(VibrationProto.FINISHED_UNEXPECTED),
- FORWARDED_TO_INPUT_DEVICES(VibrationProto.FORWARDED_TO_INPUT_DEVICES),
- CANCELLED_BINDER_DIED(VibrationProto.CANCELLED_BINDER_DIED),
- CANCELLED_BY_SCREEN_OFF(VibrationProto.CANCELLED_BY_SCREEN_OFF),
- CANCELLED_BY_SETTINGS_UPDATE(VibrationProto.CANCELLED_BY_SETTINGS_UPDATE),
- CANCELLED_BY_USER(VibrationProto.CANCELLED_BY_USER),
- CANCELLED_BY_FOREGROUND_USER(VibrationProto.CANCELLED_BY_FOREGROUND_USER),
- CANCELLED_BY_UNKNOWN_REASON(VibrationProto.CANCELLED_BY_UNKNOWN_REASON),
- CANCELLED_SUPERSEDED(VibrationProto.CANCELLED_SUPERSEDED),
- CANCELLED_BY_APP_OPS(VibrationProto.CANCELLED_BY_APP_OPS),
- IGNORED_ERROR_APP_OPS(VibrationProto.IGNORED_ERROR_APP_OPS),
- IGNORED_ERROR_CANCELLING(VibrationProto.IGNORED_ERROR_CANCELLING),
- IGNORED_ERROR_SCHEDULING(VibrationProto.IGNORED_ERROR_SCHEDULING),
- IGNORED_ERROR_TOKEN(VibrationProto.IGNORED_ERROR_TOKEN),
- IGNORED_APP_OPS(VibrationProto.IGNORED_APP_OPS),
- IGNORED_BACKGROUND(VibrationProto.IGNORED_BACKGROUND),
- IGNORED_MISSING_PERMISSION(VibrationProto.IGNORED_MISSING_PERMISSION),
- IGNORED_UNSUPPORTED(VibrationProto.IGNORED_UNSUPPORTED),
- IGNORED_FOR_EXTERNAL(VibrationProto.IGNORED_FOR_EXTERNAL),
- IGNORED_FOR_HIGHER_IMPORTANCE(VibrationProto.IGNORED_FOR_HIGHER_IMPORTANCE),
- IGNORED_FOR_ONGOING(VibrationProto.IGNORED_FOR_ONGOING),
- IGNORED_FOR_POWER(VibrationProto.IGNORED_FOR_POWER),
- IGNORED_FOR_RINGER_MODE(VibrationProto.IGNORED_FOR_RINGER_MODE),
- IGNORED_FOR_SETTINGS(VibrationProto.IGNORED_FOR_SETTINGS),
- IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED),
- IGNORED_FROM_VIRTUAL_DEVICE(VibrationProto.IGNORED_FROM_VIRTUAL_DEVICE),
- IGNORED_ON_WIRELESS_CHARGER(VibrationProto.IGNORED_ON_WIRELESS_CHARGER);
+ private VibrationSession.Status mStatus;
- private final int mProtoEnumValue;
-
- Status(int value) {
- mProtoEnumValue = value;
- }
-
- public int getProtoEnumValue() {
- return mProtoEnumValue;
- }
- }
-
- Vibration(@NonNull IBinder token, @NonNull CallerInfo callerInfo) {
+ Vibration(@NonNull IBinder token, @NonNull VibrationSession.CallerInfo callerInfo) {
Objects.requireNonNull(token);
Objects.requireNonNull(callerInfo);
+ mStatus = VibrationSession.Status.RUNNING;
this.id = sNextVibrationId.getAndIncrement();
this.callerToken = token;
this.callerInfo = callerInfo;
}
+ VibrationSession.Status getStatus() {
+ return mStatus;
+ }
+
+ /** Return true is current status is different from {@link VibrationSession.Status#RUNNING}. */
+ boolean hasEnded() {
+ return mStatus != VibrationSession.Status.RUNNING;
+ }
+
+ /**
+ * Set the {@link VibrationSession} of this vibration and reports the current system time as
+ * this vibration end time, for debugging purposes.
+ *
+ * <p>This method will only accept given value if the current status is {@link
+ * VibrationSession.Status#RUNNING}.
+ */
+ void end(Vibration.EndInfo endInfo) {
+ if (hasEnded()) {
+ // Vibration already ended, keep first ending status set and ignore this one.
+ return;
+ }
+ mStatus = endInfo.status;
+ stats.reportEnded(endInfo.endedBy);
+ }
+
/** Return true if vibration is a repeating vibration. */
abstract boolean isRepeating();
- /**
- * Holds lightweight immutable info on the process that triggered the vibration. This data
- * could potentially be kept in memory for a long time for bugreport dumpsys operations.
- *
- * Since CallerInfo can be kept in memory for a long time, it shouldn't hold any references to
- * potentially expensive or resource-linked objects, such as {@link IBinder}.
- */
- static final class CallerInfo {
- public final VibrationAttributes attrs;
- public final int uid;
- public final int deviceId;
- public final String opPkg;
- public final String reason;
+ /** Return {@link VibrationSession.DebugInfo} with read-only debug data about this vibration. */
+ abstract VibrationSession.DebugInfo getDebugInfo();
- CallerInfo(@NonNull VibrationAttributes attrs, int uid, int deviceId, String opPkg,
- String reason) {
- Objects.requireNonNull(attrs);
- this.attrs = attrs;
- this.uid = uid;
- this.deviceId = deviceId;
- this.opPkg = opPkg;
- this.reason = reason;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof CallerInfo)) return false;
- CallerInfo that = (CallerInfo) o;
- return Objects.equals(attrs, that.attrs)
- && uid == that.uid
- && deviceId == that.deviceId
- && Objects.equals(opPkg, that.opPkg)
- && Objects.equals(reason, that.reason);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(attrs, uid, deviceId, opPkg, reason);
- }
-
- @Override
- public String toString() {
- return "CallerInfo{"
- + " uid=" + uid
- + ", opPkg=" + opPkg
- + ", deviceId=" + deviceId
- + ", attrs=" + attrs
- + ", reason=" + reason
- + '}';
- }
- }
+ /** Return {@link VibrationStats.StatsInfo} with read-only metrics about this vibration. */
+ abstract VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis);
/** Immutable info passed as a signal to end a vibration. */
static final class EndInfo {
- /** The {@link Status} to be set to the vibration when it ends with this info. */
+ /** The vibration status to be set when it ends with this info. */
@NonNull
- public final Status status;
+ public final VibrationSession.Status status;
/** Info about the process that ended the vibration. */
- public final CallerInfo endedBy;
+ public final VibrationSession.CallerInfo endedBy;
- EndInfo(@NonNull Vibration.Status status) {
+ EndInfo(@NonNull VibrationSession.Status status) {
this(status, null);
}
- EndInfo(@NonNull Vibration.Status status, @Nullable CallerInfo endedBy) {
+ EndInfo(@NonNull VibrationSession.Status status,
+ @Nullable VibrationSession.CallerInfo endedBy) {
this.status = status;
this.endedBy = endedBy;
}
@@ -211,10 +148,10 @@
* Since DebugInfo can be kept in memory for a long time, it shouldn't hold any references to
* potentially expensive or resource-linked objects, such as {@link IBinder}.
*/
- static final class DebugInfo {
- final Status mStatus;
+ static final class DebugInfoImpl implements VibrationSession.DebugInfo {
+ final VibrationSession.Status mStatus;
final long mCreateTime;
- final CallerInfo mCallerInfo;
+ final VibrationSession.CallerInfo mCallerInfo;
@Nullable
final CombinedVibration mPlayedEffect;
@@ -226,9 +163,10 @@
private final int mScaleLevel;
private final float mAdaptiveScale;
- DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration playedEffect,
+ DebugInfoImpl(VibrationSession.Status status, VibrationStats stats,
+ @Nullable CombinedVibration playedEffect,
@Nullable CombinedVibration originalEffect, int scaleLevel,
- float adaptiveScale, @NonNull CallerInfo callerInfo) {
+ float adaptiveScale, @NonNull VibrationSession.CallerInfo callerInfo) {
Objects.requireNonNull(callerInfo);
mCreateTime = stats.getCreateTimeDebug();
mStartTime = stats.getStartTimeDebug();
@@ -243,6 +181,27 @@
}
@Override
+ public VibrationSession.Status getStatus() {
+ return mStatus;
+ }
+
+ @Override
+ public long getCreateUptimeMillis() {
+ return mCreateTime;
+ }
+
+ @Override
+ public VibrationSession.CallerInfo getCallerInfo() {
+ return mCallerInfo;
+ }
+
+ @Nullable
+ @Override
+ public Object getDumpAggregationKey() {
+ return mPlayedEffect;
+ }
+
+ @Override
public String toString() {
return "createTime: " + formatTime(mCreateTime, /*includeDate=*/ true)
+ ", startTime: " + formatTime(mStartTime, /*includeDate=*/ true)
@@ -257,17 +216,13 @@
+ ", callerInfo: " + mCallerInfo;
}
- void logMetrics(VibratorFrameworkStatsLogger statsLogger) {
+ @Override
+ public void logMetrics(VibratorFrameworkStatsLogger statsLogger) {
statsLogger.logVibrationAdaptiveHapticScale(mCallerInfo.uid, mAdaptiveScale);
}
- /**
- * Write this info in a compact way into given {@link PrintWriter}.
- *
- * <p>This is used by dumpsys to log multiple vibration records in single lines that are
- * easy to skim through by the sorted created time.
- */
- void dumpCompact(IndentingPrintWriter pw) {
+ @Override
+ public void dumpCompact(IndentingPrintWriter pw) {
boolean isExternalVibration = mPlayedEffect == null;
String timingsStr = String.format(Locale.ROOT,
"%s | %8s | %20s | duration: %5dms | start: %12s | end: %12s",
@@ -299,8 +254,8 @@
pw.println(timingsStr + paramStr + audioUsageStr + callerStr + effectStr);
}
- /** Write this info into given {@link PrintWriter}. */
- void dump(IndentingPrintWriter pw) {
+ @Override
+ public void dump(IndentingPrintWriter pw) {
pw.println("Vibration:");
pw.increaseIndent();
pw.println("status = " + mStatus.name().toLowerCase(Locale.ROOT));
@@ -317,8 +272,8 @@
pw.decreaseIndent();
}
- /** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */
- void dump(ProtoOutputStream proto, long fieldId) {
+ @Override
+ public void dump(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(VibrationProto.START_TIME, mStartTime);
proto.write(VibrationProto.END_TIME, mEndTime);
diff --git a/services/core/java/com/android/server/vibrator/VibrationSession.java b/services/core/java/com/android/server/vibrator/VibrationSession.java
new file mode 100644
index 0000000..5640b49
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibrationSession.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2024 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.vibrator;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.CombinedVibration;
+import android.os.IBinder;
+import android.os.VibrationAttributes;
+import android.util.IndentingPrintWriter;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * Represents a generic vibration session that plays one or more vibration requests.
+ *
+ * <p>This might represent:
+ *
+ * <ol>
+ * <li>A single {@link CombinedVibration} playback.
+ * <li>An {@link android.os.ExternalVibration} playback.
+ * </ol>
+ */
+interface VibrationSession {
+
+ /** Returns data about the client app that triggered this vibration session. */
+ CallerInfo getCallerInfo();
+
+ /** Returns debug data for logging and metric reports. */
+ DebugInfo getDebugInfo();
+
+ /**
+ * Links this session to the app process death with given callback to handle it.
+ *
+ * <p>This can be used by the service to end the vibration session when the app process dies.
+ */
+ void linkToDeath(Runnable callback);
+
+ /** Removes link to the app process death. */
+ void unlinkToDeath();
+
+ /** Notify the session end was requested, which might be acted upon asynchronously. */
+ void notifyEnded();
+
+ /**
+ * Session status with reference to values from vibratormanagerservice.proto for logging.
+ */
+ enum Status {
+ UNKNOWN(VibrationProto.UNKNOWN),
+ RUNNING(VibrationProto.RUNNING),
+ FINISHED(VibrationProto.FINISHED),
+ FINISHED_UNEXPECTED(VibrationProto.FINISHED_UNEXPECTED),
+ FORWARDED_TO_INPUT_DEVICES(VibrationProto.FORWARDED_TO_INPUT_DEVICES),
+ CANCELLED_BINDER_DIED(VibrationProto.CANCELLED_BINDER_DIED),
+ CANCELLED_BY_SCREEN_OFF(VibrationProto.CANCELLED_BY_SCREEN_OFF),
+ CANCELLED_BY_SETTINGS_UPDATE(VibrationProto.CANCELLED_BY_SETTINGS_UPDATE),
+ CANCELLED_BY_USER(VibrationProto.CANCELLED_BY_USER),
+ CANCELLED_BY_FOREGROUND_USER(VibrationProto.CANCELLED_BY_FOREGROUND_USER),
+ CANCELLED_BY_UNKNOWN_REASON(VibrationProto.CANCELLED_BY_UNKNOWN_REASON),
+ CANCELLED_SUPERSEDED(VibrationProto.CANCELLED_SUPERSEDED),
+ CANCELLED_BY_APP_OPS(VibrationProto.CANCELLED_BY_APP_OPS),
+ IGNORED_ERROR_APP_OPS(VibrationProto.IGNORED_ERROR_APP_OPS),
+ IGNORED_ERROR_CANCELLING(VibrationProto.IGNORED_ERROR_CANCELLING),
+ IGNORED_ERROR_SCHEDULING(VibrationProto.IGNORED_ERROR_SCHEDULING),
+ IGNORED_ERROR_TOKEN(VibrationProto.IGNORED_ERROR_TOKEN),
+ IGNORED_APP_OPS(VibrationProto.IGNORED_APP_OPS),
+ IGNORED_BACKGROUND(VibrationProto.IGNORED_BACKGROUND),
+ IGNORED_MISSING_PERMISSION(VibrationProto.IGNORED_MISSING_PERMISSION),
+ IGNORED_UNSUPPORTED(VibrationProto.IGNORED_UNSUPPORTED),
+ IGNORED_FOR_EXTERNAL(VibrationProto.IGNORED_FOR_EXTERNAL),
+ IGNORED_FOR_HIGHER_IMPORTANCE(VibrationProto.IGNORED_FOR_HIGHER_IMPORTANCE),
+ IGNORED_FOR_ONGOING(VibrationProto.IGNORED_FOR_ONGOING),
+ IGNORED_FOR_POWER(VibrationProto.IGNORED_FOR_POWER),
+ IGNORED_FOR_RINGER_MODE(VibrationProto.IGNORED_FOR_RINGER_MODE),
+ IGNORED_FOR_SETTINGS(VibrationProto.IGNORED_FOR_SETTINGS),
+ IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED),
+ IGNORED_FROM_VIRTUAL_DEVICE(VibrationProto.IGNORED_FROM_VIRTUAL_DEVICE),
+ IGNORED_ON_WIRELESS_CHARGER(VibrationProto.IGNORED_ON_WIRELESS_CHARGER);
+
+ private final int mProtoEnumValue;
+
+ Status(int value) {
+ mProtoEnumValue = value;
+ }
+
+ public int getProtoEnumValue() {
+ return mProtoEnumValue;
+ }
+ }
+
+ /**
+ * Holds lightweight immutable info on the process that triggered the vibration session.
+ *
+ * <p>This data could potentially be kept in memory for a long time for bugreport dumpsys
+ * operations. It shouldn't hold any references to potentially expensive or resource-linked
+ * objects, such as {@link IBinder}.
+ */
+ final class CallerInfo {
+ public final VibrationAttributes attrs;
+ public final int uid;
+ public final int deviceId;
+ public final String opPkg;
+ public final String reason;
+
+ CallerInfo(@NonNull VibrationAttributes attrs, int uid, int deviceId, String opPkg,
+ String reason) {
+ Objects.requireNonNull(attrs);
+ this.attrs = attrs;
+ this.uid = uid;
+ this.deviceId = deviceId;
+ this.opPkg = opPkg;
+ this.reason = reason;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CallerInfo)) return false;
+ CallerInfo that = (CallerInfo) o;
+ return Objects.equals(attrs, that.attrs)
+ && uid == that.uid
+ && deviceId == that.deviceId
+ && Objects.equals(opPkg, that.opPkg)
+ && Objects.equals(reason, that.reason);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(attrs, uid, deviceId, opPkg, reason);
+ }
+
+ @Override
+ public String toString() {
+ return "CallerInfo{"
+ + " uid=" + uid
+ + ", opPkg=" + opPkg
+ + ", deviceId=" + deviceId
+ + ", attrs=" + attrs
+ + ", reason=" + reason
+ + '}';
+ }
+ }
+
+ /**
+ * Interface for lightweight debug information about the vibration session for debugging.
+ *
+ * <p>This data could potentially be kept in memory for a long time for bugreport dumpsys
+ * operations. It shouldn't hold any references to potentially expensive or resource-linked
+ * objects, such as {@link IBinder}.
+ */
+ interface DebugInfo {
+
+ /** Return the vibration session status. */
+ Status getStatus();
+
+ /** Returns the session creation time from {@link android.os.SystemClock#uptimeMillis()}. */
+ long getCreateUptimeMillis();
+
+ /** Returns information about the process that created the session. */
+ CallerInfo getCallerInfo();
+
+ /**
+ * Returns the aggregation key for log records.
+ *
+ * <p>This is used to aggregate similar vibration sessions triggered in quick succession
+ * (e.g. multiple keyboard vibrations when the user is typing).
+ *
+ * <p>This does not need to include data from {@link CallerInfo} or {@link Status}.
+ *
+ * @see GroupedAggregatedLogRecords
+ */
+ @Nullable
+ Object getDumpAggregationKey();
+
+ /** Logs vibration session fields for metric reports. */
+ void logMetrics(VibratorFrameworkStatsLogger statsLogger);
+
+ /** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */
+ void dump(ProtoOutputStream proto, long fieldId);
+
+ /** Write this info into given {@link PrintWriter}. */
+ void dump(IndentingPrintWriter pw);
+
+ /**
+ * Write this info in a compact way into given {@link PrintWriter}.
+ *
+ * <p>This is used by dumpsys to log multiple records in single lines that are easy to skim
+ * through by the sorted created time.
+ */
+ void dumpCompact(IndentingPrintWriter pw);
+ }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 0d6778c..69cdcf4 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -66,6 +66,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
+import com.android.server.vibrator.VibrationSession.CallerInfo;
+import com.android.server.vibrator.VibrationSession.Status;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -416,46 +418,46 @@
/**
* Check if given vibration should be ignored by the service.
*
- * @return One of Vibration.Status.IGNORED_* values if the vibration should be ignored,
+ * @return One of VibrationSession.Status.IGNORED_* values if the vibration should be ignored,
* null otherwise.
*/
@Nullable
- public Vibration.Status shouldIgnoreVibration(@NonNull Vibration.CallerInfo callerInfo) {
+ public Status shouldIgnoreVibration(@NonNull CallerInfo callerInfo) {
final int usage = callerInfo.attrs.getUsage();
synchronized (mLock) {
if (!mUidObserver.isUidForeground(callerInfo.uid)
&& !BACKGROUND_PROCESS_USAGE_ALLOWLIST.contains(usage)) {
- return Vibration.Status.IGNORED_BACKGROUND;
+ return Status.IGNORED_BACKGROUND;
}
if (callerInfo.deviceId != Context.DEVICE_ID_DEFAULT
&& callerInfo.deviceId != Context.DEVICE_ID_INVALID) {
- return Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE;
+ return Status.IGNORED_FROM_VIRTUAL_DEVICE;
}
if (callerInfo.deviceId == Context.DEVICE_ID_INVALID
&& isAppRunningOnAnyVirtualDevice(callerInfo.uid)) {
- return Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE;
+ return Status.IGNORED_FROM_VIRTUAL_DEVICE;
}
if (mBatterySaverMode && !BATTERY_SAVER_USAGE_ALLOWLIST.contains(usage)) {
- return Vibration.Status.IGNORED_FOR_POWER;
+ return Status.IGNORED_FOR_POWER;
}
if (!callerInfo.attrs.isFlagSet(
VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
&& !shouldVibrateForUserSetting(callerInfo)) {
- return Vibration.Status.IGNORED_FOR_SETTINGS;
+ return Status.IGNORED_FOR_SETTINGS;
}
if (!callerInfo.attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) {
if (!shouldVibrateForRingerModeLocked(usage)) {
- return Vibration.Status.IGNORED_FOR_RINGER_MODE;
+ return Status.IGNORED_FOR_RINGER_MODE;
}
}
if (mVibrationConfig.ignoreVibrationsOnWirelessCharger() && mOnWirelessCharger) {
- return Vibration.Status.IGNORED_ON_WIRELESS_CHARGER;
+ return Status.IGNORED_ON_WIRELESS_CHARGER;
}
}
return null;
@@ -471,7 +473,7 @@
*
* @return true if the vibration should be cancelled when the screen goes off, false otherwise.
*/
- public boolean shouldCancelVibrationOnScreenOff(@NonNull Vibration.CallerInfo callerInfo,
+ public boolean shouldCancelVibrationOnScreenOff(@NonNull CallerInfo callerInfo,
long vibrationStartUptimeMillis) {
PowerManagerInternal pm;
synchronized (mLock) {
@@ -483,8 +485,8 @@
// ignored here and not cancel a vibration, and those are usually triggered by timeout
// or inactivity, so it's unlikely that it will override a more active goToSleep reason.
PowerManager.SleepData sleepData = pm.getLastGoToSleep();
- if ((sleepData.goToSleepUptimeMillis < vibrationStartUptimeMillis)
- || POWER_MANAGER_SLEEP_REASON_ALLOWLIST.contains(sleepData.goToSleepReason)) {
+ if (sleepData != null && (sleepData.goToSleepUptimeMillis < vibrationStartUptimeMillis
+ || POWER_MANAGER_SLEEP_REASON_ALLOWLIST.contains(sleepData.goToSleepReason))) {
// Ignore screen off events triggered before the vibration started, and all
// automatic "go to sleep" events from allowlist.
Slog.d(TAG, "Ignoring screen off event triggered at uptime "
@@ -522,7 +524,7 @@
* {@code false} to ignore the vibration.
*/
@GuardedBy("mLock")
- private boolean shouldVibrateForUserSetting(Vibration.CallerInfo callerInfo) {
+ private boolean shouldVibrateForUserSetting(CallerInfo callerInfo) {
final int usage = callerInfo.attrs.getUsage();
if (!mVibrateOn && (VIBRATE_ON_DISABLED_USAGE_ALLOWED != usage)) {
// Main setting disabled.
diff --git a/services/core/java/com/android/server/vibrator/VibrationStats.java b/services/core/java/com/android/server/vibrator/VibrationStats.java
index 8179d6a..fc0c6e7 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStats.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStats.java
@@ -166,7 +166,7 @@
* @return true if the status was accepted. This method will only accept given values if
* the end timestamp was never set.
*/
- boolean reportEnded(@Nullable Vibration.CallerInfo endedBy) {
+ boolean reportEnded(@Nullable VibrationSession.CallerInfo endedBy) {
if (hasEnded()) {
// Vibration already ended, keep first ending stats set and ignore this one.
return false;
@@ -187,7 +187,7 @@
* <p>This method will only accept the first value as the one that was interrupted by this
* vibration, and will ignore all successive calls.
*/
- void reportInterruptedAnotherVibration(@NonNull Vibration.CallerInfo callerInfo) {
+ void reportInterruptedAnotherVibration(@NonNull VibrationSession.CallerInfo callerInfo) {
if (mInterruptedUsage < 0) {
mInterruptedUsage = callerInfo.attrs.getUsage();
}
@@ -330,7 +330,7 @@
public final int[] halUnsupportedEffectsUsed;
private boolean mIsWritten;
- StatsInfo(int uid, int vibrationType, int usage, Vibration.Status status,
+ StatsInfo(int uid, int vibrationType, int usage, VibrationSession.Status status,
VibrationStats stats, long completionUptimeMillis) {
this.uid = uid;
this.vibrationType = vibrationType;
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 7152844..5137d19 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -32,6 +32,7 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.vibrator.VibrationSession.Status;
import java.util.ArrayList;
import java.util.Iterator;
@@ -217,7 +218,7 @@
}
/**
- * Calculate the {@link Vibration.Status} based on the current queue state and the expected
+ * Calculate the {@link Vibration.EndInfo} based on the current queue state and the expected
* number of {@link StartSequentialEffectStep} to be played.
*/
@Nullable
@@ -235,10 +236,10 @@
}
// No pending steps, and something happened.
if (mSuccessfulVibratorOnSteps > 0) {
- return new Vibration.EndInfo(Vibration.Status.FINISHED);
+ return new Vibration.EndInfo(Status.FINISHED);
}
// If no step was able to turn the vibrator ON successfully.
- return new Vibration.EndInfo(Vibration.Status.IGNORED_UNSUPPORTED);
+ return new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED);
}
/**
@@ -352,7 +353,7 @@
if (DEBUG) {
Slog.d(TAG, "Binder died, cancelling vibration...");
}
- notifyCancelled(new Vibration.EndInfo(Vibration.Status.CANCELLED_BINDER_DIED),
+ notifyCancelled(new Vibration.EndInfo(Status.CANCELLED_BINDER_DIED),
/* immediate= */ false);
}
@@ -377,7 +378,7 @@
if ((cancelInfo == null) || !cancelInfo.status.name().startsWith("CANCEL")) {
Slog.w(TAG, "Vibration cancel requested with bad signal=" + cancelInfo
+ ", using CANCELLED_UNKNOWN_REASON to ensure cancellation.");
- cancelInfo = new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_UNKNOWN_REASON);
+ cancelInfo = new Vibration.EndInfo(Status.CANCELLED_BY_UNKNOWN_REASON);
}
synchronized (mLock) {
if ((immediate && mSignalCancelImmediate) || (mSignalCancel != null)) {
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index cfb4c74..ab4a4d8 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -29,6 +29,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vibrator.VibrationSession.Status;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -240,7 +241,7 @@
runCurrentVibrationWithWakeLockAndDeathLink();
} finally {
clientVibrationCompleteIfNotAlready(
- new Vibration.EndInfo(Vibration.Status.FINISHED_UNEXPECTED));
+ new Vibration.EndInfo(Status.FINISHED_UNEXPECTED));
}
} finally {
mWakeLock.release();
@@ -259,7 +260,7 @@
} catch (RemoteException e) {
Slog.e(TAG, "Error linking vibration to token death", e);
clientVibrationCompleteIfNotAlready(
- new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_TOKEN));
+ new Vibration.EndInfo(Status.IGNORED_ERROR_TOKEN));
return;
}
// Ensure that the unlink always occurs now.
diff --git a/services/core/java/com/android/server/vibrator/VibratorControlService.java b/services/core/java/com/android/server/vibrator/VibratorControlService.java
index de5e662..3a814cd 100644
--- a/services/core/java/com/android/server/vibrator/VibratorControlService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorControlService.java
@@ -559,8 +559,8 @@
}
/**
- * Record for a single {@link Vibration.DebugInfo}, that can be grouped by usage and aggregated
- * by UID, {@link VibrationAttributes} and {@link VibrationEffect}.
+ * Record for a single {@link VibrationSession.DebugInfo}, that can be grouped by usage and
+ * aggregated by UID, {@link VibrationAttributes} and {@link VibrationEffect}.
*/
private static final class VibrationScaleParamRecord
implements GroupedAggregatedLogRecords.SingleLogRecord {
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index c143beb..799934a 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -73,9 +73,11 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FrameworkStatsLog;
import com.android.server.SystemService;
import com.android.server.pm.BackgroundUserSoundNotifier;
+import com.android.server.vibrator.VibrationSession.CallerInfo;
+import com.android.server.vibrator.VibrationSession.DebugInfo;
+import com.android.server.vibrator.VibrationSession.Status;
import libcore.util.NativeAllocationRegistry;
@@ -160,11 +162,12 @@
@GuardedBy("mLock")
private VibrationStepConductor mNextVibration;
@GuardedBy("mLock")
- private ExternalVibrationHolder mCurrentExternalVibration;
+ private ExternalVibrationSession mCurrentExternalVibration;
@GuardedBy("mLock")
private boolean mServiceReady;
- private final VibrationSettings mVibrationSettings;
+ @VisibleForTesting
+ final VibrationSettings mVibrationSettings;
private final VibrationScaler mVibrationScaler;
private final VibratorControlService mVibratorControlService;
private final InputDeviceDelegate mInputDeviceDelegate;
@@ -184,13 +187,12 @@
// When the system is entering a non-interactive state, we want to cancel
// vibrations in case a misbehaving app has abandoned them.
if (shouldCancelOnScreenOffLocked(mNextVibration)) {
- clearNextVibrationLocked(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF));
+ clearNextVibrationLocked(new Vibration.EndInfo(
+ Status.CANCELLED_BY_SCREEN_OFF));
}
if (shouldCancelOnScreenOffLocked(mCurrentVibration)) {
- mCurrentVibration.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
- /* immediate= */ false);
+ mCurrentVibration.notifyCancelled(new Vibration.EndInfo(
+ Status.CANCELLED_BY_SCREEN_OFF), /* immediate= */ false);
}
}
} else if (android.multiuser.Flags.addUiForSoundsFromBackgroundUsers()
@@ -198,12 +200,11 @@
synchronized (mLock) {
if (shouldCancelOnFgUserRequest(mNextVibration)) {
clearNextVibrationLocked(new Vibration.EndInfo(
- Vibration.Status.CANCELLED_BY_FOREGROUND_USER));
+ Status.CANCELLED_BY_FOREGROUND_USER));
}
if (shouldCancelOnFgUserRequest(mCurrentVibration)) {
mCurrentVibration.notifyCancelled(new Vibration.EndInfo(
- Vibration.Status.CANCELLED_BY_FOREGROUND_USER),
- /* immediate= */ false);
+ Status.CANCELLED_BY_FOREGROUND_USER), /* immediate= */ false);
}
}
}
@@ -220,12 +221,12 @@
}
synchronized (mLock) {
if (shouldCancelAppOpModeChangedLocked(mNextVibration)) {
- clearNextVibrationLocked(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_APP_OPS));
+ clearNextVibrationLocked(new Vibration.EndInfo(
+ Status.CANCELLED_BY_APP_OPS));
}
if (shouldCancelAppOpModeChangedLocked(mCurrentVibration)) {
mCurrentVibration.notifyCancelled(new Vibration.EndInfo(
- Vibration.Status.CANCELLED_BY_APP_OPS), /* immediate= */ false);
+ Status.CANCELLED_BY_APP_OPS), /* immediate= */ false);
}
}
}
@@ -441,8 +442,8 @@
return false;
}
AlwaysOnVibration alwaysOnVibration = new AlwaysOnVibration(alwaysOnId,
- new Vibration.CallerInfo(attrs, uid, Context.DEVICE_ID_DEFAULT, opPkg,
- null), effects);
+ new CallerInfo(attrs, uid, Context.DEVICE_ID_DEFAULT, opPkg, null),
+ effects);
mAlwaysOnEffects.put(alwaysOnId, alwaysOnVibration);
updateAlwaysOnLocked(alwaysOnVibration);
}
@@ -490,8 +491,7 @@
// Make sure we report the constant id in the requested haptic feedback reason.
reason = "performHapticFeedback(constant=" + constant + "): " + reason;
HapticFeedbackVibrationProvider hapticVibrationProvider = getHapticVibrationProvider();
- Vibration.Status ignoreStatus = shouldIgnoreHapticFeedback(constant, reason,
- hapticVibrationProvider);
+ Status ignoreStatus = shouldIgnoreHapticFeedback(constant, reason, hapticVibrationProvider);
if (ignoreStatus != null) {
logAndRecordPerformHapticFeedbackAttempt(uid, deviceId, opPkg, reason, ignoreStatus);
return null;
@@ -516,8 +516,7 @@
reason = "performHapticFeedbackForInputDevice(constant=" + constant + ", inputDeviceId="
+ inputDeviceId + ", inputSource=" + inputSource + "): " + reason;
HapticFeedbackVibrationProvider hapticVibrationProvider = getHapticVibrationProvider();
- Vibration.Status ignoreStatus = shouldIgnoreHapticFeedback(constant, reason,
- hapticVibrationProvider);
+ Status ignoreStatus = shouldIgnoreHapticFeedback(constant, reason, hapticVibrationProvider);
if (ignoreStatus != null) {
logAndRecordPerformHapticFeedbackAttempt(uid, deviceId, opPkg, reason, ignoreStatus);
return null;
@@ -533,7 +532,7 @@
VibrationAttributes attrs) {
if (effect == null) {
logAndRecordPerformHapticFeedbackAttempt(uid, deviceId, opPkg, reason,
- Vibration.Status.IGNORED_UNSUPPORTED);
+ Status.IGNORED_UNSUPPORTED);
Slog.w(TAG,
"performHapticFeedbackWithEffect; vibration absent for constant " + constant);
return null;
@@ -578,23 +577,21 @@
private HalVibration vibrateInternal(int uid, int deviceId, String opPkg,
@NonNull CombinedVibration effect, @NonNull VibrationAttributes attrs,
String reason, IBinder token) {
- Vibration.CallerInfo callerInfo =
- new Vibration.CallerInfo(attrs, uid, deviceId, opPkg, reason);
+ CallerInfo callerInfo = new CallerInfo(attrs, uid, deviceId, opPkg, reason);
if (token == null) {
Slog.e(TAG, "token must not be null");
- logAndRecordVibrationAttempt(effect, callerInfo, Vibration.Status.IGNORED_ERROR_TOKEN);
+ logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_ERROR_TOKEN);
return null;
}
if (effect.hasVendorEffects()
&& !hasPermission(android.Manifest.permission.VIBRATE_VENDOR_EFFECTS)) {
Slog.e(TAG, "vibrate; no permission for vendor effects");
- logAndRecordVibrationAttempt(effect, callerInfo,
- Vibration.Status.IGNORED_MISSING_PERMISSION);
+ logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_MISSING_PERMISSION);
return null;
}
enforceUpdateAppOpsStatsPermission(uid);
if (!isEffectValid(effect)) {
- logAndRecordVibrationAttempt(effect, callerInfo, Vibration.Status.IGNORED_UNSUPPORTED);
+ logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_UNSUPPORTED);
return null;
}
// Create Vibration.Stats as close to the received request as possible, for tracking.
@@ -625,11 +622,11 @@
final long ident = Binder.clearCallingIdentity();
try {
if (mCurrentExternalVibration != null) {
- mCurrentExternalVibration.mute();
+ mCurrentExternalVibration.notifyEnded();
vib.stats.reportInterruptedAnotherVibration(
mCurrentExternalVibration.callerInfo);
endExternalVibrateLocked(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
+ new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
vib.callerInfo),
/* continueExternalControl= */ false);
} else if (mCurrentVibration != null) {
@@ -645,7 +642,7 @@
vib.stats.reportInterruptedAnotherVibration(
mCurrentVibration.getVibration().callerInfo);
mCurrentVibration.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
+ new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
vib.callerInfo),
/* immediate= */ false);
}
@@ -677,7 +674,7 @@
Slog.d(TAG, "Canceling vibration");
}
Vibration.EndInfo cancelledByUserInfo =
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER);
final long ident = Binder.clearCallingIdentity();
try {
if (mNextVibration != null
@@ -693,9 +690,9 @@
}
if (mCurrentExternalVibration != null
&& shouldCancelVibration(
- mCurrentExternalVibration.externalVibration.getVibrationAttributes(),
+ mCurrentExternalVibration.getCallerInfo().attrs,
usageFilter)) {
- mCurrentExternalVibration.mute();
+ mCurrentExternalVibration.notifyEnded();
endExternalVibrateLocked(
cancelledByUserInfo, /* continueExternalControl= */ false);
}
@@ -860,7 +857,7 @@
: vibrationEndInfo.status));
}
mCurrentVibration.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE),
+ new Vibration.EndInfo(Status.CANCELLED_BY_SETTINGS_UPDATE),
/* immediate= */ false);
}
}
@@ -911,7 +908,7 @@
// Note that we don't consider pipelining here, because new pipelined ones should
// replace pending non-executing pipelined ones anyway.
clearNextVibrationLocked(
- new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED, vib.callerInfo));
+ new Vibration.EndInfo(Status.IGNORED_SUPERSEDED, vib.callerInfo));
mNextVibration = conductor;
return null;
} finally {
@@ -934,15 +931,15 @@
if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
// Shouldn't happen. The method call already logs a wtf.
mCurrentVibration = null; // Aborted.
- return new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_SCHEDULING);
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING);
}
return null;
case AppOpsManager.MODE_ERRORED:
Slog.w(TAG, "Start AppOpsManager operation errored for uid "
+ vib.callerInfo.uid);
- return new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_APP_OPS);
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
default:
- return new Vibration.EndInfo(Vibration.Status.IGNORED_APP_OPS);
+ return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -950,7 +947,7 @@
}
@GuardedBy("mLock")
- private void endVibrationLocked(HalVibration vib, Vibration.EndInfo vibrationEndInfo,
+ private void endVibrationLocked(Vibration vib, Vibration.EndInfo vibrationEndInfo,
boolean shouldWriteStats) {
vib.end(vibrationEndInfo);
logAndRecordVibration(vib.getDebugInfo());
@@ -960,15 +957,6 @@
}
}
- @GuardedBy("mLock")
- private void endVibrationAndWriteStatsLocked(ExternalVibrationHolder vib,
- Vibration.EndInfo vibrationEndInfo) {
- vib.end(vibrationEndInfo);
- logAndRecordVibration(vib.getDebugInfo());
- mFrameworkStatsLogger.writeVibrationReportedAsync(
- vib.getStatsInfo(/* completionUptimeMillis= */ SystemClock.uptimeMillis()));
- }
-
private VibrationStepConductor createVibrationStepConductor(HalVibration vib) {
CompletableFuture<Void> requestVibrationParamsFuture = null;
@@ -990,33 +978,32 @@
vib.scaleEffects(mVibrationScaler);
mInputDeviceDelegate.vibrateIfAvailable(vib.callerInfo, vib.getEffectToPlay());
- return new Vibration.EndInfo(Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
+ return new Vibration.EndInfo(Status.FORWARDED_TO_INPUT_DEVICES);
}
private void logAndRecordPerformHapticFeedbackAttempt(int uid, int deviceId, String opPkg,
- String reason, Vibration.Status status) {
- Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(
+ String reason, Status status) {
+ CallerInfo callerInfo = new CallerInfo(
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_UNKNOWN),
uid, deviceId, opPkg, reason);
logAndRecordVibrationAttempt(/* effect= */ null, callerInfo, status);
}
private void logAndRecordVibrationAttempt(@Nullable CombinedVibration effect,
- Vibration.CallerInfo callerInfo, Vibration.Status status) {
+ CallerInfo callerInfo, Status status) {
logAndRecordVibration(
- new Vibration.DebugInfo(status, new VibrationStats(),
+ new Vibration.DebugInfoImpl(status, new VibrationStats(),
effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE,
VibrationScaler.ADAPTIVE_SCALE_NONE, callerInfo));
}
- private void logAndRecordVibration(Vibration.DebugInfo info) {
+ private void logAndRecordVibration(DebugInfo info) {
info.logMetrics(mFrameworkStatsLogger);
- logVibrationStatus(info.mCallerInfo.uid, info.mCallerInfo.attrs, info.mStatus);
+ logVibrationStatus(info.getCallerInfo().uid, info.getCallerInfo().attrs, info.getStatus());
mVibratorManagerRecords.record(info);
}
- private void logVibrationStatus(int uid, VibrationAttributes attrs,
- Vibration.Status status) {
+ private void logVibrationStatus(int uid, VibrationAttributes attrs, Status status) {
switch (status) {
case IGNORED_BACKGROUND:
Slog.e(TAG, "Ignoring incoming vibration as process with"
@@ -1161,15 +1148,14 @@
if (ongoingVibrationImportance > newVibrationImportance) {
// Existing vibration has higher importance and should not be cancelled.
- return new Vibration.EndInfo(Vibration.Status.IGNORED_FOR_HIGHER_IMPORTANCE,
+ return new Vibration.EndInfo(Status.IGNORED_FOR_HIGHER_IMPORTANCE,
ongoingVibration.callerInfo);
}
// Same importance, use repeating as a tiebreaker.
if (ongoingVibration.isRepeating() && !newVibration.isRepeating()) {
// Ongoing vibration is repeating and new one is not, give priority to ongoing
- return new Vibration.EndInfo(Vibration.Status.IGNORED_FOR_ONGOING,
- ongoingVibration.callerInfo);
+ return new Vibration.EndInfo(Status.IGNORED_FOR_ONGOING, ongoingVibration.callerInfo);
}
// New vibration is repeating or this is a complete tie between them,
// give priority to new vibration.
@@ -1220,8 +1206,8 @@
*/
@GuardedBy("mLock")
@Nullable
- private Vibration.EndInfo shouldIgnoreVibrationLocked(Vibration.CallerInfo callerInfo) {
- Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(callerInfo);
+ private Vibration.EndInfo shouldIgnoreVibrationLocked(CallerInfo callerInfo) {
+ Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(callerInfo);
if (statusFromSettings != null) {
return new Vibration.EndInfo(statusFromSettings);
}
@@ -1231,9 +1217,9 @@
if (mode == AppOpsManager.MODE_ERRORED) {
// We might be getting calls from within system_server, so we don't actually
// want to throw a SecurityException here.
- return new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_APP_OPS);
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
} else {
- return new Vibration.EndInfo(Vibration.Status.IGNORED_APP_OPS);
+ return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
}
}
@@ -1241,16 +1227,16 @@
}
@Nullable
- private Vibration.Status shouldIgnoreHapticFeedback(int constant, String reason,
+ private Status shouldIgnoreHapticFeedback(int constant, String reason,
HapticFeedbackVibrationProvider hapticVibrationProvider) {
if (hapticVibrationProvider == null) {
Slog.e(TAG, reason + "; haptic vibration provider not ready.");
- return Vibration.Status.IGNORED_ERROR_SCHEDULING;
+ return Status.IGNORED_ERROR_SCHEDULING;
}
if (hapticVibrationProvider.isRestrictedHapticFeedback(constant)
&& !hasPermission(android.Manifest.permission.VIBRATE_SYSTEM_CONSTANTS)) {
Slog.w(TAG, reason + "; no permission for system constant " + constant);
- return Vibration.Status.IGNORED_MISSING_PERMISSION;
+ return Status.IGNORED_MISSING_PERMISSION;
}
return null;
}
@@ -1291,7 +1277,7 @@
* {@code attrs}. This will return one of the AppOpsManager.MODE_*.
*/
@GuardedBy("mLock")
- private int checkAppOpModeLocked(Vibration.CallerInfo callerInfo) {
+ private int checkAppOpModeLocked(CallerInfo callerInfo) {
int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
callerInfo.attrs.getAudioUsage(), callerInfo.uid, callerInfo.opPkg);
int fixedMode = fixupAppOpModeLocked(mode, callerInfo.attrs);
@@ -1306,7 +1292,7 @@
/** Start an operation in {@link AppOpsManager}, if allowed. */
@GuardedBy("mLock")
- private int startAppOpModeLocked(Vibration.CallerInfo callerInfo) {
+ private int startAppOpModeLocked(CallerInfo callerInfo) {
return fixupAppOpModeLocked(
mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg),
callerInfo.attrs);
@@ -1317,7 +1303,7 @@
* operation with same uid was previously started.
*/
@GuardedBy("mLock")
- private void finishAppOpModeLocked(Vibration.CallerInfo callerInfo) {
+ private void finishAppOpModeLocked(CallerInfo callerInfo) {
mAppOps.finishOp(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg);
}
@@ -1735,10 +1721,10 @@
*/
private static final class AlwaysOnVibration {
public final int alwaysOnId;
- public final Vibration.CallerInfo callerInfo;
+ public final CallerInfo callerInfo;
public final SparseArray<PrebakedSegment> effects;
- AlwaysOnVibration(int alwaysOnId, Vibration.CallerInfo callerInfo,
+ AlwaysOnVibration(int alwaysOnId, CallerInfo callerInfo,
SparseArray<PrebakedSegment> effects) {
this.alwaysOnId = alwaysOnId;
this.callerInfo = callerInfo;
@@ -1746,113 +1732,6 @@
}
}
- /** Holder for a {@link ExternalVibration}. */
- private final class ExternalVibrationHolder extends Vibration implements
- IBinder.DeathRecipient {
-
- public final ExternalVibration externalVibration;
- public final ExternalVibrationScale scale = new ExternalVibrationScale();
-
- private Vibration.Status mStatus;
-
- private ExternalVibrationHolder(ExternalVibration externalVibration) {
- super(externalVibration.getToken(), new Vibration.CallerInfo(
- externalVibration.getVibrationAttributes(), externalVibration.getUid(),
- // TODO(b/249785241): Find a way to link ExternalVibration to a VirtualDevice
- // instead of using DEVICE_ID_INVALID here and relying on the UID checks.
- Context.DEVICE_ID_INVALID, externalVibration.getPackage(), null));
- this.externalVibration = externalVibration;
- mStatus = Vibration.Status.RUNNING;
- }
-
- public void muteScale() {
- scale.scaleLevel = ExternalVibrationScale.ScaleLevel.SCALE_MUTE;
- if (Flags.hapticsScaleV2Enabled()) {
- scale.scaleFactor = 0;
- }
- }
-
- public void scale(VibrationScaler scaler, int usage) {
- scale.scaleLevel = scaler.getScaleLevel(usage);
- if (Flags.hapticsScaleV2Enabled()) {
- scale.scaleFactor = scaler.getScaleFactor(usage);
- }
- scale.adaptiveHapticsScale = scaler.getAdaptiveHapticsScale(usage);
- stats.reportAdaptiveScale(scale.adaptiveHapticsScale);
- }
-
- public void mute() {
- externalVibration.mute();
- }
-
- public void linkToDeath() {
- externalVibration.linkToDeath(this);
- }
-
- public void unlinkToDeath() {
- externalVibration.unlinkToDeath(this);
- }
-
- public boolean isHoldingSameVibration(ExternalVibration externalVibration) {
- return this.externalVibration.equals(externalVibration);
- }
-
- public void end(Vibration.EndInfo info) {
- if (mStatus != Vibration.Status.RUNNING) {
- // Already ended, ignore this call
- return;
- }
- mStatus = info.status;
- stats.reportEnded(info.endedBy);
-
- if (stats.hasStarted()) {
- // External vibration doesn't have feedback from total time the vibrator was playing
- // with non-zero amplitude, so we use the duration between start and end times of
- // the vibration as the time the vibrator was ON, since the haptic channels are
- // open for this duration and can receive vibration waveform data.
- stats.reportVibratorOn(
- stats.getEndUptimeMillis() - stats.getStartUptimeMillis());
- }
- }
-
- public void binderDied() {
- synchronized (mLock) {
- if (mCurrentExternalVibration != null) {
- if (DEBUG) {
- Slog.d(TAG, "External vibration finished because binder died");
- }
- endExternalVibrateLocked(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BINDER_DIED),
- /* continueExternalControl= */ false);
- }
- }
- }
-
- public Vibration.DebugInfo getDebugInfo() {
- return new Vibration.DebugInfo(mStatus, stats, /* playedEffect= */ null,
- /* originalEffect= */ null, scale.scaleLevel, scale.adaptiveHapticsScale,
- callerInfo);
- }
-
- public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
- return new VibrationStats.StatsInfo(
- externalVibration.getUid(),
- FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__EXTERNAL,
- externalVibration.getVibrationAttributes().getUsage(), mStatus, stats,
- completionUptimeMillis);
- }
-
- @Override
- boolean isRepeating() {
- // We don't currently know if the external vibration is repeating, so we just use a
- // heuristic based on the usage. Ideally this would be propagated in the
- // ExternalVibration.
- int usage = externalVibration.getVibrationAttributes().getUsage();
- return usage == VibrationAttributes.USAGE_RINGTONE
- || usage == VibrationAttributes.USAGE_ALARM;
- }
- }
-
/** Wrapper around the static-native methods of {@link VibratorManagerService} for tests. */
@VisibleForTesting
public static class NativeWrapper {
@@ -1912,7 +1791,7 @@
new VibrationRecords(recentVibrationSizeLimit, /* aggregationTimeLimit= */ 0);
}
- synchronized void record(Vibration.DebugInfo info) {
+ synchronized void record(DebugInfo info) {
GroupedAggregatedLogRecords.AggregatedLogRecord<VibrationRecord> droppedRecord =
mRecentVibrations.add(new VibrationRecord(info));
if (droppedRecord != null) {
@@ -1969,25 +1848,25 @@
}
/**
- * Record for a single {@link Vibration.DebugInfo}, that can be grouped by usage and aggregated
- * by UID, {@link VibrationAttributes} and {@link VibrationEffect}.
+ * Record for a single {@link DebugInfo}, that can be grouped by usage and aggregated by UID,
+ * {@link VibrationAttributes} and {@link CombinedVibration}.
*/
private static final class VibrationRecord
implements GroupedAggregatedLogRecords.SingleLogRecord {
- private final Vibration.DebugInfo mInfo;
+ private final DebugInfo mInfo;
- VibrationRecord(Vibration.DebugInfo info) {
+ VibrationRecord(DebugInfo info) {
mInfo = info;
}
@Override
public int getGroupKey() {
- return mInfo.mCallerInfo.attrs.getUsage();
+ return mInfo.getCallerInfo().attrs.getUsage();
}
@Override
public long getCreateUptimeMs() {
- return mInfo.mCreateTime;
+ return mInfo.getCreateUptimeMillis();
}
@Override
@@ -1995,10 +1874,10 @@
if (!(record instanceof VibrationRecord)) {
return false;
}
- Vibration.DebugInfo info = ((VibrationRecord) record).mInfo;
- return mInfo.mCallerInfo.uid == info.mCallerInfo.uid
- && Objects.equals(mInfo.mCallerInfo.attrs, info.mCallerInfo.attrs)
- && Objects.equals(mInfo.mPlayedEffect, info.mPlayedEffect);
+ DebugInfo info = ((VibrationRecord) record).mInfo;
+ return mInfo.getCallerInfo().uid == info.getCallerInfo().uid
+ && Objects.equals(mInfo.getCallerInfo().attrs, info.getCallerInfo().attrs)
+ && Objects.equals(mInfo.getDumpAggregationKey(), info.getDumpAggregationKey());
}
@Override
@@ -2048,7 +1927,8 @@
setExternalControl(false, mCurrentExternalVibration.stats);
}
// The external control was turned off, end it and report metrics right away.
- endVibrationAndWriteStatsLocked(mCurrentExternalVibration, vibrationEndInfo);
+ endVibrationLocked(mCurrentExternalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
mCurrentExternalVibration = null;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -2108,17 +1988,18 @@
@Override
public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) {
// Create Vibration.Stats as close to the received request as possible, for tracking.
- ExternalVibrationHolder vibHolder = new ExternalVibrationHolder(vib);
+ ExternalVibrationSession externalVibration = new ExternalVibrationSession(vib);
// Mute the request until we run all the checks and accept the vibration.
- vibHolder.muteScale();
+ externalVibration.muteScale();
boolean alreadyUnderExternalControl = false;
boolean waitForCompletion = false;
synchronized (mLock) {
if (!hasExternalControlCapability()) {
- endVibrationAndWriteStatsLocked(vibHolder,
- new Vibration.EndInfo(Vibration.Status.IGNORED_UNSUPPORTED));
- return vibHolder.scale;
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
}
if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
@@ -2127,44 +2008,46 @@
Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
+ " tried to play externally controlled vibration"
+ " without VIBRATE permission, ignoring.");
- endVibrationAndWriteStatsLocked(vibHolder,
- new Vibration.EndInfo(Vibration.Status.IGNORED_MISSING_PERMISSION));
- return vibHolder.scale;
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_MISSING_PERMISSION),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
}
Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(
- vibHolder.callerInfo);
+ externalVibration.callerInfo);
if (vibrationEndInfo == null
&& mCurrentExternalVibration != null
&& mCurrentExternalVibration.isHoldingSameVibration(vib)) {
// We are already playing this external vibration, so we can return the same
// scale calculated in the previous call to this method.
- return mCurrentExternalVibration.scale;
+ return mCurrentExternalVibration.getScale();
}
if (vibrationEndInfo == null) {
// Check if ongoing vibration is more important than this vibration.
- vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(vibHolder);
+ vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(externalVibration);
}
if (vibrationEndInfo != null) {
- endVibrationAndWriteStatsLocked(vibHolder, vibrationEndInfo);
- return vibHolder.scale;
+ endVibrationLocked(externalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
}
if (mCurrentExternalVibration == null) {
// If we're not under external control right now, then cancel any normal
// vibration that may be playing and ready the vibrator for external control.
if (mCurrentVibration != null) {
- vibHolder.stats.reportInterruptedAnotherVibration(
+ externalVibration.stats.reportInterruptedAnotherVibration(
mCurrentVibration.getVibration().callerInfo);
clearNextVibrationLocked(
- new Vibration.EndInfo(Vibration.Status.IGNORED_FOR_EXTERNAL,
- vibHolder.callerInfo));
+ new Vibration.EndInfo(Status.IGNORED_FOR_EXTERNAL,
+ externalVibration.callerInfo));
mCurrentVibration.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
- vibHolder.callerInfo),
+ new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
+ externalVibration.callerInfo),
/* immediate= */ true);
waitForCompletion = true;
}
@@ -2178,12 +2061,12 @@
// Note that this doesn't support multiple concurrent external controls, as we
// would need to mute the old one still if it came from a different controller.
alreadyUnderExternalControl = true;
- mCurrentExternalVibration.mute();
- vibHolder.stats.reportInterruptedAnotherVibration(
+ mCurrentExternalVibration.notifyEnded();
+ externalVibration.stats.reportInterruptedAnotherVibration(
mCurrentExternalVibration.callerInfo);
endExternalVibrateLocked(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
- vibHolder.callerInfo),
+ new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
+ externalVibration.callerInfo),
/* continueExternalControl= */ true);
}
@@ -2195,9 +2078,9 @@
mVibrationSettings.update();
}
- mCurrentExternalVibration = vibHolder;
- vibHolder.linkToDeath();
- vibHolder.scale(mVibrationScaler, attrs.getUsage());
+ mCurrentExternalVibration = externalVibration;
+ externalVibration.linkToDeath(this::onExternalVibrationBinderDied);
+ externalVibration.scale(mVibrationScaler, attrs.getUsage());
}
if (waitForCompletion) {
@@ -2206,27 +2089,27 @@
synchronized (mLock) {
// Trigger endExternalVibrateLocked to unlink to death recipient.
endExternalVibrateLocked(
- new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_CANCELLING),
+ new Vibration.EndInfo(Status.IGNORED_ERROR_CANCELLING),
/* continueExternalControl= */ false);
// Mute the request, vibration will be ignored.
- vibHolder.muteScale();
+ externalVibration.muteScale();
}
- return vibHolder.scale;
+ return externalVibration.getScale();
}
}
if (!alreadyUnderExternalControl) {
if (DEBUG) {
Slog.d(TAG, "Vibrator going under external control.");
}
- setExternalControl(true, vibHolder.stats);
+ setExternalControl(true, externalVibration.stats);
}
if (DEBUG) {
Slog.d(TAG, "Playing external vibration: " + vib);
}
// Vibrator will start receiving data from external channels after this point.
// Report current time as the vibration start time, for debugging.
- vibHolder.stats.reportStarted();
- return vibHolder.scale;
+ externalVibration.stats.reportStarted();
+ return externalVibration.getScale();
}
@Override
@@ -2238,7 +2121,7 @@
Slog.d(TAG, "Stopping external vibration: " + vib);
}
endExternalVibrateLocked(
- new Vibration.EndInfo(Vibration.Status.FINISHED),
+ new Vibration.EndInfo(Status.FINISHED),
/* continueExternalControl= */ false);
}
}
@@ -2252,6 +2135,19 @@
}
return false;
}
+
+ private void onExternalVibrationBinderDied() {
+ synchronized (mLock) {
+ if (mCurrentExternalVibration != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "External vibration finished because binder died");
+ }
+ endExternalVibrateLocked(
+ new Vibration.EndInfo(Status.CANCELLED_BINDER_DIED),
+ /* continueExternalControl= */ false);
+ }
+ }
+ }
}
/** Provide limited functionality from {@link VibratorManagerService} as shell commands. */
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 235a211..ebdf52c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -813,6 +813,8 @@
/** The last set {@link DropInputMode} for this activity surface. */
@DropInputMode
private int mLastDropInputMode = DropInputMode.NONE;
+ /** Whether the input to this activity will be dropped during the current playing animation. */
+ private boolean mIsInputDroppedForAnimation;
/**
* Whether the application has desk mode resources. Calculated and cached when
@@ -1647,6 +1649,15 @@
}
}
+ /** Sets if all input will be dropped as a protection during the client-driven animation. */
+ void setDropInputForAnimation(boolean isInputDroppedForAnimation) {
+ if (mIsInputDroppedForAnimation == isInputDroppedForAnimation) {
+ return;
+ }
+ mIsInputDroppedForAnimation = isInputDroppedForAnimation;
+ updateUntrustedEmbeddingInputProtection();
+ }
+
/**
* Sets to drop input when obscured to activity if it is embedded in untrusted mode.
*
@@ -1659,7 +1670,10 @@
if (getSurfaceControl() == null) {
return;
}
- if (isEmbeddedInUntrustedMode()) {
+ if (mIsInputDroppedForAnimation) {
+ // Disable all input during the animation.
+ setDropInputMode(DropInputMode.ALL);
+ } else if (isEmbeddedInUntrustedMode()) {
// Set drop input to OBSCURED when untrusted embedded.
setDropInputMode(DropInputMode.OBSCURED);
} else {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 197bd5a..ab02d49 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -97,6 +97,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -253,10 +254,12 @@
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
- // No AE remote animation with Shell transition.
- // Unfreeze the windows that were previously frozen for TaskFragment animation.
- unfreezeEmbeddedChangingWindows();
- overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+ // Check if there is any override
+ if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
+ // Unfreeze the windows that were previously frozen for TaskFragment animation.
+ unfreezeEmbeddedChangingWindows();
+ overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+ }
final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps)
|| containsVoiceInteraction(mDisplayContent.mOpeningApps);
@@ -687,6 +690,64 @@
}
/**
+ * Overrides the pending transition with the remote animation defined by the
+ * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
+ * {@link TaskFragment} that are organized by the same organizer.
+ *
+ * @return {@code true} if the transition is overridden.
+ */
+ private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
+ ArraySet<Integer> activityTypes) {
+ if (transitionMayContainNonAppWindows(transit)) {
+ return false;
+ }
+ if (!transitionContainsTaskFragmentWithBoundsOverride()) {
+ // No need to play TaskFragment remote animation if all embedded TaskFragment in the
+ // transition fill the Task.
+ return false;
+ }
+
+ final Task task = findParentTaskForAllEmbeddedWindows();
+ final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task);
+ final RemoteAnimationDefinition definition = organizer != null
+ ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
+ .getRemoteAnimationDefinition(organizer)
+ : null;
+ final RemoteAnimationAdapter adapter = definition != null
+ ? definition.getAdapter(transit, activityTypes)
+ : null;
+ if (adapter == null) {
+ return false;
+ }
+ mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(
+ adapter, false /* sync */, true /*isActivityEmbedding*/);
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+ "Override with TaskFragment remote animation for transit=%s",
+ AppTransition.appTransitionOldToString(transit));
+
+ final int organizerUid = mDisplayContent.mAtmService.mTaskFragmentOrganizerController
+ .getTaskFragmentOrganizerUid(organizer);
+ final boolean shouldDisableInputForRemoteAnimation = !task.isFullyTrustedEmbedding(
+ organizerUid);
+ final RemoteAnimationController remoteAnimationController =
+ mDisplayContent.mAppTransition.getRemoteAnimationController();
+ if (shouldDisableInputForRemoteAnimation && remoteAnimationController != null) {
+ // We are going to use client-driven animation, Disable all input on activity windows
+ // during the animation (unless it is fully trusted) to ensure it is safe to allow
+ // client to animate the surfaces.
+ // This is needed for all activity windows in the animation Task.
+ remoteAnimationController.setOnRemoteAnimationReady(() -> {
+ final Consumer<ActivityRecord> updateActivities =
+ activity -> activity.setDropInputForAnimation(true);
+ task.forAllActivities(updateActivities);
+ });
+ ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "Task=%d contains embedded TaskFragment."
+ + " Disabled all input during TaskFragment remote animation.", task.mTaskId);
+ }
+ return true;
+ }
+
+ /**
* Overrides the pending transition with the remote animation defined for the transition in the
* set of defined remote animations in the app window token.
*/
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index f8665c7..432089f 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -53,6 +53,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Helper class to run app animations in a remote process.
@@ -348,6 +349,10 @@
} finally {
mIsFinishing = false;
}
+ // Reset input for all activities when the remote animation is finished.
+ final Consumer<ActivityRecord> updateActivities =
+ activity -> activity.setDropInputForAnimation(false);
+ mDisplayContent.forAllActivities(updateActivities);
}
setRunningRemoteAnimation(false);
ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index e4a3176..5aa34d2 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -46,6 +46,7 @@
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
@@ -156,6 +157,13 @@
private final boolean mIsSystemOrganizer;
/**
+ * {@link RemoteAnimationDefinition} for embedded activities transition animation that is
+ * organized by this organizer.
+ */
+ @Nullable
+ private RemoteAnimationDefinition mRemoteAnimationDefinition;
+
+ /**
* Map from {@link TaskFragmentTransaction#getTransactionToken()} to the
* {@link Transition#getSyncId()} that has been deferred. {@link TransitionController} will
* wait until the organizer finished handling the {@link TaskFragmentTransaction}.
@@ -592,6 +600,50 @@
}
@Override
+ public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer,
+ @NonNull RemoteAnimationDefinition definition) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+ "Register remote animations for organizer=%s uid=%d pid=%d",
+ organizer.asBinder(), uid, pid);
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ if (organizerState == null) {
+ throw new IllegalStateException("The organizer hasn't been registered.");
+ }
+ if (organizerState.mRemoteAnimationDefinition != null) {
+ throw new IllegalStateException(
+ "The organizer has already registered remote animations="
+ + organizerState.mRemoteAnimationDefinition);
+ }
+
+ definition.setCallingPidUid(pid, uid);
+ organizerState.mRemoteAnimationDefinition = definition;
+ }
+ }
+
+ @Override
+ public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer) {
+ final int pid = Binder.getCallingPid();
+ final long uid = Binder.getCallingUid();
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+ "Unregister remote animations for organizer=%s uid=%d pid=%d",
+ organizer.asBinder(), uid, pid);
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ if (organizerState == null) {
+ Slog.e(TAG, "The organizer hasn't been registered.");
+ return;
+ }
+
+ organizerState.mRemoteAnimationDefinition = null;
+ }
+ }
+
+ @Override
public void setSavedState(@NonNull ITaskFragmentOrganizer organizer, @Nullable Bundle state) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -649,6 +701,25 @@
}
}
+ /**
+ * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
+ * {@code null} if it doesn't.
+ */
+ @Nullable
+ public RemoteAnimationDefinition getRemoteAnimationDefinition(
+ @NonNull ITaskFragmentOrganizer organizer) {
+ synchronized (mGlobalLock) {
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ if (organizerState == null) {
+ Slog.e(TAG, "TaskFragmentOrganizer has been unregistered or died when trying"
+ + " to play animation on its organized windows.");
+ return null;
+ }
+ return organizerState.mRemoteAnimationDefinition;
+ }
+ }
+
int getTaskFragmentOrganizerUid(@NonNull ITaskFragmentOrganizer organizer) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
return state.mOrganizerUid;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 6bfa32a..7f6dc84 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1057,9 +1057,8 @@
* needs to be passed/applied in shell because until finish is called, shell owns the surfaces.
* Additionally, this gives shell the ability to better deal with merged transitions.
*/
- private void buildFinishTransaction(SurfaceControl.Transaction t, TransitionInfo info) {
- // usually only size 1
- final ArraySet<DisplayContent> displays = new ArraySet<>();
+ private void buildFinishTransaction(SurfaceControl.Transaction t, TransitionInfo info,
+ DisplayContent[] participantDisplays) {
for (int i = mTargets.size() - 1; i >= 0; --i) {
final WindowContainer<?> target = mTargets.get(i).mContainer;
if (target.getParent() == null) continue;
@@ -1071,7 +1070,6 @@
t.setCornerRadius(targetLeash, 0);
t.setShadowRadius(targetLeash, 0);
t.setAlpha(targetLeash, 1);
- displays.add(target.getDisplayContent());
// For config-at-end, the end-transform will be reset after the config is actually
// applied in the client (since the transform depends on config). The other properties
// remain here because shell might want to persistently override them.
@@ -1085,9 +1083,8 @@
}
// Need to update layers on involved displays since they were all paused while
// the animation played. This puts the layers back into the correct order.
- for (int i = displays.size() - 1; i >= 0; --i) {
- if (displays.valueAt(i) == null) continue;
- assignLayers(displays.valueAt(i), t);
+ for (int i = participantDisplays.length - 1; i >= 0; --i) {
+ assignLayers(participantDisplays[i], t);
}
for (int i = 0; i < info.getRootCount(); ++i) {
@@ -1800,6 +1797,8 @@
mController.moveToPlaying(this);
// Repopulate the displays based on the resolved targets.
+ final DisplayContent[] participantDisplays = mTargetDisplays.toArray(
+ new DisplayContent[mTargetDisplays.size()]);
mTargetDisplays.clear();
for (int i = 0; i < info.getRootCount(); ++i) {
final DisplayContent dc = mController.mAtm.mRootWindowContainer.getDisplayContent(
@@ -1893,7 +1892,9 @@
controller.setupStartTransaction(transaction);
}
}
- buildFinishTransaction(mFinishTransaction, info);
+ // Use participant displays here (rather than just targets) because it's possible for
+ // there to be order changes between non-top tasks in an otherwise no-op transition.
+ buildFinishTransaction(mFinishTransaction, info, participantDisplays);
mCleanupTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
buildCleanupTransaction(mCleanupTransaction, info);
if (mController.getTransitionPlayer() != null && mIsPlayerEnabled) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 979b3a5..e3ceb33 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7920,7 +7920,7 @@
}
boolean allWindowsDrawn = false;
synchronized (mGlobalLock) {
- if (displayId == DEFAULT_DISPLAY
+ if ((displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY)
&& mRoot.getDefaultDisplay().mDisplayUpdater.waitForTransition(message)) {
// Use the ready-to-play of transition as the signal.
return;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 5eec012..b982098 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -1325,11 +1325,6 @@
pw.print("encryptionRequested=");
pw.println(encryptionRequested);
- if (!Flags.policyEngineMigrationV2Enabled()) {
- pw.print("mUsbDataSignaling=");
- pw.println(mUsbDataSignalingEnabled);
- }
-
pw.print("disableCallerId=");
pw.println(disableCallerId);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index a08af72..4beb6a8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -230,11 +230,9 @@
synchronized (mLock) {
PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- if (!handleAdminPolicySizeLimit(localPolicyState, enforcingAdmin, value,
- policyDefinition, userId)) {
- return;
- }
+ if (!handleAdminPolicySizeLimit(localPolicyState, enforcingAdmin, value,
+ policyDefinition, userId)) {
+ return;
}
if (policyDefinition.isNonCoexistablePolicy()) {
@@ -354,9 +352,7 @@
}
PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- decreasePolicySizeForAdmin(localPolicyState, enforcingAdmin);
- }
+ decreasePolicySizeForAdmin(localPolicyState, enforcingAdmin);
if (policyDefinition.isNonCoexistablePolicy()) {
setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState,
@@ -500,11 +496,9 @@
synchronized (mLock) {
PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- if (!handleAdminPolicySizeLimit(globalPolicyState, enforcingAdmin, value,
- policyDefinition, UserHandle.USER_ALL)) {
- return;
- }
+ if (!handleAdminPolicySizeLimit(globalPolicyState, enforcingAdmin, value,
+ policyDefinition, UserHandle.USER_ALL)) {
+ return;
}
// TODO(b/270999567): Move error handling for DISALLOW_CELLULAR_2G into the code
// that honors the restriction once there's an API available
@@ -571,9 +565,7 @@
synchronized (mLock) {
PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition);
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- decreasePolicySizeForAdmin(policyState, enforcingAdmin);
- }
+ decreasePolicySizeForAdmin(policyState, enforcingAdmin);
boolean policyChanged = policyState.removePolicy(enforcingAdmin);
@@ -1739,25 +1731,23 @@
pw.println();
}
pw.decreaseIndent();
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- pw.println();
+ pw.println();
- pw.println("Default admin policy size limit: " + DEFAULT_POLICY_SIZE_LIMIT);
- pw.println("Current admin policy size limit: " + mPolicySizeLimit);
- pw.println("Admin Policies size: ");
- for (int i = 0; i < mAdminPolicySize.size(); i++) {
- int userId = mAdminPolicySize.keyAt(i);
- pw.printf("User %d:\n", userId);
- pw.increaseIndent();
- for (EnforcingAdmin admin : mAdminPolicySize.get(userId).keySet()) {
- pw.printf("Admin : " + admin + " : " + mAdminPolicySize.get(userId).get(
- admin));
- pw.println();
- }
- pw.decreaseIndent();
+ pw.println("Default admin policy size limit: " + DEFAULT_POLICY_SIZE_LIMIT);
+ pw.println("Current admin policy size limit: " + mPolicySizeLimit);
+ pw.println("Admin Policies size: ");
+ for (int i = 0; i < mAdminPolicySize.size(); i++) {
+ int userId = mAdminPolicySize.keyAt(i);
+ pw.printf("User %d:\n", userId);
+ pw.increaseIndent();
+ for (EnforcingAdmin admin : mAdminPolicySize.get(userId).keySet()) {
+ pw.printf("Admin : " + admin + " : " + mAdminPolicySize.get(userId).get(
+ admin));
+ pw.println();
}
pw.decreaseIndent();
}
+ pw.decreaseIndent();
}
}
@@ -2018,23 +2008,21 @@
private void writeEnforcingAdminSizeInner(TypedXmlSerializer serializer)
throws IOException {
- if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- if (mAdminPolicySize != null) {
- for (int i = 0; i < mAdminPolicySize.size(); i++) {
- int userId = mAdminPolicySize.keyAt(i);
- for (EnforcingAdmin admin : mAdminPolicySize.get(
- userId).keySet()) {
- serializer.startTag(/* namespace= */ null,
- TAG_ENFORCING_ADMIN_AND_SIZE);
- serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN);
- admin.saveToXml(serializer);
- serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN);
- serializer.startTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE);
- serializer.attributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE,
- mAdminPolicySize.get(userId).get(admin));
- serializer.endTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE);
- serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_AND_SIZE);
- }
+ if (mAdminPolicySize != null) {
+ for (int i = 0; i < mAdminPolicySize.size(); i++) {
+ int userId = mAdminPolicySize.keyAt(i);
+ for (EnforcingAdmin admin : mAdminPolicySize.get(
+ userId).keySet()) {
+ serializer.startTag(/* namespace= */ null,
+ TAG_ENFORCING_ADMIN_AND_SIZE);
+ serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN);
+ admin.saveToXml(serializer);
+ serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN);
+ serializer.startTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE);
+ serializer.attributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE,
+ mAdminPolicySize.get(userId).get(admin));
+ serializer.endTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE);
+ serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_AND_SIZE);
}
}
}
@@ -2042,9 +2030,6 @@
private void writeMaxPolicySizeInner(TypedXmlSerializer serializer)
throws IOException {
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- return;
- }
serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
serializer.attributeInt(
/* namespace= */ null, ATTR_POLICY_SUM_SIZE, mPolicySizeLimit);
@@ -2192,9 +2177,6 @@
private void readMaxPolicySizeInner(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- return;
- }
mPolicySizeLimit = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 4abbdee..470025a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -871,6 +871,16 @@
EXEMPT_FROM_POWER_RESTRICTIONS, OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS);
}
+ private static final Set<String> METERED_DATA_RESTRICTION_EXEMPT_ROLES =
+ new ArraySet<>();
+ static {
+ // TODO(b/362545319): reference role name from role manager once it's exposed.
+ final String roleDeviceLockController =
+ "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER";
+ METERED_DATA_RESTRICTION_EXEMPT_ROLES.add(roleDeviceLockController);
+ METERED_DATA_RESTRICTION_EXEMPT_ROLES.add(RoleManager.ROLE_FINANCED_DEVICE_KIOSK);
+ }
+
/**
* Admin apps targeting Android S+ may not use
* {@link android.app.admin.DevicePolicyManager#setPasswordQuality} to set password quality
@@ -1318,9 +1328,7 @@
Bundle prevRestrictions) {
resetCrossProfileIntentFiltersIfNeeded(userId, newRestrictions, prevRestrictions);
resetUserVpnIfNeeded(userId, newRestrictions, prevRestrictions);
- if (Flags.deletePrivateSpaceUnderRestriction()) {
- removePrivateSpaceIfRestrictionIsSet(userId, newRestrictions, prevRestrictions);
- }
+ removePrivateSpaceIfRestrictionIsSet(userId, newRestrictions, prevRestrictions);
}
private void resetUserVpnIfNeeded(
@@ -1959,6 +1967,10 @@
return UserManager.isHeadlessSystemUserMode();
}
+ List<String> roleManagerGetRoleHoldersAsUser(String role, UserHandle userHandle) {
+ return getRoleManager().getRoleHoldersAsUser(role, userHandle);
+ }
+
@SuppressWarnings("AndroidFrameworkPendingIntentMutability")
PendingIntent pendingIntentGetActivityAsUser(Context context, int requestCode,
@NonNull Intent intent, int flags, Bundle options, UserHandle user) {
@@ -3681,9 +3693,6 @@
}
revertTransferOwnershipIfNecessaryLocked();
- if (!Flags.policyEngineMigrationV2Enabled()) {
- updateUsbDataSignal(mContext, isUsbDataSignalingEnabledInternalLocked());
- }
}
// Check whether work apps were paused via suspension and unsuspend if necessary.
@@ -7142,9 +7151,7 @@
// If there is a profile owner, redirect to that; otherwise query the device owner.
ComponentName aliasChooser = getProfileOwnerAsUser(caller.getUserId());
- boolean isDoUser = Flags.headlessSingleUserFixes()
- ? caller.getUserId() == getDeviceOwnerUserId()
- : caller.getUserHandle().isSystem();
+ boolean isDoUser = caller.getUserId() == getDeviceOwnerUserId();
if (aliasChooser == null && isDoUser) {
synchronized (getLockObject()) {
final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
@@ -8154,7 +8161,7 @@
// First check whether the admin is allowed to wipe the device/user/profile.
final String restriction;
boolean shouldFactoryReset = userId == UserHandle.USER_SYSTEM;
- if (Flags.headlessSingleUserFixes() && getHeadlessDeviceOwnerModeForDeviceOwner()
+ if (getHeadlessDeviceOwnerModeForDeviceOwner()
== HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER) {
shouldFactoryReset = userId == getMainUserId();
}
@@ -8178,8 +8185,7 @@
adminPackage,
userId)) {
// Legacy mode
- wipeDevice = Flags.headlessSingleUserFixes()
- && getHeadlessDeviceOwnerModeForDeviceOwner()
+ wipeDevice = getHeadlessDeviceOwnerModeForDeviceOwner()
== HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER ? isMainUser : isSystemUser;
} else {
// Explicit behaviour
@@ -9363,8 +9369,7 @@
void sendDeviceOwnerOrProfileOwnerCommand(String action, Bundle extras, int userId) {
if (userId == UserHandle.USER_ALL) {
- if (Flags.headlessDeviceOwnerDelegateSecurityLoggingBugFix()
- && getHeadlessDeviceOwnerModeForDeviceOwner()
+ if (getHeadlessDeviceOwnerModeForDeviceOwner()
== HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER) {
userId = mOwners.getDeviceOwnerUserId();
} else {
@@ -11850,7 +11855,7 @@
}
setBackwardsCompatibleAppRestrictions(
caller, packageName, restrictions, caller.getUserHandle());
- } else if (Flags.dmrhSetAppRestrictions()) {
+ } else {
final boolean isRoleHolder;
if (who != null) {
// DO or PO
@@ -11897,15 +11902,6 @@
caller.getUserHandle());
});
}
- } else {
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller,
- DELEGATION_APP_RESTRICTIONS)));
- mInjector.binderWithCleanCallingIdentity(() -> {
- mUserManager.setApplicationRestrictions(packageName, restrictions,
- caller.getUserHandle());
- });
}
DevicePolicyEventLogger
@@ -12438,12 +12434,6 @@
}
if (packageList != null) {
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- for (String pkg : packageList) {
- PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
- }
- }
-
List<InputMethodInfo> enabledImes = mInjector.binderWithCleanCallingIdentity(() ->
InputMethodManagerInternal.get().getEnabledInputMethodListAsUser(userId));
if (enabledImes != null) {
@@ -13242,7 +13232,7 @@
return Bundle.EMPTY;
}
return policies.get(enforcingAdmin).getValue();
- } else if (Flags.dmrhSetAppRestrictions()) {
+ } else {
final boolean isRoleHolder;
if (who != null) {
// Caller is DO or PO. They cannot call this on parent
@@ -13285,19 +13275,6 @@
return bundle != null ? bundle : Bundle.EMPTY;
});
}
-
- } else {
- Preconditions.checkCallAuthorization((caller.hasAdminComponent()
- && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller,
- DELEGATION_APP_RESTRICTIONS)));
- return mInjector.binderWithCleanCallingIdentity(() -> {
- Bundle bundle = mUserManager.getApplicationRestrictions(packageName,
- caller.getUserHandle());
- // if no restrictions were saved, mUserManager.getApplicationRestrictions
- // returns null, but DPM method should return an empty Bundle as per JavaDoc
- return bundle != null ? bundle : Bundle.EMPTY;
- });
}
}
@@ -14306,10 +14283,6 @@
return;
}
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- PolicySizeVerifier.enforceMaxStringLength(accountType, "account type");
- }
-
CallerIdentity caller = getCallerIdentity(who, callerPackageName);
synchronized (getLockObject()) {
int affectedUser = getAffectedUser(parent);
@@ -14920,11 +14893,6 @@
public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)
throws SecurityException {
Objects.requireNonNull(packages, "packages is null");
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- for (String pkg : packages) {
- PolicySizeVerifier.enforceMaxPackageNameLength(pkg);
- }
- }
CallerIdentity caller = getCallerIdentity(who, callerPackageName);
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_PACKAGES);
@@ -15205,7 +15173,7 @@
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(
isProfileOwner(caller) || isDefaultDeviceOwner(caller));
- if (Flags.allowScreenBrightnessControlOnCope() && parent) {
+ if (parent) {
Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
}
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_SYSTEM_SETTING);
@@ -15216,7 +15184,7 @@
"Permission denial: device owners cannot update %1$s", setting));
}
int affectedUser;
- if (Flags.allowScreenBrightnessControlOnCope() && parent) {
+ if (parent) {
affectedUser = getProfileParentId(caller.getUserId());
} else {
affectedUser = caller.getUserId();
@@ -16808,13 +16776,11 @@
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
- if (Flags.permissionMigrationForZeroTrustImplEnabled()) {
- final UserHandle user = UserHandle.of(userId);
- final String roleHolderPackage = getRoleHolderPackageNameOnUser(
- RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, userId);
- if (roleHolderPackage != null) {
- broadcastExplicitIntentToPackage(intent, roleHolderPackage, user);
- }
+ final UserHandle user = UserHandle.of(userId);
+ final String roleHolderPackage = getRoleHolderPackageNameOnUser(
+ RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, userId);
+ if (roleHolderPackage != null) {
+ broadcastExplicitIntentToPackage(intent, roleHolderPackage, user);
}
}
});
@@ -16822,18 +16788,10 @@
@Override
public SystemUpdateInfo getPendingSystemUpdate(ComponentName admin, String callerPackage) {
- if (Flags.permissionMigrationForZeroTrustImplEnabled()) {
- CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- enforcePermissions(new String[] {NOTIFY_PENDING_SYSTEM_UPDATE,
- MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES}, caller.getPackageName(),
- caller.getUserId());
- } else {
- Objects.requireNonNull(admin, "ComponentName is null");
-
- final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isProfileOwner(caller));
- }
+ CallerIdentity caller = getCallerIdentity(admin, callerPackage);
+ enforcePermissions(new String[] {NOTIFY_PENDING_SYSTEM_UPDATE,
+ MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES}, caller.getPackageName(),
+ caller.getUserId());
return mOwners.getSystemUpdateInfo();
}
@@ -17377,17 +17335,10 @@
@Nullable ComponentName componentName, @UserIdInt int callingUserId) {
synchronized (getLockObject()) {
int deviceOwnerUserId = -1;
- if (Flags.headlessDeviceOwnerProvisioningFixEnabled()) {
- deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode()
- && getHeadlessDeviceOwnerModeForDeviceAdmin(componentName, callingUserId)
- == HEADLESS_DEVICE_OWNER_MODE_AFFILIATED
- ? UserHandle.USER_SYSTEM : callingUserId;
- } else {
- deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode()
- && getHeadlessDeviceOwnerModeForDeviceOwner()
- == HEADLESS_DEVICE_OWNER_MODE_AFFILIATED
- ? UserHandle.USER_SYSTEM : callingUserId;
- }
+ deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode()
+ && getHeadlessDeviceOwnerModeForDeviceAdmin(componentName, callingUserId)
+ == HEADLESS_DEVICE_OWNER_MODE_AFFILIATED
+ ? UserHandle.USER_SYSTEM : callingUserId;
Slogf.i(LOG_TAG, "Calling user %d, device owner will be set on user %d",
callingUserId, deviceOwnerUserId);
// hasIncompatibleAccountsOrNonAdb doesn't matter since the caller is not adb.
@@ -17900,15 +17851,28 @@
});
}
+ private Set<String> getMeteredDataRestrictionExemptPackages(int userId) {
+ final Set<String> exemptPkgs = new ArraySet<>();
+ for (String role: METERED_DATA_RESTRICTION_EXEMPT_ROLES) {
+ String pkg = getRoleHolderPackageNameOnUser(role, userId);
+ if (pkg != null) {
+ exemptPkgs.add(pkg);
+ }
+ }
+
+ return exemptPkgs;
+ }
+
private List<String> removeInvalidPkgsForMeteredDataRestriction(
int userId, List<String> pkgNames) {
+ final Set<String> exemptRolePkgs = getMeteredDataRestrictionExemptPackages(userId);
synchronized (getLockObject()) {
final Set<String> activeAdmins = getActiveAdminPackagesLocked(userId);
final List<String> excludedPkgs = new ArrayList<>();
for (int i = pkgNames.size() - 1; i >= 0; --i) {
final String pkgName = pkgNames.get(i);
- // If the package is an active admin, don't restrict it.
- if (activeAdmins.contains(pkgName)) {
+ // If the package is an active admin or exempt role, don't restrict it.
+ if (activeAdmins.contains(pkgName) || exemptRolePkgs.contains(pkgName)) {
excludedPkgs.add(pkgName);
continue;
}
@@ -18673,8 +18637,7 @@
// Backup service has to be enabled on the main user in order for it to be enabled on
// secondary users.
- if (Flags.headlessSingleUserFixes() && isDeviceOwner(caller)
- && getHeadlessDeviceOwnerModeForDeviceOwner()
+ if (isDeviceOwner(caller) && getHeadlessDeviceOwnerModeForDeviceOwner()
== HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER) {
toggleBackupServiceActive(UserHandle.USER_SYSTEM, enabled);
}
@@ -21415,13 +21378,7 @@
final CallerIdentity caller = getCallerIdentity(callerPackage);
- if (Flags.permissionMigrationForZeroTrustImplEnabled()) {
- enforcePermission(MANAGE_DEVICE_POLICY_CERTIFICATES, caller.getPackageName());
- } else {
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
- }
+ enforcePermission(MANAGE_DEVICE_POLICY_CERTIFICATES, caller.getPackageName());
synchronized (getLockObject()) {
final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked(
caller.getUserId());
@@ -21749,8 +21706,6 @@
*/
@Nullable
private String getRoleHolderPackageNameOnUser(String role, int userId) {
- RoleManager roleManager = mContext.getSystemService(RoleManager.class);
-
// Clear calling identity as the RoleManager APIs require privileged permissions.
return mInjector.binderWithCleanCallingIdentity(() -> {
List<UserInfo> users;
@@ -21762,7 +21717,7 @@
}
for (UserInfo user : users) {
List<String> roleHolders =
- roleManager.getRoleHoldersAsUser(role, user.getUserHandle());
+ mInjector.roleManagerGetRoleHoldersAsUser(role, user.getUserHandle());
if (!roleHolders.isEmpty()) {
return roleHolders.get(0);
}
@@ -22022,16 +21977,9 @@
final long identity = Binder.clearCallingIdentity();
try {
boolean isSingleUserMode;
- if (Flags.headlessDeviceOwnerProvisioningFixEnabled()) {
- int headlessDeviceOwnerMode = getHeadlessDeviceOwnerModeForDeviceAdmin(
- deviceAdmin, caller.getUserId());
- isSingleUserMode =
- headlessDeviceOwnerMode == HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
- } else {
- isSingleUserMode =
- getHeadlessDeviceOwnerModeForDeviceOwner()
- == HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
- }
+ int headlessDeviceOwnerMode = getHeadlessDeviceOwnerModeForDeviceAdmin(
+ deviceAdmin, caller.getUserId());
+ isSingleUserMode = headlessDeviceOwnerMode == HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
if (Flags.headlessSingleMinTargetSdk()
&& mInjector.userManagerIsHeadlessSystemUserMode()
@@ -22430,35 +22378,17 @@
Objects.requireNonNull(packageName, "Admin package name must be provided");
final CallerIdentity caller = getCallerIdentity(packageName);
- if (!Flags.policyEngineMigrationV2Enabled()) {
- Preconditions.checkCallAuthorization(
- isDefaultDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(caller),
- "USB data signaling can only be controlled by a device owner or "
- + "a profile owner on an organization-owned device.");
+ synchronized (getLockObject()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ /* admin= */ null, MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
+ caller.getPackageName(),
+ caller.getUserId());
Preconditions.checkState(canUsbDataSignalingBeDisabled(),
"USB data signaling cannot be disabled.");
- }
-
- synchronized (getLockObject()) {
- if (Flags.policyEngineMigrationV2Enabled()) {
- EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
- /* admin= */ null, MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- caller.getPackageName(),
- caller.getUserId());
- Preconditions.checkState(canUsbDataSignalingBeDisabled(),
- "USB data signaling cannot be disabled.");
- mDevicePolicyEngine.setGlobalPolicy(
- PolicyDefinition.USB_DATA_SIGNALING,
- enforcingAdmin,
- new BooleanPolicyValue(enabled));
- } else {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
- if (admin.mUsbDataSignalingEnabled != enabled) {
- admin.mUsbDataSignalingEnabled = enabled;
- saveSettingsLocked(caller.getUserId());
- updateUsbDataSignal(mContext, isUsbDataSignalingEnabledInternalLocked());
- }
- }
+ mDevicePolicyEngine.setGlobalPolicy(
+ PolicyDefinition.USB_DATA_SIGNALING,
+ enforcingAdmin,
+ new BooleanPolicyValue(enabled));
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_USB_DATA_SIGNALING)
@@ -22480,24 +22410,10 @@
@Override
public boolean isUsbDataSignalingEnabled(String packageName) {
final CallerIdentity caller = getCallerIdentity(packageName);
- if (Flags.policyEngineMigrationV2Enabled()) {
- Boolean enabled = mDevicePolicyEngine.getResolvedPolicy(
- PolicyDefinition.USB_DATA_SIGNALING,
- caller.getUserId());
- return enabled == null || enabled;
- } else {
- synchronized (getLockObject()) {
- // If the caller is an admin, return the policy set by itself. Otherwise
- // return the device-wide policy.
- if (isDefaultDeviceOwner(caller) || isProfileOwnerOfOrganizationOwnedDevice(
- caller)) {
- return getProfileOwnerOrDeviceOwnerLocked(
- caller.getUserId()).mUsbDataSignalingEnabled;
- } else {
- return isUsbDataSignalingEnabledInternalLocked();
- }
- }
- }
+ Boolean enabled = mDevicePolicyEngine.getResolvedPolicy(
+ PolicyDefinition.USB_DATA_SIGNALING,
+ caller.getUserId());
+ return enabled == null || enabled;
}
private boolean isUsbDataSignalingEnabledInternalLocked() {
@@ -24850,9 +24766,6 @@
@Override
public void setMaxPolicyStorageLimit(String callerPackageName, int storageLimit) {
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- return;
- }
CallerIdentity caller = getCallerIdentity(callerPackageName);
enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(),
caller.getUserId());
@@ -24866,9 +24779,6 @@
@Override
public int getMaxPolicyStorageLimit(String callerPackageName) {
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- return -1;
- }
CallerIdentity caller = getCallerIdentity(callerPackageName);
enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(),
caller.getUserId());
@@ -24878,9 +24788,6 @@
@Override
public void forceSetMaxPolicyStorageLimit(String callerPackageName, int storageLimit) {
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- return;
- }
CallerIdentity caller = getCallerIdentity(callerPackageName);
enforcePermission(MANAGE_DEVICE_POLICY_STORAGE_LIMIT, caller.getPackageName(),
caller.getUserId());
@@ -24891,9 +24798,6 @@
@Override
public int getPolicySizeForAdmin(
String callerPackageName, android.app.admin.EnforcingAdmin admin) {
- if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {
- return -1;
- }
CallerIdentity caller = getCallerIdentity(callerPackageName);
enforcePermission(MANAGE_DEVICE_POLICY_STORAGE_LIMIT, caller.getPackageName(),
caller.getUserId());
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c5c371f..13c436d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,7 +16,6 @@
package com.android.server;
-import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
@@ -38,6 +37,7 @@
import android.app.INotificationManager;
import android.app.SystemServiceRegistry;
import android.app.admin.DevicePolicySafetyChecker;
+import android.app.appfunctions.AppFunctionManagerConfiguration;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -1743,12 +1743,11 @@
mSystemServiceManager.startService(LogcatManagerService.class);
t.traceEnd();
- t.traceBegin("StartAppFunctionManager");
- if (enableAppFunctionManager()) {
+ if (AppFunctionManagerConfiguration.isSupported(context)) {
+ t.traceBegin("StartAppFunctionManager");
mSystemServiceManager.startService(AppFunctionManagerService.class);
+ t.traceEnd();
}
- t.traceEnd();
-
} catch (Throwable e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service");
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
index f690b1b..2d4a29b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertEquals;
+import android.hardware.display.BrightnessInfo;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -112,7 +114,10 @@
.append("\n mBrightnessAdjustmentFlag:")
.append(displayBrightnessState.getBrightnessAdjustmentFlag())
.append("\n mIsUserInitiatedChange:")
- .append(displayBrightnessState.isUserInitiatedChange());
+ .append(displayBrightnessState.isUserInitiatedChange())
+ .append("\n mBrightnessMaxReason:")
+ .append(BrightnessInfo.briMaxReasonToString(
+ displayBrightnessState.getBrightnessMaxReason()));
return sb.toString();
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
index 0ce9233..0a03702 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
@@ -31,7 +31,6 @@
import android.content.Context;
import android.hardware.SensorManager;
-import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.PowerManager;
@@ -161,12 +160,6 @@
}
@Test
- public void testMaxReasonIsNoneOnInit() {
- assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE,
- mClamperController.getBrightnessMaxReason());
- }
-
- @Test
public void testOnDisplayChanged_DelegatesToClamper() {
mClamperController.onDisplayChanged(mMockDisplayDeviceData);
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/CrashRecoveryUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/CrashRecoveryUtilsTest.java
new file mode 100644
index 0000000..6f38fca
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/CrashRecoveryUtilsTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2024 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.crashrecovery;
+
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.quality.Strictness.LENIENT;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.os.Environment;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+
+/**
+ * Test CrashRecovery Utils.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CrashRecoveryUtilsTest {
+
+ private MockitoSession mStaticMockSession;
+ private final String mLogMsg = "Logging from test";
+ private final String mCrashrecoveryEventTag = "CrashRecovery Events: ";
+ private File mCacheDir;
+
+ @Before
+ public void setup() throws IOException {
+ Context context = ApplicationProvider.getApplicationContext();
+ mCacheDir = context.getCacheDir();
+ mStaticMockSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Environment.class)
+ .strictness(LENIENT)
+ .startMocking();
+ ExtendedMockito.doReturn(mCacheDir).when(() -> Environment.getDataDirectory());
+
+ createCrashRecoveryEventsTempDir();
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ mStaticMockSession.finishMocking();
+ deleteCrashRecoveryEventsTempFile();
+ }
+
+ @Test
+ public void testCrashRecoveryUtils() {
+ testLogCrashRecoveryEvent();
+ testDumpCrashRecoveryEvents();
+ }
+
+ @Test
+ public void testDumpCrashRecoveryEventsWithoutAnyLogs() {
+ assertThat(getCrashRecoveryEventsTempFile().exists()).isFalse();
+ StringWriter sw = new StringWriter();
+ IndentingPrintWriter ipw = new IndentingPrintWriter(sw, " ");
+ CrashRecoveryUtils.dumpCrashRecoveryEvents(ipw);
+ ipw.close();
+
+ String dump = sw.getBuffer().toString();
+ assertThat(dump).contains(mCrashrecoveryEventTag);
+ assertThat(dump).doesNotContain(mLogMsg);
+ }
+
+ private void testLogCrashRecoveryEvent() {
+ assertThat(getCrashRecoveryEventsTempFile().exists()).isFalse();
+ CrashRecoveryUtils.logCrashRecoveryEvent(Log.WARN, mLogMsg);
+
+ assertThat(getCrashRecoveryEventsTempFile().exists()).isTrue();
+ String fileContent = null;
+ try {
+ File file = getCrashRecoveryEventsTempFile();
+ FileInputStream fis = new FileInputStream(file);
+ byte[] data = new byte[(int) file.length()];
+ fis.read(data);
+ fis.close();
+ fileContent = new String(data, StandardCharsets.UTF_8);
+ } catch (Exception e) {
+ fail("Unable to read the events file");
+ }
+ assertThat(fileContent).contains(mLogMsg);
+ }
+
+ private void testDumpCrashRecoveryEvents() {
+ StringWriter sw = new StringWriter();
+ IndentingPrintWriter ipw = new IndentingPrintWriter(sw, " ");
+ CrashRecoveryUtils.dumpCrashRecoveryEvents(ipw);
+ ipw.close();
+
+ String dump = sw.getBuffer().toString();
+ assertThat(dump).contains(mCrashrecoveryEventTag);
+ assertThat(dump).contains(mLogMsg);
+ }
+
+ private void createCrashRecoveryEventsTempDir() throws IOException {
+ Files.deleteIfExists(getCrashRecoveryEventsTempFile().toPath());
+ File mMockDirectory = new File(mCacheDir, "system");
+ if (!mMockDirectory.exists()) {
+ assertThat(mMockDirectory.mkdir()).isTrue();
+ }
+ }
+
+ private void deleteCrashRecoveryEventsTempFile() throws IOException {
+ Files.deleteIfExists(getCrashRecoveryEventsTempFile().toPath());
+ }
+
+ private File getCrashRecoveryEventsTempFile() {
+ File systemTempDir = new File(mCacheDir, "system");
+ return new File(systemTempDir, "crashrecovery-events.txt");
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index c8cbbb5..2e6c93c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -102,6 +102,7 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityWindowAttributes;
import android.view.accessibility.IAccessibilityManager;
+import android.view.accessibility.IUserInitializationCompleteCallback;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
@@ -137,6 +138,7 @@
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import org.mockito.internal.util.reflection.FieldReader;
import org.mockito.internal.util.reflection.FieldSetter;
import org.mockito.stubbing.Answer;
@@ -209,6 +211,7 @@
@Mock private FullScreenMagnificationController mMockFullScreenMagnificationController;
@Mock private ProxyManager mProxyManager;
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+ @Spy private IUserInitializationCompleteCallback mUserInitializationCompleteCallback;
@Captor private ArgumentCaptor<Intent> mIntentArgumentCaptor;
private IAccessibilityManager mA11yManagerServiceOnDevice;
private AccessibilityServiceConnection mAccessibilityServiceConnection;
@@ -2042,6 +2045,36 @@
.isEqualTo(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
}
+ @Test
+ public void registerUserInitializationCompleteCallback_isRegistered() {
+ mA11yms.mUserInitializationCompleteCallbacks.clear();
+
+ mA11yms.registerUserInitializationCompleteCallback(mUserInitializationCompleteCallback);
+
+ assertThat(mA11yms.mUserInitializationCompleteCallbacks).containsExactly(
+ mUserInitializationCompleteCallback);
+ }
+
+ @Test
+ public void unregisterUserInitializationCompleteCallback_isUnregistered() {
+ mA11yms.mUserInitializationCompleteCallbacks.clear();
+ mA11yms.mUserInitializationCompleteCallbacks.add(mUserInitializationCompleteCallback);
+
+ mA11yms.unregisterUserInitializationCompleteCallback(mUserInitializationCompleteCallback);
+
+ assertThat(mA11yms.mUserInitializationCompleteCallbacks).isEmpty();
+ }
+
+ @Test
+ public void switchUser_callsUserInitializationCompleteCallback() throws RemoteException {
+ mA11yms.mUserInitializationCompleteCallbacks.add(mUserInitializationCompleteCallback);
+
+ mA11yms.switchUser(UserHandle.MIN_SECONDARY_USER_ID);
+
+ verify(mUserInitializationCompleteCallback).onUserInitializationComplete(
+ UserHandle.MIN_SECONDARY_USER_ID);
+ }
+
private Set<String> readStringsFromSetting(String setting) {
final Set<String> result = new ArraySet<>();
mA11yms.readColonDelimitedSettingToSet(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtilsTest.java b/services/tests/servicestests/src/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtilsTest.java
index 4ec2fb9..cdaeade 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/a11ychecker/AccessibilityCheckerUtilsTest.java
@@ -89,14 +89,15 @@
AccessibilityCheckResult.AccessibilityCheckResultType.NOT_RUN, null, 5,
null);
- Set<AndroidAccessibilityCheckerResult> results =
- AccessibilityCheckerUtils.processResults(
- mockNodeInfo,
- List.of(result1, result2, result3, result4),
- null,
+
+ AndroidAccessibilityCheckerResult.Builder resultBuilder =
+ AccessibilityCheckerUtils.getCommonResultBuilder(mockNodeInfo, null,
mMockPackageManager,
new ComponentName(TEST_A11Y_SERVICE_SOURCE_PACKAGE_NAME,
TEST_A11Y_SERVICE_CLASS_NAME));
+ Set<AndroidAccessibilityCheckerResult> results =
+ AccessibilityCheckerUtils.processResults(mockNodeInfo,
+ List.of(result1, result2, result3, result4), resultBuilder);
assertThat(results).containsExactly(
createResult("TargetNode", "",
@@ -128,14 +129,14 @@
TouchTargetSizeCheck.class,
AccessibilityCheckResult.AccessibilityCheckResultType.ERROR, null, 2, null);
- Set<AndroidAccessibilityCheckerResult> results =
- AccessibilityCheckerUtils.processResults(
- mockNodeInfo,
- List.of(result1, result2),
- null,
+ AndroidAccessibilityCheckerResult.Builder resultBuilder =
+ AccessibilityCheckerUtils.getCommonResultBuilder(mockNodeInfo, null,
mMockPackageManager,
new ComponentName(TEST_A11Y_SERVICE_SOURCE_PACKAGE_NAME,
TEST_A11Y_SERVICE_CLASS_NAME));
+ Set<AndroidAccessibilityCheckerResult> results =
+ AccessibilityCheckerUtils.processResults(mockNodeInfo,
+ List.of(result1, result2), resultBuilder);
assertThat(results).isEmpty();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index b4cc343..698bda3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -60,6 +60,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.List;
import java.util.Map;
/**
@@ -325,6 +326,11 @@
}
@Override
+ List<String> roleManagerGetRoleHoldersAsUser(String role, UserHandle userHandle) {
+ return services.roleManagerForMock.getRoleHoldersAsUser(role, userHandle);
+ }
+
+ @Override
PendingIntent pendingIntentGetActivityAsUser(Context context, int requestCode,
Intent intent, int flags, Bundle options, UserHandle user) {
return null;
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 b7483d6..cb4269a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -109,6 +109,7 @@
import android.app.admin.PreferentialNetworkServiceConfig;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.WifiSsidPolicy;
+import android.app.role.RoleManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
@@ -2889,6 +2890,52 @@
}
@Test
+ public void testSetMeteredDataDisabledPackagesExemptRoles() throws Exception {
+ // TODO(b/362545319): reference role name from role manager once it's exposed.
+ final String controllerRole = "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER";
+
+ setAsProfileOwner(admin1);
+
+ assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEmpty();
+
+ // Setup
+ final ArrayList<String> pkgsToRestrict = new ArrayList<>();
+ final ArrayList<String> pkgsExpectedAsNotRestricted = new ArrayList<>();
+ final String packageWithControllerRole = "com.example.controller";
+ final String packageWithKioskRole = "com.example.kiosk";
+ final String packageWithNotExemptRole = "com.example.notexempt";
+
+ pkgsToRestrict.add(packageWithControllerRole);
+ pkgsToRestrict.add(packageWithKioskRole);
+ pkgsToRestrict.add(packageWithNotExemptRole);
+
+ pkgsExpectedAsNotRestricted.add(packageWithControllerRole);
+ pkgsExpectedAsNotRestricted.add(packageWithKioskRole);
+
+ setupPackageInPackageManager(packageWithControllerRole, CALLER_USER_HANDLE, 123, 0);
+ setupPackageInPackageManager(packageWithKioskRole, CALLER_USER_HANDLE, 456, 0);
+ setupPackageInPackageManager(packageWithNotExemptRole, CALLER_USER_HANDLE, 789, 0);
+
+ when(getServices().roleManagerForMock.getRoleHoldersAsUser(controllerRole,
+ UserHandle.of(CALLER_USER_HANDLE)))
+ .thenReturn(new ArrayList<>(Arrays.asList(packageWithControllerRole)));
+ when(getServices().roleManagerForMock.getRoleHoldersAsUser(
+ RoleManager.ROLE_FINANCED_DEVICE_KIOSK,
+ UserHandle.of(CALLER_USER_HANDLE)))
+ .thenReturn(new ArrayList<>(Arrays.asList(packageWithKioskRole)));
+
+ List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict);
+
+ // Verify
+ assertThat(excludedPkgs).containsExactlyElementsIn(pkgsExpectedAsNotRestricted);
+ assertThat(dpm.getMeteredDataDisabledPackages(admin1))
+ .isEqualTo(Arrays.asList(packageWithNotExemptRole));
+ verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
+ MockUtils.checkApps(packageWithNotExemptRole),
+ eq(CALLER_USER_HANDLE));
+ }
+
+ @Test
public void testSetGetMeteredDataDisabledPackages_deviceAdmin() {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
dpm.setActiveAdmin(admin1, true);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 76aa40c..2e200a9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -142,6 +142,7 @@
public final DevicePolicyManager devicePolicyManager;
public final LocationManager locationManager;
public final RoleManager roleManager;
+ public final RoleManagerForMock roleManagerForMock;
public final SubscriptionManager subscriptionManager;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
@@ -200,6 +201,7 @@
devicePolicyManager = mock(DevicePolicyManager.class);
locationManager = mock(LocationManager.class);
roleManager = realContext.getSystemService(RoleManager.class);
+ roleManagerForMock = mock(RoleManagerForMock.class);
subscriptionManager = mock(SubscriptionManager.class);
// Package manager is huge, so we use a partial mock instead.
@@ -495,6 +497,12 @@
}
}
+ public static class RoleManagerForMock {
+ public List<String> getRoleHoldersAsUser(String role, UserHandle userHandle) {
+ return new ArrayList<>();
+ }
+ }
+
public static class SettingsForMock {
public int settingsSecureGetIntForUser(String name, int def, int userHandle) {
return 0;
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 963b27e..bf58443 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -38,6 +38,7 @@
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
@@ -69,6 +70,61 @@
private TunerResourceManagerService mTunerResourceManagerService;
private boolean mIsForeground;
+ private final class TunerClient extends IResourcesReclaimListener.Stub {
+ int[] mClientId;
+ ClientProfile mProfile;
+ boolean mReclaimed;
+
+ TunerClient() {
+ mClientId = new int[1];
+ mClientId[0] = TunerResourceManagerService.INVALID_CLIENT_ID;
+ }
+
+ public void register(String sessionId, int useCase) {
+ ResourceClientProfile profile = new ResourceClientProfile();
+ profile.tvInputSessionId = sessionId;
+ profile.useCase = useCase;
+ mTunerResourceManagerService.registerClientProfileInternal(
+ profile, this, mClientId);
+ assertThat(mClientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ mProfile = mTunerResourceManagerService.getClientProfile(mClientId[0]);
+ }
+
+ public void register(String sessionId, int useCase, int priority, int niceValue) {
+ register(sessionId, useCase);
+ mTunerResourceManagerService.updateClientPriorityInternal(
+ mClientId[0], priority, niceValue);
+ }
+
+ public void register(String sessionId, int useCase, int priority) {
+ register(sessionId, useCase, priority, 0);
+ }
+
+ public void unregister() {
+ mTunerResourceManagerService.unregisterClientProfileInternal(mClientId[0]);
+ mClientId[0] = TunerResourceManagerService.INVALID_CLIENT_ID;
+ mReclaimed = false;
+ }
+
+ public int getId() {
+ return mClientId[0];
+ }
+
+ public ClientProfile getProfile() {
+ return mProfile;
+ }
+
+ @Override
+ public void onReclaimResources() {
+ mTunerResourceManagerService.clearAllResourcesAndClientMapping(mProfile);
+ mReclaimed = true;
+ }
+
+ public boolean isReclaimed() {
+ return mReclaimed;
+ }
+ }
+
private static final class TestResourcesReclaimListener extends IResourcesReclaimListener.Stub {
boolean mReclaimed;
@@ -247,13 +303,11 @@
}
@Test
- public void requestFrontendTest_NoFrontendWithGiveTypeAvailable() {
- ResourceClientProfile profile = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- mTunerResourceManagerService.registerClientProfileInternal(
- profile, null /*listener*/, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ public void requestFrontendTest_NoFrontendWithGiveTypeAvailable() throws RemoteException {
+ // Register clients
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init frontend resources.
TunerFrontendInfo[] infos = new TunerFrontendInfo[1];
@@ -262,21 +316,20 @@
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
TunerFrontendRequest request =
- tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
assertThat(frontendHandle[0]).isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE);
+ client0.unregister();
}
@Test
- public void requestFrontendTest_FrontendWithNoExclusiveGroupAvailable() {
- ResourceClientProfile profile = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- mTunerResourceManagerService.registerClientProfileInternal(
- profile, null /*listener*/, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ public void requestFrontendTest_FrontendWithNoExclusiveGroupAvailable() throws RemoteException {
+ // Register clients
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init frontend resources.
TunerFrontendInfo[] infos = new TunerFrontendInfo[3];
@@ -295,27 +348,23 @@
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
TunerFrontendRequest request =
- tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(0);
+ client0.unregister();
}
@Test
- public void requestFrontendTest_FrontendWithExclusiveGroupAvailable() {
- ResourceClientProfile profile0 = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- ResourceClientProfile profile1 = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId0 = new int[1];
- int[] clientId1 = new int[1];
- mTunerResourceManagerService.registerClientProfileInternal(
- profile0, null /*listener*/, clientId0);
- mTunerResourceManagerService.registerClientProfileInternal(
- profile1, null /*listener*/, clientId1);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ public void requestFrontendTest_FrontendWithExclusiveGroupAvailable() throws RemoteException {
+ // Register clients
+ TunerClient client0 = new TunerClient();
+ TunerClient client1 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init frontend resources.
TunerFrontendInfo[] infos = new TunerFrontendInfo[3];
@@ -335,13 +384,13 @@
int[] frontendHandle = new int[1];
TunerFrontendRequest request =
- tunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
request =
- tunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[1].handle);
@@ -349,31 +398,20 @@
.isTrue();
assertThat(mTunerResourceManagerService.getFrontendResource(infos[2].handle).isInUse())
.isTrue();
+ client0.unregister();
+ client1.unregister();
}
@Test
- public void requestFrontendTest_NoFrontendAvailable_RequestWithLowerPriority() {
+ public void requestFrontendTest_NoFrontendAvailable_RequestWithLowerPriority()
+ throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[2];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- profiles[1] = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientPriorities = {100, 50};
- int[] clientId0 = new int[1];
- int[] clientId1 = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
-
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[0], listener, clientId0);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId0[0], clientPriorities[0], 0/*niceValue*/);
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[1], new TestResourcesReclaimListener(), clientId1);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId1[0], clientPriorities[1], 0/*niceValue*/);
+ TunerClient client0 = new TunerClient();
+ TunerClient client1 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100);
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 50);
// Init frontend resources.
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
@@ -384,46 +422,36 @@
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
TunerFrontendRequest request =
- tunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
request =
- tunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
- assertThat(listener.isReclaimed()).isFalse();
+ assertThat(client0.isReclaimed()).isFalse();
request =
- tunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
+ tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBS);
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isFalse();
- assertThat(listener.isReclaimed()).isFalse();
+ assertThat(client0.isReclaimed()).isFalse();
+ client0.unregister();
+ client1.unregister();
}
@Test
- public void requestFrontendTest_NoFrontendAvailable_RequestWithHigherPriority() {
+ public void requestFrontendTest_NoFrontendAvailable_RequestWithHigherPriority()
+ throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[2];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- profiles[1] = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientPriorities = {100, 500};
- int[] clientId0 = new int[1];
- int[] clientId1 = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[0], listener, clientId0);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId0[0], clientPriorities[0], 0/*niceValue*/);
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[1], new TestResourcesReclaimListener(), clientId1);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId1[0], clientPriorities[1], 0/*niceValue*/);
+ TunerClient client0 = new TunerClient();
+ TunerClient client1 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100);
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 500);
// Init frontend resources.
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
@@ -434,17 +462,16 @@
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
TunerFrontendRequest request =
- tunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
- .getInUseFrontendHandles()).isEqualTo(new HashSet<Integer>(Arrays.asList(
- infos[0].handle, infos[1].handle)));
+ assertThat(client0.getProfile().getInUseFrontendHandles())
+ .isEqualTo(new HashSet<Integer>(Arrays.asList(infos[0].handle, infos[1].handle)));
request =
- tunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
+ tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBS);
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[1].handle);
@@ -453,22 +480,20 @@
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
.isInUse()).isTrue();
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle)
- .getOwnerClientId()).isEqualTo(clientId1[0]);
+ .getOwnerClientId()).isEqualTo(client1.getId());
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
- .getOwnerClientId()).isEqualTo(clientId1[0]);
- assertThat(listener.isReclaimed()).isTrue();
+ .getOwnerClientId()).isEqualTo(client1.getId());
+ assertThat(client0.isReclaimed()).isTrue();
+ client0.unregister();
+ client1.unregister();
}
@Test
- public void releaseFrontendTest_UnderTheSameExclusiveGroup() {
+ public void releaseFrontendTest_UnderTheSameExclusiveGroup() throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[1];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(profiles[0], listener, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init frontend resources.
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
@@ -479,7 +504,7 @@
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
TunerFrontendRequest request =
- tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
@@ -488,43 +513,29 @@
.getFrontendResource(infos[1].handle).isInUse()).isTrue();
// Release frontend
- mTunerResourceManagerService.releaseFrontendInternal(mTunerResourceManagerService
- .getFrontendResource(frontendHandle[0]), clientId[0]);
+ mTunerResourceManagerService.releaseFrontendInternal(frontendHandle[0], client0.getId());
assertThat(mTunerResourceManagerService
.getFrontendResource(frontendHandle[0]).isInUse()).isFalse();
assertThat(mTunerResourceManagerService
.getFrontendResource(infos[1].handle).isInUse()).isFalse();
- assertThat(mTunerResourceManagerService
- .getClientProfile(clientId[0]).getInUseFrontendHandles().size()).isEqualTo(0);
+ assertThat(client0.getProfile().getInUseFrontendHandles().size()).isEqualTo(0);
+ client0.unregister();
}
@Test
- public void requestCasTest_NoCasAvailable_RequestWithHigherPriority() {
+ public void requestCasTest_NoCasAvailable_RequestWithHigherPriority() throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[2];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- profiles[1] = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientPriorities = {100, 500};
- int[] clientId0 = new int[1];
- int[] clientId1 = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[0], listener, clientId0);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId0[0], clientPriorities[0], 0/*niceValue*/);
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[1], new TestResourcesReclaimListener(), clientId1);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId1[0], clientPriorities[1], 0/*niceValue*/);
+ TunerClient client0 = new TunerClient();
+ TunerClient client1 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100);
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 500);
// Init cas resources.
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
- CasSessionRequest request = casSessionRequest(clientId0[0], 1 /*casSystemId*/);
+ CasSessionRequest request = casSessionRequest(client0.getId(), 1 /*casSystemId*/);
int[] casSessionHandle = new int[1];
// Request for 2 cas sessions.
assertThat(mTunerResourceManagerService
@@ -533,54 +544,45 @@
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0]))
.isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
- .getInUseCasSystemId()).isEqualTo(1);
+ assertThat(client0.getProfile().getInUseCasSystemId())
+ .isEqualTo(1);
assertThat(mTunerResourceManagerService.getCasResource(1)
- .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId0[0])));
+ .getOwnerClientIds()).isEqualTo(
+ new HashSet<Integer>(Arrays.asList(client0.getId())));
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isTrue();
- request = casSessionRequest(clientId1[0], 1);
+ request = casSessionRequest(client1.getId(), 1);
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0]))
.isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId1[0])
- .getInUseCasSystemId()).isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
- .getInUseCasSystemId()).isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
+ assertThat(client1.getProfile().getInUseCasSystemId()).isEqualTo(1);
+ assertThat(client0.getProfile().getInUseCasSystemId())
+ .isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
assertThat(mTunerResourceManagerService.getCasResource(1)
- .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId1[0])));
+ .getOwnerClientIds()).isEqualTo(
+ new HashSet<Integer>(Arrays.asList(client1.getId())));
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse();
- assertThat(listener.isReclaimed()).isTrue();
+ assertThat(client0.isReclaimed()).isTrue();
+ client0.unregister();
+ client1.unregister();
}
@Test
- public void requestCiCamTest_NoCiCamAvailable_RequestWithHigherPriority() {
+ public void requestCiCamTest_NoCiCamAvailable_RequestWithHigherPriority()
+ throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[2];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- profiles[1] = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientPriorities = {100, 500};
- int[] clientId0 = new int[1];
- int[] clientId1 = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[0], listener, clientId0);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId0[0], clientPriorities[0], 0/*niceValue*/);
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[1], new TestResourcesReclaimListener(), clientId1);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId1[0], clientPriorities[1], 0/*niceValue*/);
+ TunerClient client0 = new TunerClient();
+ TunerClient client1 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100);
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 500);
// Init cicam/cas resources.
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
- TunerCiCamRequest request = tunerCiCamRequest(clientId0[0], 1 /*ciCamId*/);
+ TunerCiCamRequest request = tunerCiCamRequest(client0.getId(), 1 /*ciCamId*/);
int[] ciCamHandle = new int[1];
// Request for 2 ciCam sessions.
assertThat(mTunerResourceManagerService
@@ -589,139 +591,125 @@
.requestCiCamInternal(request, ciCamHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(ciCamHandle[0]))
.isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
- .getInUseCiCamId()).isEqualTo(1);
+ assertThat(client0.getProfile().getInUseCiCamId()).isEqualTo(1);
assertThat(mTunerResourceManagerService.getCiCamResource(1)
- .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId0[0])));
+ .getOwnerClientIds()).isEqualTo(
+ new HashSet<Integer>(Arrays.asList(client0.getId())));
assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isTrue();
- request = tunerCiCamRequest(clientId1[0], 1);
+ request = tunerCiCamRequest(client1.getId(), 1);
assertThat(mTunerResourceManagerService
.requestCiCamInternal(request, ciCamHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(ciCamHandle[0]))
.isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId1[0])
- .getInUseCiCamId()).isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
- .getInUseCiCamId()).isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
+ assertThat(client1.getProfile().getInUseCiCamId()).isEqualTo(1);
+ assertThat(client0.getProfile().getInUseCiCamId())
+ .isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
assertThat(mTunerResourceManagerService.getCiCamResource(1)
- .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId1[0])));
- assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isFalse();
- assertThat(listener.isReclaimed()).isTrue();
+ .getOwnerClientIds()).isEqualTo(
+ new HashSet<Integer>(Arrays.asList(client1.getId())));
+ assertThat(mTunerResourceManagerService
+ .getCiCamResource(1).isFullyUsed()).isFalse();
+ assertThat(client0.isReclaimed()).isTrue();
+ client0.unregister();
+ client1.unregister();
}
@Test
- public void releaseCasTest() {
+ public void releaseCasTest() throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[1];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(profiles[0], listener, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init cas resources.
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
- CasSessionRequest request = casSessionRequest(clientId[0], 1 /*casSystemId*/);
+ CasSessionRequest request = casSessionRequest(client0.getId(), 1 /*casSystemId*/);
int[] casSessionHandle = new int[1];
// Request for 1 cas sessions.
assertThat(mTunerResourceManagerService
.requestCasSessionInternal(request, casSessionHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0]))
.isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId[0])
- .getInUseCasSystemId()).isEqualTo(1);
+ assertThat(client0.getProfile().getInUseCasSystemId()).isEqualTo(1);
assertThat(mTunerResourceManagerService.getCasResource(1)
- .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId[0])));
+ .getOwnerClientIds()).isEqualTo(
+ new HashSet<Integer>(Arrays.asList(client0.getId())));
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse();
// Release cas
mTunerResourceManagerService.releaseCasSessionInternal(mTunerResourceManagerService
- .getCasResource(1), clientId[0]);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId[0])
- .getInUseCasSystemId()).isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
+ .getCasResource(1), client0.getId());
+ assertThat(client0.getProfile().getInUseCasSystemId())
+ .isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse();
assertThat(mTunerResourceManagerService.getCasResource(1)
.getOwnerClientIds()).isEmpty();
+ client0.unregister();
}
@Test
- public void releaseCiCamTest() {
+ public void releaseCiCamTest() throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[1];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(profiles[0], listener, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init cas resources.
mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/);
- TunerCiCamRequest request = tunerCiCamRequest(clientId[0], 1 /*ciCamId*/);
+ TunerCiCamRequest request = tunerCiCamRequest(client0.getId(), 1 /*ciCamId*/);
int[] ciCamHandle = new int[1];
// Request for 1 ciCam sessions.
assertThat(mTunerResourceManagerService
.requestCiCamInternal(request, ciCamHandle)).isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(ciCamHandle[0]))
.isEqualTo(1);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId[0])
- .getInUseCiCamId()).isEqualTo(1);
+ assertThat(client0.getProfile().getInUseCiCamId()).isEqualTo(1);
assertThat(mTunerResourceManagerService.getCiCamResource(1)
- .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId[0])));
- assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isFalse();
+ .getOwnerClientIds()).isEqualTo(
+ new HashSet<Integer>(Arrays.asList(client0.getId())));
+ assertThat(mTunerResourceManagerService
+ .getCiCamResource(1).isFullyUsed()).isFalse();
// Release ciCam
mTunerResourceManagerService.releaseCiCamInternal(mTunerResourceManagerService
- .getCiCamResource(1), clientId[0]);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId[0])
- .getInUseCiCamId()).isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
- assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isFalse();
+ .getCiCamResource(1), client0.getId());
+ assertThat(client0.getProfile().getInUseCiCamId())
+ .isEqualTo(ClientProfile.INVALID_RESOURCE_ID);
+ assertThat(mTunerResourceManagerService
+ .getCiCamResource(1).isFullyUsed()).isFalse();
assertThat(mTunerResourceManagerService.getCiCamResource(1)
.getOwnerClientIds()).isEmpty();
+ client0.unregister();
}
@Test
- public void requestLnbTest_NoLnbAvailable_RequestWithHigherPriority() {
+ public void requestLnbTest_NoLnbAvailable_RequestWithHigherPriority() throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[2];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- profiles[1] = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientPriorities = {100, 500};
- int[] clientId0 = new int[1];
- int[] clientId1 = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[0], listener, clientId0);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId0[0], clientPriorities[0], 0/*niceValue*/);
- mTunerResourceManagerService.registerClientProfileInternal(
- profiles[1], new TestResourcesReclaimListener(), clientId1);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.updateClientPriorityInternal(
- clientId1[0], clientPriorities[1], 0/*niceValue*/);
+ TunerClient client0 = new TunerClient();
+ TunerClient client1 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100);
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 500);
// Init lnb resources.
int[] lnbHandles = {1};
mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
TunerLnbRequest request = new TunerLnbRequest();
- request.clientId = clientId0[0];
+ request.clientId = client0.getId();
int[] lnbHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]);
- assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0]).getInUseLnbHandles())
+ assertThat(client0.getProfile().getInUseLnbHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(lnbHandles[0])));
request = new TunerLnbRequest();
- request.clientId = clientId1[0];
+ request.clientId = client1.getId();
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
@@ -729,29 +717,26 @@
assertThat(mTunerResourceManagerService.getLnbResource(lnbHandles[0])
.isInUse()).isTrue();
assertThat(mTunerResourceManagerService.getLnbResource(lnbHandles[0])
- .getOwnerClientId()).isEqualTo(clientId1[0]);
- assertThat(listener.isReclaimed()).isTrue();
- assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0])
- .getInUseLnbHandles().size()).isEqualTo(0);
+ .getOwnerClientId()).isEqualTo(client1.getId());
+ assertThat(client0.isReclaimed()).isTrue();
+ assertThat(client0.getProfile().getInUseLnbHandles().size()).isEqualTo(0);
+ client0.unregister();
+ client1.unregister();
}
@Test
- public void releaseLnbTest() {
+ public void releaseLnbTest() throws RemoteException {
// Register clients
- ResourceClientProfile[] profiles = new ResourceClientProfile[1];
- profiles[0] = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
- mTunerResourceManagerService.registerClientProfileInternal(profiles[0], listener, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init lnb resources.
int[] lnbHandles = {0};
mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles);
TunerLnbRequest request = new TunerLnbRequest();
- request.clientId = clientId[0];
+ request.clientId = client0.getId();
int[] lnbHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestLnbInternal(request, lnbHandle)).isTrue();
@@ -762,19 +747,16 @@
.getLnbResource(lnbHandle[0]));
assertThat(mTunerResourceManagerService
.getLnbResource(lnbHandle[0]).isInUse()).isFalse();
- assertThat(mTunerResourceManagerService
- .getClientProfile(clientId[0]).getInUseLnbHandles().size()).isEqualTo(0);
+ assertThat(client0.getProfile().getInUseLnbHandles().size()).isEqualTo(0);
+ client0.unregister();
}
@Test
- public void unregisterClientTest_usingFrontend() {
- // Register client
- ResourceClientProfile profile = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- mTunerResourceManagerService.registerClientProfileInternal(
- profile, null /*listener*/, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ public void unregisterClientTest_usingFrontend() throws RemoteException {
+ // Register clients
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
// Init frontend resources.
TunerFrontendInfo[] infos = new TunerFrontendInfo[2];
@@ -785,7 +767,7 @@
mTunerResourceManagerService.setFrontendInfoListInternal(infos);
TunerFrontendRequest request =
- tunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT);
+ tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT);
int[] frontendHandle = new int[1];
assertThat(mTunerResourceManagerService
.requestFrontendInternal(request, frontendHandle)).isTrue();
@@ -796,26 +778,20 @@
.isInUse()).isTrue();
// Unregister client when using frontend
- mTunerResourceManagerService.unregisterClientProfileInternal(clientId[0]);
+ client0.unregister();
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle)
.isInUse()).isFalse();
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
.isInUse()).isFalse();
- assertThat(mTunerResourceManagerService.checkClientExists(clientId[0])).isFalse();
-
+ assertThat(mTunerResourceManagerService.checkClientExists(client0.getId())).isFalse();
}
@Test
- public void requestDemuxTest() {
- // Register client
- ResourceClientProfile profile0 = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- ResourceClientProfile profile1 = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId0 = new int[1];
- mTunerResourceManagerService.registerClientProfileInternal(
- profile0, null /*listener*/, clientId0);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ public void requestDemuxTest() throws RemoteException {
+ // Register clients
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
TunerDemuxInfo[] infos = new TunerDemuxInfo[3];
infos[0] = tunerDemuxInfo(0 /* handle */, Filter.TYPE_TS | Filter.TYPE_IP);
@@ -825,7 +801,7 @@
int[] demuxHandle0 = new int[1];
// first with undefined type (should be the first one with least # of caps)
- TunerDemuxRequest request = tunerDemuxRequest(clientId0[0], Filter.TYPE_UNDEFINED);
+ TunerDemuxRequest request = tunerDemuxRequest(client0.getId(), Filter.TYPE_UNDEFINED);
assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle0))
.isTrue();
assertThat(demuxHandle0[0]).isEqualTo(1);
@@ -846,16 +822,16 @@
assertThat(demuxHandle0[0]).isEqualTo(2);
// request for another TS
- int[] clientId1 = new int[1];
- mTunerResourceManagerService.registerClientProfileInternal(
- profile1, null /*listener*/, clientId1);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ TunerClient client1 = new TunerClient();
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+
int[] demuxHandle1 = new int[1];
- TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_TS);
+ TunerDemuxRequest request1 = tunerDemuxRequest(client1.getId(), Filter.TYPE_TS);
assertThat(mTunerResourceManagerService.requestDemuxInternal(request1, demuxHandle1))
.isTrue();
assertThat(demuxHandle1[0]).isEqualTo(0);
- assertThat(mTunerResourceManagerService.getResourceIdFromHandle(demuxHandle1[0]))
+ assertThat(mTunerResourceManagerService.getResourceIdFromHandle(client1.getId()))
.isEqualTo(0);
// release demuxes
@@ -863,33 +839,23 @@
mTunerResourceManagerService.releaseDemuxInternal(dr);
dr = mTunerResourceManagerService.getDemuxResource(demuxHandle1[0]);
mTunerResourceManagerService.releaseDemuxInternal(dr);
+
+ client0.unregister();
+ client1.unregister();
}
@Test
- public void requestDemuxTest_ResourceReclaim() {
+ public void requestDemuxTest_ResourceReclaim() throws RemoteException {
// Register clients
- ResourceClientProfile profile0 = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- ResourceClientProfile profile1 = resourceClientProfile("1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
- ResourceClientProfile profile2 = resourceClientProfile("2" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
- int[] clientId0 = new int[1];
- int[] clientId1 = new int[1];
- int[] clientId2 = new int[1];
- TestResourcesReclaimListener listener0 = new TestResourcesReclaimListener();
- TestResourcesReclaimListener listener1 = new TestResourcesReclaimListener();
- TestResourcesReclaimListener listener2 = new TestResourcesReclaimListener();
-
- mTunerResourceManagerService.registerClientProfileInternal(
- profile0, listener0, clientId0);
- assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.registerClientProfileInternal(
- profile1, listener1, clientId1);
- assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- mTunerResourceManagerService.registerClientProfileInternal(
- profile2, listener2, clientId1);
- assertThat(clientId2[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ TunerClient client0 = new TunerClient();
+ TunerClient client1 = new TunerClient();
+ TunerClient client2 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
+ client1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
+ client2.register("2" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN);
// Init demux resources.
TunerDemuxInfo[] infos = new TunerDemuxInfo[2];
@@ -897,66 +863,67 @@
infos[1] = tunerDemuxInfo(1 /*handle*/, Filter.TYPE_TS);
mTunerResourceManagerService.setDemuxInfoListInternal(infos);
- // let clientId0(prio:100) request for IP - should succeed
- TunerDemuxRequest request0 = tunerDemuxRequest(clientId0[0], Filter.TYPE_IP);
+ // let client0(prio:100) request for IP - should succeed
+ TunerDemuxRequest request0 = tunerDemuxRequest(client0.getId(), Filter.TYPE_IP);
int[] demuxHandle0 = new int[1];
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request0, demuxHandle0)).isTrue();
assertThat(demuxHandle0[0]).isEqualTo(0);
- // let clientId1(prio:50) request for IP - should fail
- TunerDemuxRequest request1 = tunerDemuxRequest(clientId1[0], Filter.TYPE_IP);
+ // let client1(prio:50) request for IP - should fail
+ TunerDemuxRequest request1 = tunerDemuxRequest(client1.getId(), Filter.TYPE_IP);
int[] demuxHandle1 = new int[1];
demuxHandle1[0] = -1;
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request1, demuxHandle1)).isFalse();
- assertThat(listener0.isReclaimed()).isFalse();
+ assertThat(client0.isReclaimed()).isFalse();
assertThat(demuxHandle1[0]).isEqualTo(-1);
- // let clientId1(prio:50) request for TS - should succeed
+ // let client1(prio:50) request for TS - should succeed
request1.desiredFilterTypes = Filter.TYPE_TS;
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request1, demuxHandle1)).isTrue();
assertThat(demuxHandle1[0]).isEqualTo(1);
- assertThat(listener0.isReclaimed()).isFalse();
+ assertThat(client0.isReclaimed()).isFalse();
- // now release demux for the clientId0 (higher priority) and request demux
+ // now release demux for the client0 (higher priority) and request demux
DemuxResource dr = mTunerResourceManagerService.getDemuxResource(demuxHandle0[0]);
mTunerResourceManagerService.releaseDemuxInternal(dr);
- // let clientId2(prio:50) request for TS - should succeed
- TunerDemuxRequest request2 = tunerDemuxRequest(clientId2[0], Filter.TYPE_TS);
+ // let client2(prio:50) request for TS - should succeed
+ TunerDemuxRequest request2 = tunerDemuxRequest(client2.getId(), Filter.TYPE_TS);
int[] demuxHandle2 = new int[1];
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request2, demuxHandle2)).isTrue();
assertThat(demuxHandle2[0]).isEqualTo(0);
- assertThat(listener1.isReclaimed()).isFalse();
+ assertThat(client1.isReclaimed()).isFalse();
- // let clientId0(prio:100) request for TS - should reclaim from clientId2
+ // let client0(prio:100) request for TS - should reclaim from client1
// , who has the smaller caps
request0.desiredFilterTypes = Filter.TYPE_TS;
assertThat(mTunerResourceManagerService
.requestDemuxInternal(request0, demuxHandle0)).isTrue();
- assertThat(listener1.isReclaimed()).isFalse();
- assertThat(listener2.isReclaimed()).isTrue();
+ assertThat(client1.isReclaimed()).isTrue();
+ assertThat(client2.isReclaimed()).isFalse();
+ client0.unregister();
+ client1.unregister();
+ client2.unregister();
}
@Test
public void requestDescramblerTest() {
- // Register client
- ResourceClientProfile profile = resourceClientProfile("0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
- int[] clientId = new int[1];
- mTunerResourceManagerService.registerClientProfileInternal(
- profile, null /*listener*/, clientId);
- assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ // Register clients
+ TunerClient client0 = new TunerClient();
+ client0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK);
int[] desHandle = new int[1];
TunerDescramblerRequest request = new TunerDescramblerRequest();
- request.clientId = clientId[0];
+ request.clientId = client0.getId();
assertThat(mTunerResourceManagerService.requestDescramblerInternal(request, desHandle))
.isTrue();
assertThat(mTunerResourceManagerService.getResourceIdFromHandle(desHandle[0])).isEqualTo(0);
+ client0.unregister();
}
@Test
@@ -978,74 +945,26 @@
}
@Test
- public void shareFrontendTest_FrontendWithExclusiveGroupReadyToShare() {
+ public void shareFrontendTest_FrontendWithExclusiveGroupReadyToShare() throws RemoteException {
/**** Register Clients and Set Priority ****/
-
- // Int array to save the returned client ids
- int[] ownerClientId0 = new int[1];
- int[] ownerClientId1 = new int[1];
- int[] shareClientId0 = new int[1];
- int[] shareClientId1 = new int[1];
-
- // Predefined client profiles
- ResourceClientProfile[] ownerProfiles = new ResourceClientProfile[2];
- ResourceClientProfile[] shareProfiles = new ResourceClientProfile[2];
- ownerProfiles[0] = resourceClientProfile(
- "0" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE);
- ownerProfiles[1] = resourceClientProfile(
- "1" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE);
- shareProfiles[0] = resourceClientProfile(
- "2" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD);
- shareProfiles[1] = resourceClientProfile(
- "3" /*sessionId*/,
- TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD);
-
- // Predefined client reclaim listeners
- TestResourcesReclaimListener ownerListener0 = new TestResourcesReclaimListener();
- TestResourcesReclaimListener shareListener0 = new TestResourcesReclaimListener();
- TestResourcesReclaimListener ownerListener1 = new TestResourcesReclaimListener();
- TestResourcesReclaimListener shareListener1 = new TestResourcesReclaimListener();
- // Register clients and validate the returned client ids
- mTunerResourceManagerService
- .registerClientProfileInternal(ownerProfiles[0], ownerListener0, ownerClientId0);
- mTunerResourceManagerService
- .registerClientProfileInternal(shareProfiles[0], shareListener0, shareClientId0);
- mTunerResourceManagerService
- .registerClientProfileInternal(ownerProfiles[1], ownerListener1, ownerClientId1);
- mTunerResourceManagerService
- .registerClientProfileInternal(shareProfiles[1], shareListener1, shareClientId1);
- assertThat(ownerClientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- assertThat(shareClientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- assertThat(ownerClientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
- assertThat(shareClientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
+ TunerClient ownerClient0 = new TunerClient();
+ TunerClient ownerClient1 = new TunerClient();
+ TunerClient shareClient0 = new TunerClient();
+ TunerClient shareClient1 = new TunerClient();
+ ownerClient0.register("0" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE, 100);
+ ownerClient1.register("1" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE, 300);
+ shareClient0.register("2" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD, 200);
+ shareClient1.register("3" /*sessionId*/,
+ TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD, 400);
mTunerResourceManagerService.updateClientPriorityInternal(
- ownerClientId0[0],
- 100/*priority*/,
- 0/*niceValue*/);
- mTunerResourceManagerService.updateClientPriorityInternal(
- shareClientId0[0],
- 200/*priority*/,
- 0/*niceValue*/);
- mTunerResourceManagerService.updateClientPriorityInternal(
- ownerClientId1[0],
- 300/*priority*/,
- 0/*niceValue*/);
- mTunerResourceManagerService.updateClientPriorityInternal(
- shareClientId1[0],
- 400/*priority*/,
- 0/*niceValue*/);
- mTunerResourceManagerService.updateClientPriorityInternal(
- shareClientId1[0],
+ shareClient1.getId(),
-1/*invalid priority*/,
0/*niceValue*/);
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId1[0])
- .getPriority())
- .isEqualTo(400);
+ assertThat(shareClient1.getProfile().getPriority()).isEqualTo(400);
/**** Init Frontend Resources ****/
@@ -1072,7 +991,7 @@
// Predefined frontend request and array to save returned frontend handle
int[] frontendHandle = new int[1];
TunerFrontendRequest request = tunerFrontendRequest(
- ownerClientId0[0] /*clientId*/,
+ ownerClient0.getId() /*clientId*/,
FrontendSettings.TYPE_DVBT);
// Request call and validate granted resource and internal mapping
@@ -1080,9 +999,7 @@
.requestFrontendInternal(request, frontendHandle))
.isTrue();
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId0[0])
- .getInUseFrontendHandles())
+ assertThat(ownerClient0.getProfile().getInUseFrontendHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
infos[0].handle,
infos[1].handle)));
@@ -1091,11 +1008,11 @@
// Share frontend call and validate the internal mapping
mTunerResourceManagerService.shareFrontendInternal(
- shareClientId0[0]/*selfClientId*/,
- ownerClientId0[0]/*targetClientId*/);
+ shareClient0.getId()/*selfClientId*/,
+ ownerClient0.getId()/*targetClientId*/);
mTunerResourceManagerService.shareFrontendInternal(
- shareClientId1[0]/*selfClientId*/,
- ownerClientId0[0]/*targetClientId*/);
+ shareClient1.getId()/*selfClientId*/,
+ ownerClient0.getId()/*targetClientId*/);
// Verify fe in use status
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle)
.isInUse()).isTrue();
@@ -1103,31 +1020,24 @@
.isInUse()).isTrue();
// Verify fe owner status
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle)
- .getOwnerClientId()).isEqualTo(ownerClientId0[0]);
+ .getOwnerClientId()).isEqualTo(ownerClient0.getId());
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
- .getOwnerClientId()).isEqualTo(ownerClientId0[0]);
+ .getOwnerClientId()).isEqualTo(ownerClient0.getId());
// Verify share fe client status in the primary owner client
- assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0])
- .getShareFeClientIds())
+ assertThat(ownerClient0.getProfile().getShareFeClientIds())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
- shareClientId0[0],
- shareClientId1[0])));
+ shareClient0.getId(),
+ shareClient1.getId())));
// Verify in use frontend list in all the primary owner and share owner clients
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId0[0])
- .getInUseFrontendHandles())
+ assertThat(ownerClient0.getProfile().getInUseFrontendHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
infos[0].handle,
infos[1].handle)));
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId0[0])
- .getInUseFrontendHandles())
+ assertThat(shareClient0.getProfile().getInUseFrontendHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
infos[0].handle,
infos[1].handle)));
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId1[0])
- .getInUseFrontendHandles())
+ assertThat(shareClient1.getProfile().getInUseFrontendHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
infos[0].handle,
infos[1].handle)));
@@ -1135,21 +1045,17 @@
/**** Remove Frontend Share Owner ****/
// Unregister the second share fe client
- mTunerResourceManagerService.unregisterClientProfileInternal(shareClientId1[0]);
+ shareClient1.unregister();
// Validate the internal mapping
- assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0])
- .getShareFeClientIds())
+ assertThat(ownerClient0.getProfile().getShareFeClientIds())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
- shareClientId0[0])));
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId0[0])
- .getInUseFrontendHandles())
+ shareClient0.getId())));
+ assertThat(ownerClient0.getProfile().getInUseFrontendHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
infos[0].handle,
infos[1].handle)));
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId0[0])
+ assertThat(shareClient0.getProfile()
.getInUseFrontendHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
infos[0].handle,
@@ -1159,7 +1065,7 @@
// Predefined second frontend request
request = tunerFrontendRequest(
- ownerClientId1[0] /*clientId*/,
+ ownerClient1.getId() /*clientId*/,
FrontendSettings.TYPE_DVBT);
// Second request call
@@ -1170,43 +1076,35 @@
// Validate granted resource and internal mapping
assertThat(frontendHandle[0]).isEqualTo(infos[0].handle);
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle)
- .getOwnerClientId()).isEqualTo(ownerClientId1[0]);
+ .getOwnerClientId()).isEqualTo(ownerClient1.getId());
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
- .getOwnerClientId()).isEqualTo(ownerClientId1[0]);
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId1[0])
- .getInUseFrontendHandles())
+ .getOwnerClientId()).isEqualTo(ownerClient1.getId());
+ assertThat(ownerClient1.getProfile().getInUseFrontendHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
infos[0].handle,
infos[1].handle)));
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId0[0])
- .getInUseFrontendHandles()
+ assertThat(ownerClient0.getProfile().getInUseFrontendHandles()
.isEmpty())
.isTrue();
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId0[0])
- .getInUseFrontendHandles()
+ assertThat(shareClient0.getProfile().getInUseFrontendHandles()
.isEmpty())
.isTrue();
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId0[0])
- .getShareFeClientIds()
+ assertThat(ownerClient0.getProfile().getShareFeClientIds()
.isEmpty())
.isTrue();
- assertThat(ownerListener0.isReclaimed()).isTrue();
- assertThat(shareListener0.isReclaimed()).isTrue();
+ assertThat(ownerClient0.isReclaimed()).isTrue();
+ assertThat(shareClient0.isReclaimed()).isTrue();
/**** Release Frontend Resource From Primary Owner ****/
// Reshare the frontend
mTunerResourceManagerService.shareFrontendInternal(
- shareClientId0[0]/*selfClientId*/,
- ownerClientId1[0]/*targetClientId*/);
+ shareClient0.getId()/*selfClientId*/,
+ ownerClient1.getId()/*targetClientId*/);
// Release the frontend resource from the primary owner
- mTunerResourceManagerService.releaseFrontendInternal(mTunerResourceManagerService
- .getFrontendResource(infos[0].handle), ownerClientId1[0]);
+ mTunerResourceManagerService.releaseFrontendInternal(infos[0].handle,
+ ownerClient1.getId());
// Validate the internal mapping
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle)
@@ -1214,19 +1112,13 @@
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
.isInUse()).isFalse();
// Verify client status
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId1[0])
- .getInUseFrontendHandles()
+ assertThat(ownerClient1.getProfile().getInUseFrontendHandles()
.isEmpty())
.isTrue();
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId0[0])
- .getInUseFrontendHandles()
+ assertThat(shareClient0.getProfile().getInUseFrontendHandles()
.isEmpty())
.isTrue();
- assertThat(mTunerResourceManagerService
- .getClientProfile(ownerClientId1[0])
- .getShareFeClientIds()
+ assertThat(ownerClient1.getProfile().getShareFeClientIds()
.isEmpty())
.isTrue();
@@ -1234,7 +1126,7 @@
// Predefined Lnb request and handle array
TunerLnbRequest requestLnb = new TunerLnbRequest();
- requestLnb.clientId = shareClientId0[0];
+ requestLnb.clientId = shareClient0.getId();
int[] lnbHandle = new int[1];
// Request for an Lnb
@@ -1247,11 +1139,11 @@
.requestFrontendInternal(request, frontendHandle))
.isTrue();
mTunerResourceManagerService.shareFrontendInternal(
- shareClientId0[0]/*selfClientId*/,
- ownerClientId1[0]/*targetClientId*/);
+ shareClient0.getId()/*selfClientId*/,
+ ownerClient1.getId()/*targetClientId*/);
// Unregister the primary owner of the shared frontend
- mTunerResourceManagerService.unregisterClientProfileInternal(ownerClientId1[0]);
+ ownerClient1.unregister();
// Validate the internal mapping
assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle)
@@ -1259,16 +1151,15 @@
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].handle)
.isInUse()).isFalse();
// Verify client status
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId0[0])
- .getInUseFrontendHandles()
+ assertThat(shareClient0.getProfile().getInUseFrontendHandles()
.isEmpty())
.isTrue();
- assertThat(mTunerResourceManagerService
- .getClientProfile(shareClientId0[0])
- .getInUseLnbHandles())
+ assertThat(shareClient0.getProfile().getInUseLnbHandles())
.isEqualTo(new HashSet<Integer>(Arrays.asList(
lnbHandles[0])));
+
+ ownerClient0.unregister();
+ shareClient0.unregister();
}
private TunerFrontendInfo tunerFrontendInfo(
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/vibrator/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index f3ecfcc..66788b6 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -45,6 +45,8 @@
import androidx.test.InstrumentationRegistry;
+import com.android.server.vibrator.VibrationSession.CallerInfo;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -262,7 +264,7 @@
public void vibrateIfAvailable_withNoInputDevice_returnsFalse() {
assertFalse(mInputDeviceDelegate.isAvailable());
assertFalse(mInputDeviceDelegate.vibrateIfAvailable(
- new Vibration.CallerInfo(VIBRATION_ATTRIBUTES, UID, -1, PACKAGE_NAME, REASON),
+ new CallerInfo(VIBRATION_ATTRIBUTES, UID, -1, PACKAGE_NAME, REASON),
SYNCED_EFFECT));
}
@@ -277,7 +279,7 @@
mInputDeviceDelegate.updateInputDeviceVibrators(/* vibrateInputDevices= */ true);
assertTrue(mInputDeviceDelegate.vibrateIfAvailable(
- new Vibration.CallerInfo(VIBRATION_ATTRIBUTES, UID, -1, PACKAGE_NAME, REASON),
+ new CallerInfo(VIBRATION_ATTRIBUTES, UID, -1, PACKAGE_NAME, REASON),
SYNCED_EFFECT));
verify(mIInputManagerMock).vibrateCombined(eq(1), same(SYNCED_EFFECT), any());
verify(mIInputManagerMock).vibrateCombined(eq(2), same(SYNCED_EFFECT), any());
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSessionTest.java
similarity index 80%
rename from services/tests/vibrator/src/com/android/server/vibrator/VibrationTest.java
rename to services/tests/vibrator/src/com/android/server/vibrator/VibrationSessionTest.java
index 84f8412..f69d1c4 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSessionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -24,13 +24,13 @@
import java.util.Arrays;
-public class VibrationTest {
+public class VibrationSessionTest {
@Test
public void status_hasUniqueProtoEnumValues() {
assertThat(
- Arrays.stream(Vibration.Status.values())
- .map(Vibration.Status::getProtoEnumValue)
+ Arrays.stream(VibrationSession.Status.values())
+ .map(VibrationSession.Status::getProtoEnumValue)
.collect(toList()))
.containsNoDuplicates();
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index 38cd49d..c7a136a 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -81,6 +81,8 @@
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
+import com.android.server.vibrator.VibrationSession.CallerInfo;
+import com.android.server.vibrator.VibrationSession.Status;
import org.junit.After;
import org.junit.Before;
@@ -292,7 +294,7 @@
if (expectedAllowedVibrations.contains(usage)) {
assertVibrationNotIgnoredForUsage(usage);
} else {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_BACKGROUND);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_BACKGROUND);
}
}
}
@@ -350,7 +352,7 @@
createSystemReadyVibrationSettings();
for (int usage : ALL_USAGES) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_ON_WIRELESS_CHARGER);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_ON_WIRELESS_CHARGER);
}
}
@@ -365,7 +367,7 @@
mRegisteredBatteryBroadcastReceiver.onReceive(mContextSpy, wirelessChargingIntent);
for (int usage : ALL_USAGES) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_ON_WIRELESS_CHARGER);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_ON_WIRELESS_CHARGER);
}
}
@@ -377,7 +379,7 @@
createSystemReadyVibrationSettings();
// Check that initially, all usages are ignored due to the wireless charging.
for (int usage : ALL_USAGES) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_ON_WIRELESS_CHARGER);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_ON_WIRELESS_CHARGER);
}
Intent nonWirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_USB);
@@ -404,7 +406,7 @@
if (expectedAllowedVibrations.contains(usage)) {
assertVibrationNotIgnoredForUsage(usage);
} else {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_POWER);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_POWER);
}
}
}
@@ -426,7 +428,7 @@
for (int usage : ALL_USAGES) {
if (usage == USAGE_RINGTONE || usage == USAGE_NOTIFICATION) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_RINGER_MODE);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_RINGER_MODE);
} else {
assertVibrationNotIgnoredForUsage(usage);
}
@@ -470,7 +472,7 @@
if (usage == USAGE_ACCESSIBILITY) {
assertVibrationNotIgnoredForUsage(usage);
} else {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_SETTINGS);
}
assertVibrationNotIgnoredForUsageAndFlags(usage,
VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF);
@@ -512,7 +514,7 @@
for (int usage : ALL_USAGES) {
if (usage == USAGE_TOUCH) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_SETTINGS);
} else {
assertVibrationNotIgnoredForUsage(usage);
}
@@ -527,7 +529,7 @@
for (int usage : ALL_USAGES) {
if (usage == USAGE_TOUCH || usage == USAGE_IME_FEEDBACK) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_SETTINGS);
} else {
assertVibrationNotIgnoredForUsage(usage);
}
@@ -542,7 +544,7 @@
for (int usage : ALL_USAGES) {
if (usage == USAGE_HARDWARE_FEEDBACK || usage == USAGE_PHYSICAL_EMULATION) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_SETTINGS);
} else {
assertVibrationNotIgnoredForUsage(usage);
}
@@ -557,7 +559,7 @@
for (int usage : ALL_USAGES) {
if (usage == USAGE_NOTIFICATION) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_SETTINGS);
} else {
assertVibrationNotIgnoredForUsage(usage);
}
@@ -574,7 +576,7 @@
for (int usage : ALL_USAGES) {
if (usage == USAGE_RINGTONE) {
- assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(usage, Status.IGNORED_FOR_SETTINGS);
} else {
assertVibrationNotIgnoredForUsage(usage);
}
@@ -597,7 +599,7 @@
mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
- assertVibrationIgnoredForUsage(USAGE_RINGTONE, Vibration.Status.IGNORED_FOR_RINGER_MODE);
+ assertVibrationIgnoredForUsage(USAGE_RINGTONE, Status.IGNORED_FOR_RINGER_MODE);
}
@Test
@@ -611,7 +613,7 @@
new VibrationAttributes.Builder()
.setUsage(USAGE_IME_FEEDBACK)
.build(),
- Vibration.Status.IGNORED_FOR_SETTINGS);
+ Status.IGNORED_FOR_SETTINGS);
// General touch and keyboard touch with bypass flag not ignored.
assertVibrationNotIgnoredForUsage(USAGE_TOUCH);
@@ -629,7 +631,7 @@
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 1 /* ON */);
// General touch ignored.
- assertVibrationIgnoredForUsage(USAGE_TOUCH, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(USAGE_TOUCH, Status.IGNORED_FOR_SETTINGS);
// Keyboard touch not ignored.
assertVibrationNotIgnoredForAttributes(
@@ -645,14 +647,14 @@
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 1 /* ON */);
// General touch ignored.
- assertVibrationIgnoredForUsage(USAGE_TOUCH, Vibration.Status.IGNORED_FOR_SETTINGS);
+ assertVibrationIgnoredForUsage(USAGE_TOUCH, Status.IGNORED_FOR_SETTINGS);
// Keyboard touch ignored.
assertVibrationIgnoredForAttributes(
new VibrationAttributes.Builder()
.setUsage(USAGE_IME_FEEDBACK)
.build(),
- Vibration.Status.IGNORED_FOR_SETTINGS);
+ Status.IGNORED_FOR_SETTINGS);
}
@Test
@@ -668,7 +670,7 @@
// Ignore the vibration when the coming device id represents a virtual device.
for (int usage : ALL_USAGES) {
assertVibrationIgnoredForUsageAndDevice(usage, VIRTUAL_DEVICE_ID,
- Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE);
+ Status.IGNORED_FROM_VIRTUAL_DEVICE);
}
}
@@ -911,22 +913,21 @@
}
private void assertVibrationIgnoredForUsage(@VibrationAttributes.Usage int usage,
- Vibration.Status expectedStatus) {
+ Status expectedStatus) {
assertVibrationIgnoredForUsageAndDevice(usage, Context.DEVICE_ID_DEFAULT, expectedStatus);
}
private void assertVibrationIgnoredForUsageAndDevice(@VibrationAttributes.Usage int usage,
- int deviceId, Vibration.Status expectedStatus) {
- Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(
+ int deviceId, Status expectedStatus) {
+ CallerInfo callerInfo = new CallerInfo(
VibrationAttributes.createForUsage(usage), UID, deviceId, null, null);
assertEquals(errorMessageForUsage(usage), expectedStatus,
mVibrationSettings.shouldIgnoreVibration(callerInfo));
}
private void assertVibrationIgnoredForAttributes(VibrationAttributes attrs,
- Vibration.Status expectedStatus) {
- Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(attrs, UID,
- Context.DEVICE_ID_DEFAULT, null, null);
+ Status expectedStatus) {
+ CallerInfo callerInfo = new CallerInfo(attrs, UID, Context.DEVICE_ID_DEFAULT, null, null);
assertEquals(errorMessageForAttributes(attrs), expectedStatus,
mVibrationSettings.shouldIgnoreVibration(callerInfo));
}
@@ -948,7 +949,7 @@
private void assertVibrationNotIgnoredForUsageAndFlagsAndDevice(
@VibrationAttributes.Usage int usage, int deviceId,
@VibrationAttributes.Flag int flags) {
- Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(
+ CallerInfo callerInfo = new CallerInfo(
new VibrationAttributes.Builder().setUsage(usage).setFlags(flags).build(), UID,
deviceId, null, null);
assertNull(errorMessageForUsage(usage),
@@ -956,7 +957,7 @@
}
private void assertVibrationNotIgnoredForAttributes(VibrationAttributes attrs) {
- Vibration.CallerInfo callerInfo = new Vibration.CallerInfo(attrs, UID,
+ CallerInfo callerInfo = new CallerInfo(attrs, UID,
Context.DEVICE_ID_DEFAULT, null, null);
assertNull(errorMessageForAttributes(attrs),
mVibrationSettings.shouldIgnoreVibration(callerInfo));
@@ -1017,10 +1018,10 @@
new PowerManager.SleepData(sleepTime, reason));
}
- private Vibration.CallerInfo createCallerInfo(int uid, String opPkg,
+ private CallerInfo createCallerInfo(int uid, String opPkg,
@VibrationAttributes.Usage int usage) {
VibrationAttributes attrs = VibrationAttributes.createForUsage(usage);
- return new Vibration.CallerInfo(attrs, uid, VIRTUAL_DEVICE_ID, opPkg, null);
+ return new CallerInfo(attrs, uid, VIRTUAL_DEVICE_ID, opPkg, null);
}
private void setBatteryReceiverRegistrationResult(Intent result) {
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
index bfdaa78..31cc50f1 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -78,6 +78,8 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.LocalServices;
+import com.android.server.vibrator.VibrationSession.CallerInfo;
+import com.android.server.vibrator.VibrationSession.Status;
import org.junit.After;
import org.junit.Before;
@@ -189,7 +191,7 @@
waitForCompletion();
verify(mControllerCallbacks, never()).onComplete(anyInt(), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
+ verifyCallbacksTriggered(vibrationId, Status.IGNORED_UNSUPPORTED);
}
@Test
@@ -202,7 +204,7 @@
waitForCompletion();
verify(mControllerCallbacks, never()).onComplete(anyInt(), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
+ verifyCallbacksTriggered(vibrationId, Status.IGNORED_UNSUPPORTED);
}
@Test
@@ -216,7 +218,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(10)),
@@ -233,7 +235,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(10)),
@@ -253,7 +255,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(15L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(15)),
@@ -326,13 +328,10 @@
assertTrue(mThread.isRunningVibrationId(vibrationId));
assertTrue(mControllers.get(VIBRATOR_ID).isVibrating());
- Vibration.EndInfo cancelVibrationInfo = new Vibration.EndInfo(
- Vibration.Status.CANCELLED_SUPERSEDED, new Vibration.CallerInfo(
- VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ALARM), /* uid= */
- 1, /* deviceId= */ -1, /* opPkg= */ null, /* reason= */ null));
- mVibrationConductor.notifyCancelled(
- cancelVibrationInfo,
- /* immediate= */ false);
+ Vibration.EndInfo cancelVibrationInfo = new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
+ new CallerInfo(VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ALARM),
+ /* uid= */ 1, /* deviceId= */ -1, /* opPkg= */ null, /* reason= */ null));
+ mVibrationConductor.notifyCancelled(cancelVibrationInfo, /* immediate= */ false);
waitForCompletion();
assertFalse(mThread.isRunningVibrationId(vibrationId));
@@ -363,11 +362,10 @@
assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false);
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_USER);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(5000)),
fakeVibrator.getEffectSegments(vibrationId));
@@ -385,7 +383,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(300L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
assertThat(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId))
@@ -406,7 +404,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(350L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
assertThat(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId))
@@ -433,11 +431,10 @@
assertTrue(waitUntil(() -> fakeVibrator.getEffectSegments(vibrationId).size() >= 5,
5000L + TEST_TIMEOUT_MILLIS));
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false);
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_USER);
assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
assertThat(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).subList(0, 5))
@@ -466,12 +463,11 @@
assertTrue(waitUntil(() -> !fakeVibrator.getEffectSegments(vibrationId).isEmpty(),
TEST_TIMEOUT_MILLIS));
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false);
waitForCompletion();
// PWLE size max was used to generate a single vibrate call with 10 segments.
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_USER);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(10, fakeVibrator.getEffectSegments(vibrationId).size());
}
@@ -496,12 +492,11 @@
assertTrue(waitUntil(() -> !fakeVibrator.getEffectSegments(vibrationId).isEmpty(),
TEST_TIMEOUT_MILLIS));
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_SCREEN_OFF), /* immediate= */ false);
waitForCompletion();
// Composition size max was used to generate a single vibrate call with 10 primitives.
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_SCREEN_OFF);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(10, fakeVibrator.getEffectSegments(vibrationId).size());
}
@@ -519,11 +514,10 @@
assertTrue(waitUntil(() -> !fakeVibrator.getAmplitudes().isEmpty(), TEST_TIMEOUT_MILLIS));
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false);
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_USER);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(5550)),
fakeVibrator.getEffectSegments(vibrationId));
@@ -545,11 +539,10 @@
assertTrue(waitUntil(() -> fakeVibrator.getEffectSegments(vibrationId).size() > 1,
expectedOnDuration + TEST_TIMEOUT_MILLIS));
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false);
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_USER);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
List<VibrationEffectSegment> effectSegments = fakeVibrator.getEffectSegments(vibrationId);
// First time, turn vibrator ON for the expected fixed duration.
@@ -584,14 +577,14 @@
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
Thread cancellingThread =
new Thread(() -> mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE),
+ new Vibration.EndInfo(Status.CANCELLED_BY_SETTINGS_UPDATE),
/* immediate= */ false));
cancellingThread.start();
waitForCompletion(/* timeout= */ 50);
cancellingThread.join();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_SETTINGS_UPDATE);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@@ -614,14 +607,14 @@
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
Thread cancellingThread =
new Thread(() -> mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE),
+ new Vibration.EndInfo(Status.CANCELLED_BY_SETTINGS_UPDATE),
/* immediate= */ false));
cancellingThread.start();
waitForCompletion(/* timeout= */ 50);
cancellingThread.join();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_SETTINGS_UPDATE);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@@ -641,14 +634,14 @@
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
Thread cancellingThread =
new Thread(() -> mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+ new Vibration.EndInfo(Status.CANCELLED_BY_SCREEN_OFF),
/* immediate= */ false));
cancellingThread.start();
waitForCompletion(/* timeout= */ 50);
cancellingThread.join();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_SCREEN_OFF);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@@ -663,7 +656,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_THUD)),
@@ -684,7 +677,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedOneShot(10)),
@@ -701,7 +694,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L));
verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
+ verifyCallbacksTriggered(vibrationId, Status.IGNORED_UNSUPPORTED);
assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty());
}
@@ -718,7 +711,7 @@
eq(PerformVendorEffectVibratorStep.VENDOR_EFFECT_MAX_DURATION_MS));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertThat(mControllers.get(VIBRATOR_ID).isVibrating()).isFalse();
assertThat(mVibratorProviders.get(VIBRATOR_ID).getVendorEffects(vibrationId))
@@ -743,7 +736,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(40L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(
expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0),
@@ -762,7 +755,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L));
verify(mManagerHooks, never()).noteVibratorOff(eq(UID));
verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.IGNORED_UNSUPPORTED);
+ verifyCallbacksTriggered(vibrationId, Status.IGNORED_UNSUPPORTED);
assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty());
}
@@ -784,7 +777,7 @@
long vibrationId = startThreadAndDispatcher(effect);
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
// Vibrator compose called twice.
verify(mControllerCallbacks, times(2)).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
assertEquals(3, fakeVibrator.getEffectSegments(vibrationId).size());
@@ -824,7 +817,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(10L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks, times(5)).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(
expectedOneShot(10),
@@ -865,7 +858,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), anyLong());
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks, times(4)).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
List<VibrationEffectSegment> segments =
@@ -904,7 +897,7 @@
verify(mManagerHooks).noteVibratorOn(eq(UID), eq(100L));
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(
expectedRamp(/* amplitude= */ 1, /* frequencyHz= */ 150, /* duration= */ 10),
@@ -942,7 +935,7 @@
long vibrationId = startThreadAndDispatcher(effect);
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
// Vibrator compose called 3 times with 2 segments instead of 2 times with 3 segments.
// Using best split points instead of max-packing PWLEs.
@@ -967,7 +960,7 @@
waitForCompletion();
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BINDER_DIED);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BINDER_DIED);
}
@Test
@@ -977,7 +970,7 @@
long vibrationId = startThreadAndDispatcher(VibrationEffect.createOneShot(10, 100));
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
verify(mManagerHooks, never()).prepareSyncedVibration(anyLong(), any());
verify(mManagerHooks, never()).triggerSyncedVibration(anyLong());
verify(mManagerHooks, never()).cancelSyncedVibration();
@@ -998,7 +991,7 @@
verify(mManagerHooks).noteVibratorOff(eq(UID));
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
verify(mControllerCallbacks, never()).onComplete(eq(2), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_TICK)),
@@ -1022,7 +1015,7 @@
verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(1).isVibrating());
assertFalse(mControllers.get(2).isVibrating());
assertFalse(mControllers.get(3).isVibrating());
@@ -1065,7 +1058,7 @@
verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(4), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(1).isVibrating());
assertFalse(mControllers.get(2).isVibrating());
assertFalse(mControllers.get(3).isVibrating());
@@ -1117,7 +1110,7 @@
batteryVerifier.verify(mManagerHooks).noteVibratorOn(eq(UID), eq(20L));
batteryVerifier.verify(mManagerHooks).noteVibratorOff(eq(UID));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(1).isVibrating());
assertFalse(mControllers.get(2).isVibrating());
assertFalse(mControllers.get(3).isVibrating());
@@ -1166,7 +1159,7 @@
verify(mManagerHooks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mManagerHooks).triggerSyncedVibration(eq(vibrationId));
verify(mManagerHooks, never()).cancelSyncedVibration();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
VibrationEffectSegment expected = expectedPrimitive(
VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 100);
@@ -1213,7 +1206,7 @@
verify(mManagerHooks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mManagerHooks).triggerSyncedVibration(eq(vibrationId));
verify(mManagerHooks, never()).cancelSyncedVibration();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
}
@Test
@@ -1305,7 +1298,7 @@
verify(mControllerCallbacks).onComplete(eq(1), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(2), eq(vibrationId));
verify(mControllerCallbacks).onComplete(eq(3), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertFalse(mControllers.get(1).isVibrating());
assertFalse(mControllers.get(2).isVibrating());
assertFalse(mControllers.get(3).isVibrating());
@@ -1478,8 +1471,7 @@
// fail at waitForCompletion(cancellingThread).
Thread cancellingThread = new Thread(
() -> mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false));
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false));
cancellingThread.start();
// Cancelling the vibration should be fast and return right away, even if the thread is
@@ -1488,7 +1480,7 @@
// After the vibrator call ends the vibration is cancelled and the vibrator is turned off.
waitForCompletion(/* timeout= */ latency + TEST_TIMEOUT_MILLIS);
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_USER);
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@@ -1517,14 +1509,14 @@
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
Thread cancellingThread = new Thread(
() -> mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+ new Vibration.EndInfo(Status.CANCELLED_BY_SCREEN_OFF),
/* immediate= */ false));
cancellingThread.start();
waitForCompletion(/* timeout= */ 50);
cancellingThread.join();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_SCREEN_OFF);
assertFalse(mControllers.get(1).isVibrating());
assertFalse(mControllers.get(2).isVibrating());
}
@@ -1551,14 +1543,14 @@
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
Thread cancellingThread = new Thread(
() -> mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+ new Vibration.EndInfo(Status.CANCELLED_BY_SCREEN_OFF),
/* immediate= */ false));
cancellingThread.start();
waitForCompletion(/* timeout= */ 50);
cancellingThread.join();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_SCREEN_OFF);
assertFalse(mControllers.get(1).isVibrating());
assertFalse(mControllers.get(2).isVibrating());
}
@@ -1585,15 +1577,14 @@
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
Thread cancellingThread = new Thread(
() -> mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(
- Vibration.Status.CANCELLED_BY_SCREEN_OFF),
+ new Vibration.EndInfo(Status.CANCELLED_BY_SCREEN_OFF),
/* immediate= */ false));
cancellingThread.start();
waitForCompletion(/* timeout= */ 50);
cancellingThread.join();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_SCREEN_OFF);
assertFalse(mControllers.get(1).isVibrating());
assertFalse(mControllers.get(2).isVibrating());
}
@@ -1612,7 +1603,7 @@
verify(mVibrationToken).linkToDeath(same(mVibrationConductor), eq(0));
verify(mVibrationToken).unlinkToDeath(same(mVibrationConductor), eq(0));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BINDER_DIED);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BINDER_DIED);
assertFalse(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId).isEmpty());
assertFalse(mControllers.get(VIBRATOR_ID).isVibrating());
}
@@ -1628,7 +1619,7 @@
waitForCompletion();
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
// Duration extended for 5 + 5 + 5 + 15.
assertEquals(Arrays.asList(expectedOneShot(30)),
@@ -1651,7 +1642,7 @@
// Vibration completed but vibrator not yet released.
verify(mManagerHooks, timeout(TEST_TIMEOUT_MILLIS)).onVibrationCompleted(eq(vibrationId),
- eq(new Vibration.EndInfo(Vibration.Status.FINISHED)));
+ eq(new Vibration.EndInfo(Status.FINISHED)));
verify(mManagerHooks, never()).onVibrationThreadReleased(anyLong());
// Thread still running ramp down.
@@ -1663,13 +1654,12 @@
// Will stop the ramp down right away.
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE),
- /* immediate= */ true);
+ new Vibration.EndInfo(Status.CANCELLED_BY_SETTINGS_UPDATE), /* immediate= */ true);
waitForCompletion();
// Does not cancel already finished vibration, but releases vibrator.
verify(mManagerHooks, never()).onVibrationCompleted(eq(vibrationId),
- eq(new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SETTINGS_UPDATE)));
+ eq(new Vibration.EndInfo(Status.CANCELLED_BY_SETTINGS_UPDATE)));
verify(mManagerHooks).onVibrationThreadReleased(vibrationId);
}
@@ -1684,11 +1674,10 @@
assertTrue(waitUntil(() -> mControllers.get(VIBRATOR_ID).isVibrating(),
TEST_TIMEOUT_MILLIS));
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false);
waitForCompletion();
- verifyCallbacksTriggered(vibrationId, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId, Status.CANCELLED_BY_USER);
// Duration extended for 10000 + 15.
assertEquals(Arrays.asList(expectedOneShot(10_015)),
@@ -1711,7 +1700,7 @@
waitForCompletion();
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibrationId));
@@ -1729,7 +1718,7 @@
waitForCompletion();
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertThat(mVibratorProviders.get(VIBRATOR_ID).getVendorEffects(vibrationId))
.containsExactly(effect)
@@ -1752,7 +1741,7 @@
waitForCompletion();
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertEquals(
Arrays.asList(expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0)),
@@ -1779,7 +1768,7 @@
waitForCompletion();
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
- verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId, Status.FINISHED);
assertEquals(Arrays.asList(expectedRamp(0, 1, 150, 150, 1)),
fakeVibrator.getEffectSegments(vibrationId));
@@ -1810,14 +1799,13 @@
long vibrationId1 = startThreadAndDispatcher(effect1);
waitForCompletion();
verify(mControllerCallbacks).onComplete(VIBRATOR_ID, vibrationId1);
- verifyCallbacksTriggered(vibrationId1, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId1, Status.FINISHED);
long vibrationId2 = startThreadAndDispatcher(effect2);
// Effect2 won't complete on its own. Cancel it after a couple of repeats.
Thread.sleep(150); // More than two TICKs.
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_USER),
- /* immediate= */ false);
+ new Vibration.EndInfo(Status.CANCELLED_BY_USER), /* immediate= */ false);
waitForCompletion();
long vibrationId3 = startThreadAndDispatcher(effect3);
@@ -1827,8 +1815,7 @@
long start4 = System.currentTimeMillis();
long vibrationId4 = startThreadAndDispatcher(effect4);
mVibrationConductor.notifyCancelled(
- new Vibration.EndInfo(Vibration.Status.CANCELLED_BY_SCREEN_OFF),
- /* immediate= */ true);
+ new Vibration.EndInfo(Status.CANCELLED_BY_SCREEN_OFF), /* immediate= */ true);
waitForCompletion();
long duration4 = System.currentTimeMillis() - start4;
@@ -1841,14 +1828,14 @@
// Effect1
verify(mControllerCallbacks).onComplete(VIBRATOR_ID, vibrationId1);
- verifyCallbacksTriggered(vibrationId1, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId1, Status.FINISHED);
assertEquals(Arrays.asList(expectedPrebaked(VibrationEffect.EFFECT_CLICK)),
fakeVibrator.getEffectSegments(vibrationId1));
// Effect2: repeating, cancelled.
verify(mControllerCallbacks, atLeast(2)).onComplete(VIBRATOR_ID, vibrationId2);
- verifyCallbacksTriggered(vibrationId2, Vibration.Status.CANCELLED_BY_USER);
+ verifyCallbacksTriggered(vibrationId2, Status.CANCELLED_BY_USER);
// The exact count of segments might vary, so just check that there's more than 2 and
// all elements are the same segment.
@@ -1860,13 +1847,13 @@
// Effect3
verify(mControllerCallbacks).onComplete(eq(VIBRATOR_ID), eq(vibrationId3));
- verifyCallbacksTriggered(vibrationId3, Vibration.Status.FINISHED);
+ verifyCallbacksTriggered(vibrationId3, Status.FINISHED);
assertEquals(Arrays.asList(
expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0)),
fakeVibrator.getEffectSegments(vibrationId3));
// Effect4: cancelled quickly.
- verifyCallbacksTriggered(vibrationId4, Vibration.Status.CANCELLED_BY_SCREEN_OFF);
+ verifyCallbacksTriggered(vibrationId4, Status.CANCELLED_BY_SCREEN_OFF);
assertTrue("Tested duration=" + duration4, duration4 < 2000);
// Effect5: played normally after effect4, which may or may not have played.
@@ -1907,7 +1894,7 @@
.build();
HalVibration vib = new HalVibration(mVibrationToken,
CombinedVibration.createParallel(effect),
- new Vibration.CallerInfo(attrs, UID, DEVICE_ID, PACKAGE_NAME, "reason"));
+ new CallerInfo(attrs, UID, DEVICE_ID, PACKAGE_NAME, "reason"));
return startThreadAndDispatcher(vib, requestVibrationParamsFuture);
}
@@ -1944,7 +1931,7 @@
private HalVibration createVibration(CombinedVibration effect) {
return new HalVibration(mVibrationToken, effect,
- new Vibration.CallerInfo(ATTRS, UID, DEVICE_ID, PACKAGE_NAME, "reason"));
+ new CallerInfo(ATTRS, UID, DEVICE_ID, PACKAGE_NAME, "reason"));
}
private SparseArray<VibratorController> createVibratorControllers() {
@@ -2007,7 +1994,7 @@
.collect(Collectors.toList());
}
- private void verifyCallbacksTriggered(long vibrationId, Vibration.Status expectedStatus) {
+ private void verifyCallbacksTriggered(long vibrationId, Status expectedStatus) {
verifyCallbacksTriggered(vibrationId, new Vibration.EndInfo(expectedStatus));
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorFrameworkStatsLoggerTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorFrameworkStatsLoggerTest.java
index 3466bbb..cd057b6 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorFrameworkStatsLoggerTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorFrameworkStatsLoggerTest.java
@@ -22,6 +22,8 @@
import android.os.Handler;
import android.os.test.TestLooper;
+import com.android.server.vibrator.VibrationSession.Status;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -113,7 +115,6 @@
}
private static VibrationStats.StatsInfo newEmptyStatsInfo() {
- return new VibrationStats.StatsInfo(
- 0, 0, 0, Vibration.Status.FINISHED, new VibrationStats(), 0L);
+ return new VibrationStats.StatsInfo(0, 0, 0, Status.FINISHED, new VibrationStats(), 0L);
}
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 4afb562..4012575 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -110,6 +110,7 @@
import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
import com.android.server.pm.BackgroundUserSoundNotifier;
+import com.android.server.vibrator.VibrationSession.Status;
import org.junit.After;
import org.junit.Before;
@@ -803,8 +804,8 @@
mockVibrators(1);
VibratorManagerService service = createSystemReadyService();
- var vib = vibrate(service,
- VibrationEffect.createWaveform(new long[]{100, 100, 100, 100}, 0), RINGTONE_ATTRS);
+ HalVibration vib = vibrate(service, VibrationEffect.createWaveform(
+ new long[]{0, TEST_TIMEOUT_MILLIS, TEST_TIMEOUT_MILLIS}, 0), RINGTONE_ATTRS);
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
@@ -815,14 +816,80 @@
service.mAppOpsChangeListener.onOpChanged(AppOpsManager.OP_VIBRATE, null);
assertTrue(waitUntil(s -> vib.hasEnded(), service, TEST_TIMEOUT_MILLIS));
+ assertThat(vib.getStatus()).isEqualTo(Status.CANCELLED_BY_APP_OPS);
+ }
- var statsInfoCaptor = ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
- verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
- .writeVibrationReportedAsync(statsInfoCaptor.capture());
+ @Test
+ public void vibrate_thenPowerModeChanges_getsCancelled() throws Exception {
+ mockVibrators(1, 2);
+ VibratorManagerService service = createSystemReadyService();
- VibrationStats.StatsInfo touchMetrics = statsInfoCaptor.getAllValues().get(0);
- assertEquals(Vibration.Status.CANCELLED_BY_APP_OPS.getProtoEnumValue(),
- touchMetrics.status);
+ HalVibration vib = vibrate(service,
+ CombinedVibration.startParallel()
+ .addVibrator(1, VibrationEffect.createOneShot(2 * TEST_TIMEOUT_MILLIS, 100))
+ .combine(),
+ HAPTIC_FEEDBACK_ATTRS);
+
+ // VibrationThread will start this vibration async, so wait until vibration is triggered.
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+
+ assertTrue(waitUntil(s -> vib.hasEnded(), service, TEST_TIMEOUT_MILLIS));
+ assertThat(vib.getStatus()).isEqualTo(Status.CANCELLED_BY_SETTINGS_UPDATE);
+ }
+
+ @Test
+ public void vibrate_thenSettingsRefreshedWithoutChange_doNotCancelVibration() throws Exception {
+ mockVibrators(1);
+ VibratorManagerService service = createSystemReadyService();
+
+ vibrate(service, VibrationEffect.createOneShot(2 * TEST_TIMEOUT_MILLIS, 100),
+ HAPTIC_FEEDBACK_ATTRS);
+
+ // VibrationThread will start this vibration async, so wait until vibration is triggered.
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ service.updateServiceState();
+
+ // Vibration is not stopped nearly after updating service.
+ assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50));
+ }
+
+ @Test
+ public void vibrate_thenSettingsChange_getsCancelled() throws Exception {
+ mockVibrators(1);
+ VibratorManagerService service = createSystemReadyService();
+
+ HalVibration vib = vibrate(service,
+ VibrationEffect.createOneShot(2 * TEST_TIMEOUT_MILLIS, 100),
+ HAPTIC_FEEDBACK_ATTRS);
+
+ // VibrationThread will start this vibration async, so wait until vibration is triggered.
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF);
+ service.mVibrationSettings.mSettingObserver.onChange(false);
+ service.updateServiceState();
+
+ assertTrue(waitUntil(s -> vib.hasEnded(), service, TEST_TIMEOUT_MILLIS));
+ assertThat(vib.getStatus()).isEqualTo(Status.CANCELLED_BY_SETTINGS_UPDATE);
+ }
+
+ @Test
+ public void vibrate_thenScreenTurnsOff_getsCancelled() throws Throwable {
+ mockVibrators(1);
+ VibratorManagerService service = createSystemReadyService();
+
+ HalVibration vib = vibrate(service, VibrationEffect.createWaveform(
+ new long[]{0, TEST_TIMEOUT_MILLIS, TEST_TIMEOUT_MILLIS}, 0), ALARM_ATTRS);
+
+ assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
+
+ service.mIntentReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_SCREEN_OFF));
+
+ assertTrue(waitUntil(s -> vib.hasEnded(), service, TEST_TIMEOUT_MILLIS));
+ assertThat(vib.getStatus()).isEqualTo(Status.CANCELLED_BY_SCREEN_OFF);
}
@Test
@@ -831,8 +898,8 @@
mockVibrators(1);
VibratorManagerService service = createSystemReadyService();
- var vib = vibrate(service,
- VibrationEffect.createWaveform(new long[]{100, 100, 100, 100}, 0), ALARM_ATTRS);
+ HalVibration vib = vibrate(service, VibrationEffect.createWaveform(
+ new long[]{0, TEST_TIMEOUT_MILLIS, TEST_TIMEOUT_MILLIS}, 0), ALARM_ATTRS);
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
@@ -841,14 +908,7 @@
BackgroundUserSoundNotifier.ACTION_MUTE_SOUND));
assertTrue(waitUntil(s -> vib.hasEnded(), service, TEST_TIMEOUT_MILLIS));
-
- var statsInfoCaptor = ArgumentCaptor.forClass(VibrationStats.StatsInfo.class);
- verify(mVibratorFrameworkStatsLoggerMock, timeout(TEST_TIMEOUT_MILLIS))
- .writeVibrationReportedAsync(statsInfoCaptor.capture());
-
- VibrationStats.StatsInfo touchMetrics = statsInfoCaptor.getAllValues().get(0);
- assertEquals(Vibration.Status.CANCELLED_BY_FOREGROUND_USER.getProtoEnumValue(),
- touchMetrics.status);
+ assertThat(vib.getStatus()).isEqualTo(Status.CANCELLED_BY_FOREGROUND_USER);
}
@Test
@@ -1314,7 +1374,7 @@
}
@Test
- public void vibrate_withriggerCallback_finishesVibration() throws Exception {
+ public void vibrate_withTriggerCallback_finishesVibration() throws Exception {
mockCapabilities(IVibratorManager.CAP_SYNC, IVibratorManager.CAP_PREPARE_COMPOSE);
mockVibrators(1, 2);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
@@ -1947,41 +2007,6 @@
}
@Test
- public void vibrate_withPowerModeChange_cancelVibrationIfNotAllowed() throws Exception {
- mockVibrators(1, 2);
- VibratorManagerService service = createSystemReadyService();
- vibrate(service,
- CombinedVibration.startParallel()
- .addVibrator(1, VibrationEffect.createOneShot(1000, 100))
- .combine(),
- HAPTIC_FEEDBACK_ATTRS);
-
- // VibrationThread will start this vibration async, so wait until vibration is triggered.
- assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
-
- mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
-
- // Haptic feedback cancelled on low power mode.
- assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
- }
-
- @Test
- public void vibrate_withSettingsChange_doNotCancelVibration() throws Exception {
- mockVibrators(1);
- VibratorManagerService service = createSystemReadyService();
-
- vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS);
-
- // VibrationThread will start this vibration async, so wait until vibration is triggered.
- assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
-
- service.updateServiceState();
-
- // Vibration is not stopped nearly after updating service.
- assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50));
- }
-
- @Test
public void vibrate_ignoreVibrationFromVirtualDevice() throws Exception {
mockVibrators(1);
VibratorManagerService service = createSystemReadyService();
@@ -2475,6 +2500,113 @@
}
@Test
+ public void onExternalVibration_thenDeniedAppOps_doNotCancelVibration() throws Throwable {
+ mockVibrators(1);
+ mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+
+ IExternalVibrationController externalVibrationControllerMock =
+ mock(IExternalVibrationController.class);
+ ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+ AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
+ ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
+ externalVibration);
+
+ assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);
+
+ when(mAppOpsManagerMock.checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_ALARM), anyInt(), anyString()))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
+ service.mAppOpsChangeListener.onOpChanged(AppOpsManager.OP_VIBRATE, null);
+
+ verify(externalVibrationControllerMock, never()).mute();
+ }
+
+ @Test
+ public void onExternalVibration_thenPowerModeChanges_doNotCancelVibration() throws Exception {
+ mockVibrators(1);
+ mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+ createSystemReadyService();
+
+ IExternalVibrationController externalVibrationControllerMock =
+ mock(IExternalVibrationController.class);
+ ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+ AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
+ ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
+ externalVibration);
+
+ assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);
+
+ mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+
+ verify(externalVibrationControllerMock, never()).mute();
+ }
+
+ @Test
+ public void onExternalVibration_thenSettingsChange_doNotCancelVibration() throws Exception {
+ mockVibrators(1);
+ mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+
+ IExternalVibrationController externalVibrationControllerMock =
+ mock(IExternalVibrationController.class);
+ ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+ AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
+ ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
+ externalVibration);
+
+ assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);
+
+ setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF);
+ service.mVibrationSettings.mSettingObserver.onChange(false);
+ service.updateServiceState();
+
+ verify(externalVibrationControllerMock, never()).mute();
+ }
+
+ @Test
+ public void onExternalVibration_thenScreenTurnsOff_doNotCancelVibration() throws Throwable {
+ mockVibrators(1);
+ mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+
+ IExternalVibrationController externalVibrationControllerMock =
+ mock(IExternalVibrationController.class);
+ ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+ AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
+ ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
+ externalVibration);
+
+ assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);
+
+ service.mIntentReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_SCREEN_OFF));
+
+ verify(externalVibrationControllerMock, never()).mute();
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.multiuser.Flags.FLAG_ADD_UI_FOR_SOUNDS_FROM_BACKGROUND_USERS)
+ public void onExternalVibration_thenFgUserRequestsMute_doNotCancelVibration() throws Throwable {
+ mockVibrators(1);
+ mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
+ VibratorManagerService service = createSystemReadyService();
+
+ IExternalVibrationController externalVibrationControllerMock =
+ mock(IExternalVibrationController.class);
+ ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+ AUDIO_ALARM_ATTRS, externalVibrationControllerMock, mock(IBinder.class));
+ ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
+ externalVibration);
+
+ assertThat(scale.scaleLevel).isNotEqualTo(ExternalVibrationScale.ScaleLevel.SCALE_MUTE);
+
+ service.mIntentReceiver.onReceive(mContextSpy, new Intent(
+ BackgroundUserSoundNotifier.ACTION_MUTE_SOUND));
+
+ verify(externalVibrationControllerMock, never()).mute();
+ }
+
+ @Test
public void frameworkStats_externalVibration_reportsAllMetrics() throws Exception {
mockVibrators(1);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
@@ -2501,7 +2633,7 @@
assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__EXTERNAL,
statsInfo.vibrationType);
assertEquals(VibrationAttributes.USAGE_ALARM, statsInfo.usage);
- assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), statsInfo.status);
+ assertEquals(Status.FINISHED.getProtoEnumValue(), statsInfo.status);
assertTrue(statsInfo.totalDurationMillis > 0);
assertTrue(
"Expected vibrator ON for at least 10ms, got " + statsInfo.vibratorOnMillis + "ms",
@@ -2533,7 +2665,7 @@
assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE,
metrics.vibrationType);
assertEquals(VibrationAttributes.USAGE_RINGTONE, metrics.usage);
- assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), metrics.status);
+ assertEquals(Status.FINISHED.getProtoEnumValue(), metrics.status);
assertTrue("Total duration was too low, " + metrics.totalDurationMillis + "ms",
metrics.totalDurationMillis >= 20);
assertTrue("Vibrator ON duration was too low, " + metrics.vibratorOnMillis + "ms",
@@ -2586,7 +2718,7 @@
assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__REPEATED,
metrics.vibrationType);
assertEquals(VibrationAttributes.USAGE_RINGTONE, metrics.usage);
- assertEquals(Vibration.Status.CANCELLED_BY_USER.getProtoEnumValue(), metrics.status);
+ assertEquals(Status.CANCELLED_BY_USER.getProtoEnumValue(), metrics.status);
assertTrue("Total duration was too low, " + metrics.totalDurationMillis + "ms",
metrics.totalDurationMillis >= 100);
assertTrue("Vibrator ON duration was too low, " + metrics.vibratorOnMillis + "ms",
@@ -2647,7 +2779,7 @@
assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE,
metrics.vibrationType);
assertEquals(VibrationAttributes.USAGE_ALARM, metrics.usage);
- assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), metrics.status);
+ assertEquals(Status.FINISHED.getProtoEnumValue(), metrics.status);
// At least 4 effect/primitive played, 20ms each, plus configured fallback.
assertTrue("Total duration was too low, " + metrics.totalDurationMillis + "ms",
@@ -2703,7 +2835,7 @@
VibrationStats.StatsInfo touchMetrics = argumentCaptor.getAllValues().get(0);
assertEquals(UID, touchMetrics.uid);
assertEquals(VibrationAttributes.USAGE_TOUCH, touchMetrics.usage);
- assertEquals(Vibration.Status.CANCELLED_SUPERSEDED.getProtoEnumValue(),
+ assertEquals(Status.CANCELLED_SUPERSEDED.getProtoEnumValue(),
touchMetrics.status);
assertTrue(touchMetrics.endedBySameUid);
assertEquals(VibrationAttributes.USAGE_ALARM, touchMetrics.endedByUsage);
@@ -2712,7 +2844,7 @@
VibrationStats.StatsInfo alarmMetrics = argumentCaptor.getAllValues().get(1);
assertEquals(UID, alarmMetrics.uid);
assertEquals(VibrationAttributes.USAGE_ALARM, alarmMetrics.usage);
- assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), alarmMetrics.status);
+ assertEquals(Status.FINISHED.getProtoEnumValue(), alarmMetrics.status);
assertFalse(alarmMetrics.endedBySameUid);
assertEquals(-1, alarmMetrics.endedByUsage);
assertEquals(VibrationAttributes.USAGE_TOUCH, alarmMetrics.interruptedUsage);
@@ -2742,12 +2874,12 @@
VibrationStats.StatsInfo touchMetrics = argumentCaptor.getAllValues().get(0);
assertEquals(UID, touchMetrics.uid);
assertEquals(VibrationAttributes.USAGE_TOUCH, touchMetrics.usage);
- assertEquals(Vibration.Status.IGNORED_FOR_POWER.getProtoEnumValue(), touchMetrics.status);
+ assertEquals(Status.IGNORED_FOR_POWER.getProtoEnumValue(), touchMetrics.status);
VibrationStats.StatsInfo ringtoneMetrics = argumentCaptor.getAllValues().get(1);
assertEquals(UID, ringtoneMetrics.uid);
assertEquals(VibrationAttributes.USAGE_RINGTONE, ringtoneMetrics.usage);
- assertEquals(Vibration.Status.IGNORED_FOR_SETTINGS.getProtoEnumValue(),
+ assertEquals(Status.IGNORED_FOR_SETTINGS.getProtoEnumValue(),
ringtoneMetrics.status);
for (VibrationStats.StatsInfo metrics : argumentCaptor.getAllValues()) {
@@ -2814,7 +2946,7 @@
assertEquals(FrameworkStatsLog.VIBRATION_REPORTED__VIBRATION_TYPE__SINGLE,
metrics.vibrationType);
assertEquals(VibrationAttributes.USAGE_NOTIFICATION, metrics.usage);
- assertEquals(Vibration.Status.FINISHED.getProtoEnumValue(), metrics.status);
+ assertEquals(Status.FINISHED.getProtoEnumValue(), metrics.status);
assertTrue(metrics.totalDurationMillis >= 20);
// vibratorOnMillis accumulates both vibrators, it's 20 for each constant.
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
index d147325..0575d98 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
@@ -41,6 +41,8 @@
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -50,6 +52,8 @@
import com.android.internal.R;
import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import java.util.Collections;
@@ -62,7 +66,13 @@
*/
@SmallTest
+@EnableFlags(com.android.hardware.input.Flags.FLAG_MODIFIER_SHORTCUT_MANAGER_REFACTOR)
public class ModifierShortcutManagerTests {
+
+ @ClassRule public static final SetFlagsRule.ClassRule SET_FLAGS_CLASS_RULE =
+ new SetFlagsRule.ClassRule();
+ @Rule public final SetFlagsRule mSetFlagsRule = SET_FLAGS_CLASS_RULE.createSetFlagsRule();
+
private ModifierShortcutManager mModifierShortcutManager;
private Handler mHandler;
private Context mContext;
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
index 71f90a2..43171f8 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java
@@ -44,26 +44,21 @@
import android.content.ComponentName;
import android.content.Intent;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
@Presubmit
@SmallTest
+@EnableFlags(com.android.hardware.input.Flags.FLAG_MODIFIER_SHORTCUT_MANAGER_REFACTOR)
public class ModifierShortcutTests extends ShortcutKeyTestBase {
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
private static final SparseArray<String> INTENT_SHORTCUTS = new SparseArray<>();
private static final SparseArray<String> ROLE_SHORTCUTS = new SparseArray<>();
static {
@@ -258,7 +253,7 @@
* META+CTRL+BACKSPACE for taking a bugreport when the flag is enabled.
*/
@Test
- @RequiresFlagsEnabled(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
+ @EnableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
public void testTakeBugReport_flagEnabled() throws RemoteException {
sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_CTRL_LEFT, KEYCODE_DEL}, 0);
mPhoneWindowManager.assertTakeBugreport(true);
@@ -268,7 +263,7 @@
* META+CTRL+BACKSPACE for taking a bugreport does nothing when the flag is disabledd.
*/
@Test
- @RequiresFlagsDisabled(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
+ @DisableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
public void testTakeBugReport_flagDisabled() throws RemoteException {
sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_CTRL_LEFT, KEYCODE_DEL}, 0);
mPhoneWindowManager.assertTakeBugreport(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index af4394a..0c1fbf3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -25,11 +25,15 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -37,6 +41,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.WindowContainer.POSITION_BOTTOM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -46,11 +51,14 @@
import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.gui.DropInputMode;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -833,6 +841,353 @@
}
@Test
+ public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+ prepareActivityForAppTransition(activity);
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation run by the remote handler.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() {
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord closingActivity = createActivityRecord(task);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
+
+ // Make sure the TaskFragment is not embedded.
+ assertFalse(taskFragment.isEmbeddedWithBoundsOverride());
+ final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
+ prepareActivityForAppTransition(closingActivity);
+ prepareActivityForAppTransition(openingActivity);
+ final int uid = 12345;
+ closingActivity.info.applicationInfo.uid = uid;
+ openingActivity.info.applicationInfo.uid = uid;
+ task.effectiveUid = uid;
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(openingActivity, closingActivity,
+ null /* changingTaskFragment */);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation is not run by the remote handler because the activity is filling the Task.
+ assertFalse(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() {
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord closingActivity = createActivityRecord(task);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
+
+ // Make sure the TaskFragment is embedded.
+ taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ final Rect embeddedBounds = new Rect(task.getBounds());
+ embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2;
+ taskFragment.setBounds(embeddedBounds);
+ assertTrue(taskFragment.isEmbeddedWithBoundsOverride());
+ final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
+ prepareActivityForAppTransition(closingActivity);
+ prepareActivityForAppTransition(openingActivity);
+ final int uid = 12345;
+ closingActivity.info.applicationInfo.uid = uid;
+ openingActivity.info.applicationInfo.uid = uid;
+ task.effectiveUid = uid;
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(openingActivity, closingActivity,
+ null /* changingTaskFragment */);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation run by the remote handler.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Closing non-embedded activity.
+ final ActivityRecord closingActivity = createActivityRecord(task);
+ prepareActivityForAppTransition(closingActivity);
+ // Opening TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
+ prepareActivityForAppTransition(openingActivity);
+ task.effectiveUid = openingActivity.getUid();
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation run by the remote handler.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Closing TaskFragment with embedded activity.
+ final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final ActivityRecord closingActivity = taskFragment1.getTopMostActivity();
+ prepareActivityForAppTransition(closingActivity);
+ closingActivity.info.applicationInfo.uid = 12345;
+ // Opening TaskFragment with embedded activity with different UID.
+ final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final ActivityRecord openingActivity = taskFragment2.getTopMostActivity();
+ prepareActivityForAppTransition(openingActivity);
+ openingActivity.info.applicationInfo.uid = 54321;
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation run by the remote handler.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Closing activity in Task1.
+ final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
+ prepareActivityForAppTransition(closingActivity);
+ // Opening TaskFragment with embedded activity in Task2.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
+ prepareActivityForAppTransition(openingActivity);
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation not run by the remote handler.
+ assertFalse(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Closing TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
+ prepareActivityForAppTransition(closingActivity);
+ closingActivity.info.applicationInfo.uid = 12345;
+ task.effectiveUid = closingActivity.getUid();
+ // Opening non-embedded activity with different UID.
+ final ActivityRecord openingActivity = createActivityRecord(task);
+ prepareActivityForAppTransition(openingActivity);
+ openingActivity.info.applicationInfo.uid = 54321;
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation should not run by the remote handler when there are non-embedded activities of
+ // different UID.
+ assertFalse(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+ prepareActivityForAppTransition(activity);
+ // Set wallpaper as visible.
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
+ spyOn(mDisplayContent.mWallpaperController);
+ doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // Animation should not run by the remote handler when there is wallpaper in the transition.
+ assertFalse(remoteAnimationRunner.isAnimationStarted());
+ }
+
+ @Test
+ public void testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Create a TaskFragment with embedded activities, one is trusted embedded, and the other
+ // one is untrusted embedded.
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(2)
+ .setOrganizer(organizer)
+ .build();
+ final ActivityRecord activity0 = taskFragment.getChildAt(0).asActivityRecord();
+ final ActivityRecord activity1 = taskFragment.getChildAt(1).asActivityRecord();
+ // Also create a non-embedded activity in the Task.
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).build();
+ task.addChild(activity2, POSITION_BOTTOM);
+ prepareActivityForAppTransition(activity0);
+ prepareActivityForAppTransition(activity1);
+ prepareActivityForAppTransition(activity2);
+ doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0);
+ doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1);
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // The animation will be animated remotely by client and all activities are input disabled
+ // for untrusted animation.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ verify(activity0).setDropInputForAnimation(true);
+ verify(activity1).setDropInputForAnimation(true);
+ verify(activity2).setDropInputForAnimation(true);
+ verify(activity0).setDropInputMode(DropInputMode.ALL);
+ verify(activity1).setDropInputMode(DropInputMode.ALL);
+ verify(activity2).setDropInputMode(DropInputMode.ALL);
+
+ // Reset input after animation is finished.
+ clearInvocations(activity0);
+ clearInvocations(activity1);
+ clearInvocations(activity2);
+ remoteAnimationRunner.finishAnimation();
+
+ verify(activity0).setDropInputForAnimation(false);
+ verify(activity1).setDropInputForAnimation(false);
+ verify(activity2).setDropInputForAnimation(false);
+ verify(activity0).setDropInputMode(DropInputMode.OBSCURED);
+ verify(activity1).setDropInputMode(DropInputMode.NONE);
+ verify(activity2).setDropInputMode(DropInputMode.NONE);
+ }
+
+ /**
+ * Since we don't have any use case to rely on handling input during animation, disable it even
+ * if it is trusted embedding so that it could cover some edge-cases when a previously trusted
+ * host starts doing something bad.
+ */
+ @Test
+ public void testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Create a TaskFragment with only trusted embedded activity
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(1)
+ .setOrganizer(organizer)
+ .build();
+ final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
+ prepareActivityForAppTransition(activity);
+ doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity);
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // The animation will be animated remotely by client and all activities are input disabled
+ // for untrusted animation.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ verify(activity).setDropInputForAnimation(true);
+ verify(activity).setDropInputMode(DropInputMode.ALL);
+
+ // Reset input after animation is finished.
+ clearInvocations(activity);
+ remoteAnimationRunner.finishAnimation();
+
+ verify(activity).setDropInputForAnimation(false);
+ verify(activity).setDropInputMode(DropInputMode.NONE);
+ }
+
+ /**
+ * We don't need to drop input for fully trusted embedding (system app, and embedding in the
+ * same app). This will allow users to do fast tapping.
+ */
+ @Test
+ public void testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
+ setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
+
+ // Create a TaskFragment with only trusted embedded activity
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .createActivityCount(1)
+ .setOrganizer(organizer)
+ .build();
+ final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
+ prepareActivityForAppTransition(activity);
+ final int uid = mAtm.mTaskFragmentOrganizerController.getTaskFragmentOrganizerUid(
+ getITaskFragmentOrganizer(organizer));
+ doReturn(true).when(task).isFullyTrustedEmbedding(uid);
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare and start transition.
+ prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ // The animation will be animated remotely by client, but input should not be dropped for
+ // fully trusted.
+ assertTrue(remoteAnimationRunner.isAnimationStarted());
+ verify(activity, never()).setDropInputForAnimation(true);
+ verify(activity, never()).setDropInputMode(DropInputMode.ALL);
+ }
+
+ @Test
public void testTransitionGoodToGoForTaskFragments() {
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final Task task = createTask(mDisplayContent);
@@ -898,6 +1253,22 @@
verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any());
}
+ /** Registers remote animation for the organizer. */
+ private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
+ TestRemoteAnimationRunner remoteAnimationRunner) {
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ remoteAnimationRunner, 10, 1);
+ final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer);
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter);
+ registerTaskFragmentOrganizer(iOrganizer);
+ mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
+ }
+
private static ITaskFragmentOrganizer getITaskFragmentOrganizer(
TaskFragmentOrganizer organizer) {
return ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java
index affaad6..1933908 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentDeferredUpdateTests.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
@@ -316,6 +317,50 @@
verify(mScreenUnblocker).sendToTarget();
}
+ @Test
+ public void testWaitForAllWindowsDrawnForInvalidDisplay_usesTransitionToUnblock() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_WAIT_FOR_TRANSITION_ON_DISPLAY_SWITCH);
+
+ final WindowState defaultDisplayWindow = createWindow(/* parent= */ null,
+ TYPE_BASE_APPLICATION, mDisplayContent, "DefaultDisplayWindow");
+ makeWindowVisibleAndNotDrawn(defaultDisplayWindow);
+
+ mDisplayContent.mDisplayUpdater.onDisplaySwitching(/* switching= */ true);
+
+ mWmInternal.waitForAllWindowsDrawn(mScreenUnblocker,
+ /* timeout= */ Integer.MAX_VALUE, INVALID_DISPLAY);
+
+ // Perform display update
+ mUniqueId = "new_default_display_unique_id";
+ mDisplayContent.requestDisplayUpdate(mock(Runnable.class));
+
+ when(mDisplayContent.mTransitionController.inTransition()).thenReturn(true);
+
+ // Notify that transition started collecting
+ captureStartTransitionCollection().getAllValues().forEach((callback) ->
+ callback.onCollectStarted(/* deferred= */ true));
+
+ // Verify that screen is not unblocked yet
+ verify(mScreenUnblocker, never()).sendToTarget();
+
+ // Make all display windows drawn
+ defaultDisplayWindow.mWinAnimator.mDrawState = HAS_DRAWN;
+ mWm.mRoot.performSurfacePlacement();
+
+ // Verify that default display is still not unblocked yet
+ // (so it doesn't use old windows drawn path)
+ verify(mScreenUnblocker, never()).sendToTarget();
+
+ // Mark start transaction as presented
+ when(mDisplayContent.mTransitionController.inTransition()).thenReturn(false);
+ captureRequestedTransition().getAllValues().forEach(
+ this::makeTransitionTransactionCompleted);
+
+ // Verify that the default screen unblocker is sent only after start transaction
+ // of the Shell transition is presented
+ verify(mScreenUnblocker).sendToTarget();
+ }
+
private void prepareSecondaryDisplay() {
mSecondaryDisplayContent = createNewDisplay();
when(mSecondaryScreenUnblocker.getTarget()).thenReturn(mWm.mH);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index d013053..a71b81e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -90,6 +90,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.view.RemoteAnimationDefinition;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.ITaskFragmentOrganizer;
@@ -139,6 +140,7 @@
private IBinder mFragmentToken;
private WindowContainerTransaction mTransaction;
private WindowContainerToken mFragmentWindowToken;
+ private RemoteAnimationDefinition mDefinition;
private IBinder mErrorToken;
private Rect mTaskFragBounds;
@@ -167,6 +169,7 @@
mTransaction = new WindowContainerTransaction();
mTransaction.setTaskFragmentOrganizer(mIOrganizer);
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
+ mDefinition = new RemoteAnimationDefinition();
mErrorToken = new Binder();
final Rect displayBounds = mDisplayContent.getBounds();
mTaskFragBounds = new Rect(displayBounds.left, displayBounds.top, displayBounds.centerX(),
@@ -576,6 +579,17 @@
}
@Test
+ public void testRegisterRemoteAnimations() {
+ mController.registerRemoteAnimations(mIOrganizer, mDefinition);
+
+ assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
+
+ mController.unregisterRemoteAnimations(mIOrganizer);
+
+ assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
+ }
+
+ @Test
public void testApplyTransaction_disallowRemoteTransitionForNonSystemOrganizer() {
mTransaction.setRelativeBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index 808a575..1e1abf2 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -39,7 +39,10 @@
/**
* CallControl provides client side control of a call. Each Call will get an individual CallControl
- * instance in which the client can alter the state of the associated call.
+ * instance in which the client can alter the state of the associated call. Outgoing and incoming
+ * calls should move to active (via {@link CallControl#setActive(Executor, OutcomeReceiver)} or
+ * answered (via {@link CallControl#answer(int, Executor, OutcomeReceiver)} before 60 seconds. If
+ * the new call is not moved to active or answered before 60 seconds, the call will be disconnected.
*
* <p>
* Each method is Transactional meaning that it can succeed or fail. If a transaction succeeds,
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 1df6cf7..ad7d987 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2621,7 +2621,9 @@
}
/**
- * Sets state to ringing (e.g., an inbound ringing connection).
+ * Sets state to ringing (e.g., an inbound ringing connection). The Connection should not be
+ * in STATE_RINGING for more than 60 seconds. After 60 seconds, the Connection will
+ * be disconnected.
*/
public final void setRinging() {
checkImmutable();
@@ -2645,7 +2647,9 @@
}
/**
- * Sets state to dialing (e.g., dialing an outbound connection).
+ * Sets state to dialing (e.g., dialing an outbound connection). The Connection should not be
+ * in STATE_DIALING for more than 60 seconds. After 60 seconds, the Connection will
+ * be disconnected.
*/
public final void setDialing() {
checkImmutable();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index cba2eea..13bd5eb 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -10014,6 +10014,19 @@
public static final String KEY_SATELLITE_NIDD_APN_NAME_STRING =
"satellite_nidd_apn_name_string";
+ /**
+ * Default value {@code true}, meaning when an emergency call request comes in, if the device is
+ * in emergency satellite mode but hasn't sent the first satellite datagram, then exits
+ * satellite mode to allow the emergency call to go through.
+ *
+ * If {@code false}, the emergency call is always blocked if device is in emergency satellite
+ * mode. Note if device is NOT in emergency satellite mode, emergency call is always allowed.
+ *
+ * @hide
+ */
+ public static final String KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL =
+ "satellite_roaming_turn_off_session_for_emergency_call_bool";
+
/** @hide */
@IntDef({
CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC,
@@ -11276,6 +11289,7 @@
sDefaults.putBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL, false);
sDefaults.putString(KEY_SATELLITE_NIDD_APN_NAME_STRING, "");
+ sDefaults.putBoolean(KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL, true);
sDefaults.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, 0);
sDefaults.putInt(KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT,
SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7481daa..bc709ab 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -132,6 +132,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.flags.Flags;
+import com.android.internal.telephony.util.TelephonyUtils;
import com.android.telephony.Rlog;
import java.io.IOException;
@@ -9975,6 +9976,7 @@
ALLOWED_NETWORK_TYPES_REASON_POWER,
ALLOWED_NETWORK_TYPES_REASON_CARRIER,
ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G,
+ ALLOWED_NETWORK_TYPES_REASON_TEST,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AllowedNetworkTypesReason {
@@ -10013,6 +10015,14 @@
public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3;
/**
+ * To indicate allowed network type change is requested by Testing purpose, should be default to
+ * {@link #getAllNetworkTypesBitmask} when done testing.
+ *
+ * @hide
+ */
+ public static final int ALLOWED_NETWORK_TYPES_REASON_TEST = 4;
+
+ /**
* Set the allowed network types of the device and provide the reason triggering the allowed
* network change.
* <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
@@ -10118,6 +10128,8 @@
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER:
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G:
return true;
+ case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_TEST:
+ return TelephonyUtils.IS_DEBUGGABLE;
}
return false;
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index c5934a7..83fc0dc 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -592,7 +592,7 @@
() -> resultListener.accept(result)));
}
};
- telephony.requestSatelliteEnabled(mSubId, attributes.isEnabled(),
+ telephony.requestSatelliteEnabled(attributes.isEnabled(),
attributes.isDemoMode(), attributes.isEmergencyMode(), errorCallback);
} else {
Rlog.e(TAG, "requestEnabled() invalid telephony");
@@ -650,7 +650,7 @@
}
}
};
- telephony.requestIsSatelliteEnabled(mSubId, receiver);
+ telephony.requestIsSatelliteEnabled(receiver);
} else {
loge("requestIsEnabled() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
@@ -707,7 +707,7 @@
}
}
};
- telephony.requestIsDemoModeEnabled(mSubId, receiver);
+ telephony.requestIsDemoModeEnabled(receiver);
} else {
loge("requestIsDemoModeEnabled() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
@@ -764,7 +764,7 @@
}
}
};
- telephony.requestIsEmergencyModeEnabled(mSubId, receiver);
+ telephony.requestIsEmergencyModeEnabled(receiver);
} else {
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
@@ -821,7 +821,7 @@
}
}
};
- telephony.requestIsSatelliteSupported(mSubId, receiver);
+ telephony.requestIsSatelliteSupported(receiver);
} else {
loge("requestIsSupported() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
@@ -878,7 +878,7 @@
}
}
};
- telephony.requestSatelliteCapabilities(mSubId, receiver);
+ telephony.requestSatelliteCapabilities(receiver);
} else {
loge("requestCapabilities() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
@@ -1204,8 +1204,7 @@
}
};
sSatelliteTransmissionUpdateCallbackMap.put(callback, internalCallback);
- telephony.startSatelliteTransmissionUpdates(mSubId, errorCallback,
- internalCallback);
+ telephony.startSatelliteTransmissionUpdates(errorCallback, internalCallback);
} else {
loge("startTransmissionUpdates() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(
@@ -1255,8 +1254,7 @@
() -> resultListener.accept(result)));
}
};
- telephony.stopSatelliteTransmissionUpdates(mSubId, errorCallback,
- internalCallback);
+ telephony.stopSatelliteTransmissionUpdates(errorCallback, internalCallback);
// TODO: Notify SmsHandler that pointing UI stopped
} else {
loge("stopSatelliteTransmissionUpdates: No internal callback.");
@@ -1312,7 +1310,7 @@
() -> resultListener.accept(result)));
}
};
- cancelRemote = telephony.provisionSatelliteService(mSubId, token, provisionData,
+ cancelRemote = telephony.provisionSatelliteService(token, provisionData,
errorCallback);
} else {
loge("provisionService() invalid telephony");
@@ -1364,7 +1362,7 @@
() -> resultListener.accept(result)));
}
};
- telephony.deprovisionSatelliteService(mSubId, token, errorCallback);
+ telephony.deprovisionSatelliteService(token, errorCallback);
} else {
loge("deprovisionService() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(
@@ -1419,8 +1417,7 @@
}
};
sSatelliteProvisionStateCallbackMap.put(callback, internalCallback);
- return telephony.registerForSatelliteProvisionStateChanged(
- mSubId, internalCallback);
+ return telephony.registerForSatelliteProvisionStateChanged(internalCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -1453,7 +1450,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForSatelliteProvisionStateChanged(mSubId, internalCallback);
+ telephony.unregisterForSatelliteProvisionStateChanged(internalCallback);
} else {
loge("unregisterForProvisionStateChanged: No internal callback.");
}
@@ -1510,7 +1507,7 @@
}
}
};
- telephony.requestIsSatelliteProvisioned(mSubId, receiver);
+ telephony.requestIsSatelliteProvisioned(receiver);
} else {
loge("requestIsProvisioned() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
@@ -1560,7 +1557,7 @@
}
};
sSatelliteModemStateCallbackMap.put(callback, internalCallback);
- return telephony.registerForSatelliteModemStateChanged(mSubId, internalCallback);
+ return telephony.registerForSatelliteModemStateChanged(internalCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -1593,7 +1590,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForModemStateChanged(mSubId, internalCallback);
+ telephony.unregisterForModemStateChanged(internalCallback);
} else {
loge("unregisterForModemStateChanged: No internal callback.");
}
@@ -1656,7 +1653,7 @@
}
};
sSatelliteDatagramCallbackMap.put(callback, internalCallback);
- return telephony.registerForIncomingDatagram(mSubId, internalCallback);
+ return telephony.registerForIncomingDatagram(internalCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -1688,7 +1685,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForIncomingDatagram(mSubId, internalCallback);
+ telephony.unregisterForIncomingDatagram(internalCallback);
} else {
loge("unregisterForIncomingDatagram: No internal callback.");
}
@@ -1732,7 +1729,7 @@
() -> resultListener.accept(result)));
}
};
- telephony.pollPendingDatagrams(mSubId, internalCallback);
+ telephony.pollPendingDatagrams(internalCallback);
} else {
loge("pollPendingDatagrams() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(
@@ -1790,7 +1787,7 @@
() -> resultListener.accept(result)));
}
};
- telephony.sendDatagram(mSubId, datagramType, datagram,
+ telephony.sendDatagram(datagramType, datagram,
needFullScreenPointingUI, internalCallback);
} else {
loge("sendDatagram() invalid telephony");
@@ -1908,7 +1905,7 @@
}
}
};
- telephony.requestTimeForNextSatelliteVisibility(mSubId, receiver);
+ telephony.requestTimeForNextSatelliteVisibility(receiver);
} else {
loge("requestTimeForNextSatelliteVisibility() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
@@ -1939,7 +1936,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- telephony.setDeviceAlignedWithSatellite(mSubId, isAligned);
+ telephony.setDeviceAlignedWithSatellite(isAligned);
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -2203,7 +2200,7 @@
}
}
};
- telephony.requestNtnSignalStrength(mSubId, receiver);
+ telephony.requestNtnSignalStrength(receiver);
} else {
loge("requestNtnSignalStrength() invalid telephony");
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
@@ -2254,7 +2251,7 @@
ntnSignalStrength)));
}
};
- telephony.registerForNtnSignalStrengthChanged(mSubId, internalCallback);
+ telephony.registerForNtnSignalStrengthChanged(internalCallback);
sNtnSignalStrengthCallbackMap.put(callback, internalCallback);
} else {
throw new IllegalStateException("Telephony service is null.");
@@ -2294,7 +2291,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForNtnSignalStrengthChanged(mSubId, internalCallback);
+ telephony.unregisterForNtnSignalStrengthChanged(internalCallback);
} else {
loge("unregisterForNtnSignalStrengthChanged: No internal callback.");
throw new IllegalArgumentException("callback is not valid");
@@ -2339,7 +2336,7 @@
}
};
sSatelliteCapabilitiesCallbackMap.put(callback, internalCallback);
- return telephony.registerForCapabilitiesChanged(mSubId, internalCallback);
+ return telephony.registerForCapabilitiesChanged(internalCallback);
} else {
throw new IllegalStateException("Telephony service is null.");
}
@@ -2372,7 +2369,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForCapabilitiesChanged(mSubId, internalCallback);
+ telephony.unregisterForCapabilitiesChanged(internalCallback);
} else {
loge("unregisterForCapabilitiesChanged: No internal callback.");
}
@@ -2448,7 +2445,7 @@
};
sSatelliteSupportedStateCallbackMap.put(callback, internalCallback);
return telephony.registerForSatelliteSupportedStateChanged(
- mSubId, internalCallback);
+ internalCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -2483,7 +2480,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForSatelliteSupportedStateChanged(mSubId, internalCallback);
+ telephony.unregisterForSatelliteSupportedStateChanged(internalCallback);
} else {
loge("unregisterForSupportedStateChanged: No internal callback.");
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 0c5f30f..e852e6b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2743,7 +2743,6 @@
/**
* Request to enable or disable the satellite modem.
*
- * @param subId The subId of the subscription to enable or disable the satellite modem for.
* @param enableSatellite True to enable the satellite modem and false to disable.
* @param enableDemoMode True if demo mode is enabled and false otherwise. When
* disabling satellite, {@code enableDemoMode} is always considered as
@@ -2755,93 +2754,83 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode,
+ void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
boolean isEmergency, in IIntegerConsumer callback);
/**
* Request to get whether the satellite modem is enabled.
*
- * @param subId The subId of the subscription to request whether satellite is enabled for.
* @param receiver Result receiver to get the error code of the request and whether the
* satellite modem is enabled.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestIsSatelliteEnabled(int subId, in ResultReceiver receiver);
+ void requestIsSatelliteEnabled(in ResultReceiver receiver);
/**
* Request to get whether the satellite service demo mode is enabled.
*
- * @param subId The subId of the subscription to request whether the satellite demo mode is
- * enabled for.
* @param receiver Result receiver to get the error code of the request and whether the
* satellite demo mode is enabled.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestIsDemoModeEnabled(int subId, in ResultReceiver receiver);
+ void requestIsDemoModeEnabled(in ResultReceiver receiver);
/**
* Request to get whether the satellite service is enabled with emergency mode.
*
- * @param subId The subId of the subscription to request whether the satellite demo mode is
- * enabled for.
* @param receiver Result receiver to get the error code of the request and whether the
* satellite is enabled with emergency mode.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestIsEmergencyModeEnabled(int subId, in ResultReceiver receiver);
+ void requestIsEmergencyModeEnabled(in ResultReceiver receiver);
/**
* Request to get whether the satellite service is supported on the device.
*
- * @param subId The subId of the subscription to check whether satellite is supported for.
* @param receiver Result receiver to get the error code of the request and whether the
* satellite service is supported on the device.
*/
- void requestIsSatelliteSupported(int subId, in ResultReceiver receiver);
+ void requestIsSatelliteSupported(in ResultReceiver receiver);
/**
* Request to get the capabilities of the satellite service.
*
- * @param subId The subId of the subscription to get the capabilities for.
* @param receiver Result receiver to get the error code of the request and the requested
* capabilities of the satellite service.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestSatelliteCapabilities(int subId, in ResultReceiver receiver);
+ void requestSatelliteCapabilities(in ResultReceiver receiver);
/**
* Start receiving satellite transmission updates.
*
- * @param subId The subId of the subscription to stop satellite transmission updates for.
* @param resultCallback The callback to get the result of the request.
* @param callback The callback to handle transmission updates.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void startSatelliteTransmissionUpdates(int subId, in IIntegerConsumer resultCallback,
+ void startSatelliteTransmissionUpdates(in IIntegerConsumer resultCallback,
in ISatelliteTransmissionUpdateCallback callback);
/**
* Stop receiving satellite transmission updates.
*
- * @param subId The subId of the subscritpion to stop satellite transmission updates for.
* @param resultCallback The callback to get the result of the request.
* @param callback The callback that was passed to startSatelliteTransmissionUpdates.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void stopSatelliteTransmissionUpdates(int subId, in IIntegerConsumer resultCallback,
+ void stopSatelliteTransmissionUpdates(in IIntegerConsumer resultCallback,
in ISatelliteTransmissionUpdateCallback callback);
/**
* Register the subscription with a satellite provider.
* This is needed to register the subscription if the provider allows dynamic registration.
*
- * @param subId The subId of the subscription to be provisioned.
* @param token The token to be used as a unique identifier for provisioning with satellite
* gateway.
* @provisionData Data from the provisioning app that can be used by provisioning server
@@ -2851,7 +2840,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- ICancellationSignal provisionSatelliteService(int subId, in String token,
+ ICancellationSignal provisionSatelliteService(in String token,
in byte[] provisionData, in IIntegerConsumer callback);
/**
@@ -2861,110 +2850,99 @@
* {@link SatelliteCallback.SatelliteProvisionStateListener#onSatelliteProvisionStateChanged}
* should report as deprovisioned.
*
- * @param subId The subId of the subscription to be deprovisioned.
* @param token The token of the device/subscription to be deprovisioned.
* @param callback The callback to get the result of the request.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void deprovisionSatelliteService(int subId, in String token, in IIntegerConsumer callback);
+ void deprovisionSatelliteService(in String token, in IIntegerConsumer callback);
/**
* Registers for provision state changed from satellite modem.
*
- * @param subId The subId of the subscription to register for provision state changed.
* @param callback The callback to handle the satellite provision state changed event.
*
* @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForSatelliteProvisionStateChanged(int subId,
- in ISatelliteProvisionStateCallback callback);
+ int registerForSatelliteProvisionStateChanged(in ISatelliteProvisionStateCallback callback);
/**
* Unregisters for provision state changed from satellite modem.
* If callback was not registered before, the request will be ignored.
*
- * @param subId The subId of the subscription to unregister for provision state changed.
* @param callback The callback that was passed to registerForSatelliteProvisionStateChanged.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForSatelliteProvisionStateChanged(int subId,
+ void unregisterForSatelliteProvisionStateChanged(
in ISatelliteProvisionStateCallback callback);
/**
* Request to get whether the device is provisioned with a satellite provider.
*
- * @param subId The subId of the subscription to get whether the device is provisioned for.
* @param receiver Result receiver to get the error code of the request and whether the
* device is provisioned with a satellite provider.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestIsSatelliteProvisioned(int subId, in ResultReceiver receiver);
+ void requestIsSatelliteProvisioned(in ResultReceiver receiver);
/**
* Registers for modem state changed from satellite modem.
*
- * @param subId The subId of the subscription to register for satellite modem state changed.
* @param callback The callback to handle the satellite modem state changed event.
*
* @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForSatelliteModemStateChanged(int subId, ISatelliteModemStateCallback callback);
+ int registerForSatelliteModemStateChanged(ISatelliteModemStateCallback callback);
/**
* Unregisters for modem state changed from satellite modem.
* If callback was not registered before, the request will be ignored.
*
- * @param subId The subId of the subscription to unregister for satellite modem state changed.
* @param callback The callback that was passed to registerForSatelliteStateChanged.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForModemStateChanged(int subId, ISatelliteModemStateCallback callback);
+ void unregisterForModemStateChanged(ISatelliteModemStateCallback callback);
/**
* Register to receive incoming datagrams over satellite.
*
- * @param subId The subId of the subscription to register for incoming satellite datagrams.
* @param callback The callback to handle the incoming datagrams.
*
* @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForIncomingDatagram(int subId, ISatelliteDatagramCallback callback);
+ int registerForIncomingDatagram(ISatelliteDatagramCallback callback);
/**
* Unregister to stop receiving incoming datagrams over satellite.
* If callback was not registered before, the request will be ignored.
*
- * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
* @param callback The callback that was passed to registerForIncomingDatagram.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForIncomingDatagram(int subId, ISatelliteDatagramCallback callback);
+ void unregisterForIncomingDatagram(ISatelliteDatagramCallback callback);
/**
* Poll pending satellite datagrams over satellite.
*
- * @param subId The subId of the subscription used for receiving datagrams.
* @param callback The callback to get the result of the request.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void pollPendingDatagrams(int subId, IIntegerConsumer callback);
+ void pollPendingDatagrams(IIntegerConsumer callback);
/**
* Send datagram over satellite.
*
- * @param subId The subId of the subscription to send satellite datagrams for.
* @param datagramType Type of datagram.
* @param datagram Datagram to send over satellite.
* @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
@@ -2973,7 +2951,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void sendDatagram(int subId, int datagramType, in SatelliteDatagram datagram,
+ void sendDatagram(int datagramType, in SatelliteDatagram datagram,
in boolean needFullScreenPointingUI, IIntegerConsumer callback);
/**
@@ -2991,13 +2969,12 @@
/**
* Request to get the time after which the satellite will be visible.
*
- * @param subId The subId to get the time after which the satellite will be visible for.
* @param receiver Result receiver to get the error code of the request and the requested
* time after which the satellite will be visible.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestTimeForNextSatelliteVisibility(int subId, in ResultReceiver receiver);
+ void requestTimeForNextSatelliteVisibility(in ResultReceiver receiver);
/**
* Inform whether the device is aligned with the satellite within in margin for demo mode.
@@ -3007,7 +2984,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void setDeviceAlignedWithSatellite(int subId, boolean isAligned);
+ void setDeviceAlignedWithSatellite(boolean isAligned);
/**
* This API can be used by only CTS to update satellite vendor service package name.
@@ -3163,20 +3140,18 @@
/**
* Request to get the signal strength of the satellite connection.
*
- * @param subId The subId of the subscription to request for.
* @param receiver Result receiver to get the error code of the request and the current signal
* strength of the satellite connection.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestNtnSignalStrength(int subId, in ResultReceiver receiver);
+ void requestNtnSignalStrength(in ResultReceiver receiver);
/**
* Registers for NTN signal strength changed from satellite modem. If the registration operation
* is not successful, a {@link SatelliteException} that contains {@link SatelliteResult} will be
* thrown.
*
- * @param subId The subId of the subscription to request for.
* @param callback The callback to handle the NTN signal strength changed event. If the
* operation is successful, {@link NtnSignalStrengthCallback#onNtnSignalStrengthChanged(
* NtnSignalStrength)} will return an instance of {@link NtnSignalStrength} with a value of
@@ -3185,30 +3160,27 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void registerForNtnSignalStrengthChanged(int subId,
- in INtnSignalStrengthCallback callback);
+ void registerForNtnSignalStrengthChanged(in INtnSignalStrengthCallback callback);
/**
* Unregisters for NTN signal strength changed from satellite modem.
* If callback was not registered before, the request will be ignored.
*
- * @param subId The subId of the subscription to unregister for provision state changed.
* @param callback The callback that was passed to
* {@link #registerForNtnSignalStrengthChanged(Executor, NtnSignalStrengthCallback)}.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForNtnSignalStrengthChanged(int subId, in INtnSignalStrengthCallback callback);
+ void unregisterForNtnSignalStrengthChanged(in INtnSignalStrengthCallback callback);
/**
* Registers for satellite capabilities change event from the satellite service.
*
- * @param executor The executor on which the callback will be called.
* @param callback The callback to handle the satellite capabilities changed event.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForCapabilitiesChanged(int subId, in ISatelliteCapabilitiesCallback callback);
+ int registerForCapabilitiesChanged(in ISatelliteCapabilitiesCallback callback);
/**
* Unregisters for satellite capabilities change event from the satellite service.
@@ -3219,8 +3191,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForCapabilitiesChanged(int subId,
- in ISatelliteCapabilitiesCallback callback);
+ void unregisterForCapabilitiesChanged(in ISatelliteCapabilitiesCallback callback);
/**
* This API can be used by only CTS to override the cached value for the device overlay config
@@ -3329,26 +3300,24 @@
/**
* Registers for supported state changed from satellite modem.
*
- * @param subId The subId of the subscription to register for supported state changed.
* @param callback The callback to handle the satellite supported state changed event.
*
* @return The {@link SatelliteError} result of the operation.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForSatelliteSupportedStateChanged(int subId,
+ int registerForSatelliteSupportedStateChanged(
in ISatelliteSupportedStateCallback callback);
/**
* Unregisters for supported state changed from satellite modem.
* If callback was not registered before, the request will be ignored.
*
- * @param subId The subId of the subscription to unregister for supported state changed.
* @param callback The callback that was passed to registerForSatelliteSupportedStateChanged.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForSatelliteSupportedStateChanged(int subId,
+ void unregisterForSatelliteSupportedStateChanged(
in ISatelliteSupportedStateCallback callback);
/**
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index 379b45c..c3e1a1f 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -24,6 +24,7 @@
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.traces.parsers.toFlickerComponent
+import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -177,6 +178,13 @@
@Ignore("Not applicable to this CUJ.")
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {}
+ @FlakyTest(bugId = 342596801)
+ override fun entireScreenCovered() = super.entireScreenCovered()
+
+ @FlakyTest(bugId = 342596801)
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
/** {@inheritDoc} */
private var startDisplayBounds = Rect()
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index adeba72..6e6a327 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -196,7 +196,7 @@
super.appLayerBecomesVisible()
}
- @Presubmit
+ @FlakyTest(bugId = 338296297)
@Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
diff --git a/tests/Input/assets/testPointerFillStyle.png b/tests/Input/assets/testPointerFillStyle.png
index b2354f8..297244f 100644
--- a/tests/Input/assets/testPointerFillStyle.png
+++ b/tests/Input/assets/testPointerFillStyle.png
Binary files differ
diff --git a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
index d97dd7c..5c5421a 100755
--- a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
+++ b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
@@ -213,9 +213,9 @@
"
run_hoststubgen_for_failure "One specific class disallowed" \
- "TinyFrameworkClassAnnotations is not allowed to have Ravenwood annotations" \
+ "TinyFrameworkAnnotations is not allowed to have Ravenwood annotations" \
"
-!com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+!com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
* # All other classes allowed
"
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
index 6cf2143..7dd4fdd 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -202,18 +202,6 @@
}
/**
- * Take a class name. If it's a nested class, then return the name of its direct outer class name.
- * Otherwise, return null.
- */
-fun getDirectOuterClassName(className: String): String? {
- val pos = className.lastIndexOf('$')
- if (pos < 0) {
- return null
- }
- return className.substring(0, pos)
-}
-
-/**
* Write bytecode to push all the method arguments to the stack.
* The number of arguments and their type are taken from [methodDescriptor].
*/
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
index 47790b1..37048d9 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
@@ -16,7 +16,6 @@
package com.android.hoststubgen.filters
import com.android.hoststubgen.asm.ClassNodes
-import com.android.hoststubgen.asm.getDirectOuterClassName
/**
* This is used as the second last fallback filter. This filter propagates the class-wide policy
@@ -24,72 +23,69 @@
*/
class ClassWidePolicyPropagatingFilter(
private val classes: ClassNodes,
- fallback: OutputFilter,
- ) : DelegatingFilter(fallback) {
+ fallback: OutputFilter
+) : DelegatingFilter(fallback) {
- private fun getClassWidePolicy(className: String, resolve: Boolean): FilterPolicyWithReason? {
+ /**
+ * We don't use ClassNode.outerClass, because it gives as the top-level
+ * outer class (A$B$C -> A), not the direct outer class (A$B$C -> A$B).
+ *
+ * Sometimes a class name includes `$`, but is not as a nested class name separator
+ * (e.g. a class name like `MyClass$$`). In this case, `MyClass$` is not actually a class.
+ *
+ * So before getting the class policy on a nonexistent class, which may cause an
+ * incorrect result, we make sure the class actually exists.
+ */
+ private fun getDirectOuterClass(className: String): String? {
var currentClass = className
-
-
- // If the class name is `a.b.c.A$B$C`, then we try to get the class wide policy
- // from a.b.c.A$B$C, then a.b.c.A$B, and then a.b.c.A.
while (true) {
- // Sometimes a class name has a `$` in it but not as a nest class name separator --
- // e.g. class name like "MyClass$$". In this case, `MyClass$` may not actually be
- // a class name.
- // So before getting the class policy on a nonexistent class, which may cause an
- // incorrect result, we make sure if className actually exists.
- if (classes.hasClass(className)) {
- outermostFilter.getPolicyForClass(className).let { policy ->
- if (policy.policy.isClassWidePolicy) {
- val p = if (resolve) {
- policy.policy.resolveClassWidePolicy()
- } else {
- policy.policy
- }
-
- return p.withReason(policy.reason)
- .wrapReason("class-wide in $currentClass")
- }
- // If the class's policy is remove, then remove it.
- if (policy.policy == FilterPolicy.Remove) {
- return FilterPolicy.Remove.withReason("class-wide in $currentClass")
- }
- }
- }
-
- // Next, look at the outer class...
- val outer = getDirectOuterClassName(currentClass)
- if (outer == null) {
+ val pos = currentClass.lastIndexOf('$')
+ if (pos < 0) {
return null
}
- currentClass = outer
+ currentClass = currentClass.substring(0, pos)
+ if (classes.hasClass(currentClass)) {
+ return currentClass
+ }
}
}
+ private fun getClassWidePolicy(className: String, resolve: Boolean): FilterPolicyWithReason? {
+ outermostFilter.getPolicyForClass(className).let { policy ->
+ if (policy.policy.isClassWidePolicy) {
+ val p = if (resolve) {
+ policy.policy.resolveClassWidePolicy()
+ } else {
+ policy.policy
+ }
+
+ return p.withReason(policy.reason)
+ .wrapReason("class-wide in $className")
+ }
+ // If the class's policy is remove, then remove it.
+ if (policy.policy == FilterPolicy.Remove) {
+ return FilterPolicy.Remove.withReason("class-wide in $className")
+ }
+ }
+ return null
+ }
+
override fun getPolicyForClass(className: String): FilterPolicyWithReason {
- // If it's a nested class, use the outer class's policy.
- getDirectOuterClassName(className)?.let { outerName ->
- getClassWidePolicy(outerName, resolve = false)?.let { policy ->
- return policy
- }
- }
-
- return super.getPolicyForClass(className)
+ // If the class name is `a.b.c.A$B$C`, then we try to get the class wide policy
+ // from a.b.c.A$B$C, then a.b.c.A$B, and then a.b.c.A, recursively
+ return getDirectOuterClass(className)?.let { getClassWidePolicy(it, resolve = false) }
+ ?: super.getPolicyForClass(className)
}
- override fun getPolicyForField(
- className: String,
- fieldName: String
- ): FilterPolicyWithReason {
+ override fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason {
return getClassWidePolicy(className, resolve = true)
?: super.getPolicyForField(className, fieldName)
}
override fun getPolicyForMethod(
- className: String,
- methodName: String,
- descriptor: String
+ className: String,
+ methodName: String,
+ descriptor: String
): FilterPolicyWithReason {
return getClassWidePolicy(className, resolve = true)
?: super.getPolicyForMethod(className, methodName, descriptor)
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
index bd9e85e..de4cb0c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt
@@ -6,10 +6,10 @@
# To allow a specific class to use annotations:
-# com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+# com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
# To disallow a specific class to use annotations:
-# !com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+# !com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
# To allow a specific package to use annotations:
# com.android.hoststubgen.test.*
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index c2f593c..845e1d0 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -394,6 +394,211 @@
com/android/hoststubgen/test/tinyframework/R$Nested
InnerClasses:
public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 3, methods: 10, attributes: 2
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int remove;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 6 1 value I
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOneInner(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 4 1 value I
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public void toBeRemoved(java.lang.String);
+ descriptor: (Ljava/lang/String;)V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 8 1 foo Ljava/lang/String;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRemove
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 10 1 value I
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestSubstitute(
+ suffix="_host"
+ )
+
+ public int addTwo_host(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 4 1 value I
+
+ public static native int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestSubstitute(
+ suffix="_host"
+ )
+
+ private static int nativeAddThree_host(int);
+ descriptor: (I)I
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 value I
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
@@ -492,388 +697,6 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
InnerClasses:
private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
- Compiled from "TinyFrameworkClassAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 3, methods: 10, attributes: 2
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
-
- public int remove;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=1, args_size=1
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: aload_0
- x: iconst_1
- x: putfield #x // Field stub:I
- x: aload_0
- x: iconst_2
- x: putfield #x // Field keep:I
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: aload_0
- x: iload_1
- x: invokevirtual #x // Method addOneInner:(I)I
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 0 6 1 value I
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: iload_1
- x: iconst_1
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 0 4 1 value I
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
-
- public void toBeRemoved(java.lang.String);
- descriptor: (Ljava/lang/String;)V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- x: athrow
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 0 8 1 foo Ljava/lang/String;
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestRemove
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String not supported on host side
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 0 10 1 value I
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestSubstitute(
- suffix="_host"
- )
-
- public int addTwo_host(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: iload_1
- x: iconst_2
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 0 4 1 value I
-
- public static native int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestSubstitute(
- suffix="_host"
- )
-
- private static int nativeAddThree_host(int);
- descriptor: (I)I
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=1, args_size=1
- x: iload_0
- x: iconst_3
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 value I
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: ldc #x // String This value shouldn\'t be seen on the host side.
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestThrow
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: aload_0
- x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-}
-SourceFile: "TinyFrameworkClassAnnotations.java"
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestClassLoadHook(
- value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
- )
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
- Compiled from "TinyFrameworkClassClassWideAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 3, methods: 10, attributes: 2
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
-
- public int remove;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=1, args_size=1
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: aload_0
- x: iconst_1
- x: putfield #x // Field stub:I
- x: aload_0
- x: iconst_2
- x: putfield #x // Field keep:I
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: aload_0
- x: iload_1
- x: invokevirtual #x // Method addOneInner:(I)I
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 6 1 value I
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: iload_1
- x: iconst_1
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 4 1 value I
-
- public void toBeRemoved(java.lang.String);
- descriptor: (Ljava/lang/String;)V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- x: athrow
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 8 1 foo Ljava/lang/String;
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String not supported on host side
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 10 1 value I
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestSubstitute(
- suffix="_host"
- )
-
- public int addTwo_host(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: iload_1
- x: iconst_2
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 4 1 value I
-
- public static native int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestSubstitute(
- suffix="_host"
- )
-
- public static int nativeAddThree_host(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=1, args_size=1
- x: iload_0
- x: iconst_3
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 value I
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: ldc #x // String This value shouldn\'t be seen on the host side.
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: aload_0
- x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
-}
-SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
@@ -936,6 +759,118 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 6, attributes: 2
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 10 1 value I
+ RuntimeInvisibleAnnotations:
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestSubstitute(
+ suffix="_host"
+ )
+
+ public int addTwo_host(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
Compiled from "TinyFrameworkClassWithInitializerDefault.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
@@ -2684,7 +2619,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 1, attributes: 4
+ interfaces: 0, fields: 2, methods: 1, attributes: 3
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -2717,9 +2652,6 @@
<no name> final mandated
}
SourceFile: "TinyFrameworkNestedClasses.java"
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
@@ -2778,6 +2710,40 @@
InnerClasses:
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 3
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 8
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
Compiled from "TinyFrameworkNestedClasses.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
@@ -2786,7 +2752,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 2, attributes: 4
+ interfaces: 0, fields: 1, methods: 2, attributes: 3
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -2820,13 +2786,11 @@
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
}
SourceFile: "TinyFrameworkNestedClasses.java"
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
InnerClasses:
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
Compiled from "TinyFrameworkNestedClasses.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
@@ -2942,6 +2906,7 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
@@ -2957,6 +2922,7 @@
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect.class
Compiled from "TinyFrameworkPackageRedirect.java"
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 1b83d24..86a9c65 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -216,6 +216,129 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestMembers:
com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 5, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
@@ -339,302 +462,6 @@
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
- Compiled from "TinyFrameworkClassAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 5, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-}
-SourceFile: "TinyFrameworkClassAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestClassLoadHook(
- value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
- )
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
- Compiled from "TinyFrameworkClassClassWideAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 3, methods: 8, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int remove;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public void toBeRemoved(java.lang.String);
- descriptor: (Ljava/lang/String;)V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-}
-SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
@@ -712,6 +539,97 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 4, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
Compiled from "TinyFrameworkClassWithInitializerDefault.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
@@ -2153,7 +2071,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 1, attributes: 5
+ interfaces: 0, fields: 2, methods: 1, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -2199,9 +2117,50 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -2211,7 +2170,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 2, attributes: 5
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -2257,15 +2216,13 @@
InnerClasses:
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -2406,6 +2363,7 @@
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
@@ -2420,6 +2378,7 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index d23b450..c6b9c7a 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -450,6 +450,227 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestMembers:
com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 6 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOneInner(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String addOneInner
+ x: ldc #x // String (I)I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 15 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 15 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
@@ -592,434 +813,6 @@
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
- Compiled from "TinyFrameworkClassAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 8, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
-
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=1, args_size=1
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: aload_0
- x: iconst_1
- x: putfield #x // Field stub:I
- x: aload_0
- x: iconst_2
- x: putfield #x // Field keep:I
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: aload_0
- x: iload_1
- x: invokevirtual #x // Method addOneInner:(I)I
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 0 6 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String addOneInner
- x: ldc #x // String (I)I
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- x: iload_1
- x: iconst_1
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 15 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 15 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: iload_1
- x: iconst_2
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 0 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=1, args_size=1
- x: iload_0
- x: iconst_3
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String unsupportedMethod
- x: ldc #x // String ()Ljava/lang/String;
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Unreachable
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestThrow
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: aload_0
- x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-}
-SourceFile: "TinyFrameworkClassAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestClassLoadHook(
- value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
- )
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
- Compiled from "TinyFrameworkClassClassWideAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 3, methods: 8, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int remove;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=1, args_size=1
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: aload_0
- x: iconst_1
- x: putfield #x // Field stub:I
- x: aload_0
- x: iconst_2
- x: putfield #x // Field keep:I
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: aload_0
- x: iload_1
- x: invokevirtual #x // Method addOneInner:(I)I
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 6 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: iload_1
- x: iconst_1
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public void toBeRemoved(java.lang.String);
- descriptor: (Ljava/lang/String;)V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- x: athrow
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 8 1 foo Ljava/lang/String;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- x: iload_1
- x: iconst_2
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 0 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=2, locals=1, args_size=1
- x: iload_0
- x: iconst_3
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 4 0 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: ldc #x // String This value shouldn\'t be seen on the host side.
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- x: aload_0
- x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-}
-SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
@@ -1107,6 +900,140 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 5, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=2, args_size=2
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 0 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
Compiled from "TinyFrameworkClassWithInitializerDefault.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
@@ -3430,7 +3357,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 1, attributes: 5
+ interfaces: 0, fields: 2, methods: 1, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3485,9 +3412,6 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -3568,6 +3492,55 @@
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 8
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
Compiled from "TinyFrameworkNestedClasses.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
@@ -3576,7 +3549,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 2, attributes: 5
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -3627,15 +3600,13 @@
InnerClasses:
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -3793,6 +3764,7 @@
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
@@ -3807,6 +3779,7 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
index 1b83d24..86a9c65 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -216,6 +216,129 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestMembers:
com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 5, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
@@ -339,302 +462,6 @@
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
- Compiled from "TinyFrameworkClassAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 5, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-}
-SourceFile: "TinyFrameworkClassAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestClassLoadHook(
- value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
- )
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
- Compiled from "TinyFrameworkClassClassWideAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 3, methods: 8, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int remove;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public void toBeRemoved(java.lang.String);
- descriptor: (Ljava/lang/String;)V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=2, args_size=2
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=3, locals=1, args_size=1
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Stub!
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-}
-SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
@@ -712,6 +539,97 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 4, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=2, args_size=2
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
Compiled from "TinyFrameworkClassWithInitializerDefault.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
@@ -2153,7 +2071,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 1, attributes: 5
+ interfaces: 0, fields: 2, methods: 1, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -2199,9 +2117,50 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 1, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=3, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -2211,7 +2170,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 2, attributes: 5
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -2257,15 +2216,13 @@
InnerClasses:
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -2406,6 +2363,7 @@
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
@@ -2420,6 +2378,7 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
index d12a23d..da434a6 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -611,6 +611,265 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestMembers:
com/android/hoststubgen/test/tinyframework/R$Nested
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.class
+ Compiled from "TinyFrameworkAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 2, methods: 8, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int keep;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String addOne
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 11 6 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+
+ public int addOneInner(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String addOneInner
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String addOneInner
+ x: ldc #x // String (I)I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 26 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 26 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestKeep
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String addTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public static int nativeAddThree(int);
+ descriptor: (I)I
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String nativeAddThree
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations
+ x: ldc #x // String visibleButUsesUnsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestStub
+ x: #x(#x=s#x)
+ android.hosttest.annotation.HostSideTestClassLoadHook(
+ value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+ )
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
@@ -803,522 +1062,6 @@
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
- Compiled from "TinyFrameworkClassAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 8, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
-
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String <init>
- x: ldc #x // String ()V
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: aload_0
- x: iconst_1
- x: putfield #x // Field stub:I
- x: aload_0
- x: iconst_2
- x: putfield #x // Field keep:I
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String addOne
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: aload_0
- x: iload_1
- x: invokevirtual #x // Method addOneInner:(I)I
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 11 6 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String addOneInner
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String addOneInner
- x: ldc #x // String (I)I
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- x: iload_1
- x: iconst_1
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 26 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 26 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String addTwo
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: iload_1
- x: iconst_2
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- 11 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String nativeAddThree
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: iload_0
- x: iconst_3
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 4 0 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String unsupportedMethod
- x: ldc #x // String ()Ljava/lang/String;
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String unsupportedMethod
- x: ldc #x // String ()Ljava/lang/String;
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: ldc #x // String Unreachable
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- x: athrow
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestThrow
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- x: ldc #x // String visibleButUsesUnsupportedMethod
- x: ldc #x // String ()Ljava/lang/String;
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: aload_0
- x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
-}
-SourceFile: "TinyFrameworkClassAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestStub
- x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestClassLoadHook(
- value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
- )
-## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
- Compiled from "TinyFrameworkClassClassWideAnnotations.java"
-public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
- minor version: 0
- major version: 61
- flags: (0x0021) ACC_PUBLIC, ACC_SUPER
- this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- super_class: #x // java/lang/Object
- interfaces: 0, fields: 3, methods: 9, attributes: 3
- public int stub;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int keep;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int remove;
- descriptor: I
- flags: (0x0001) ACC_PUBLIC
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- private static {};
- descriptor: ()V
- flags: (0x000a) ACC_PRIVATE, ACC_STATIC
- Code:
- stack=2, locals=0, args_size=0
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- x: return
-
- public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
- descriptor: ()V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String <init>
- x: ldc #x // String ()V
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: aload_0
- x: invokespecial #x // Method java/lang/Object."<init>":()V
- x: aload_0
- x: iconst_1
- x: putfield #x // Field stub:I
- x: aload_0
- x: iconst_2
- x: putfield #x // Field keep:I
- x: return
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOne(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String addOne
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: aload_0
- x: iload_1
- x: invokevirtual #x // Method addOneInner:(I)I
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 11 6 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addOneInner(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String addOneInner
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: iload_1
- x: iconst_1
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 11 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public void toBeRemoved(java.lang.String);
- descriptor: (Ljava/lang/String;)V
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String toBeRemoved
- x: ldc #x // String (Ljava/lang/String;)V
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: new #x // class java/lang/RuntimeException
- x: dup
- x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- x: athrow
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 11 8 1 foo Ljava/lang/String;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public int addTwo(int);
- descriptor: (I)I
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=2, args_size=2
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String addTwo
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: iload_1
- x: iconst_2
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- 11 4 1 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public static int nativeAddThree(int);
- descriptor: (I)I
- flags: (0x0009) ACC_PUBLIC, ACC_STATIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String nativeAddThree
- x: ldc #x // String (I)I
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: iload_0
- x: iconst_3
- x: iadd
- x: ireturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 4 0 value I
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String unsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String unsupportedMethod
- x: ldc #x // String ()Ljava/lang/String;
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: ldc #x // String This value shouldn\'t be seen on the host side.
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-
- public java.lang.String visibleButUsesUnsupportedMethod();
- descriptor: ()Ljava/lang/String;
- flags: (0x0001) ACC_PUBLIC
- Code:
- stack=4, locals=1, args_size=1
- x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
- x: ldc #x // String visibleButUsesUnsupportedMethod
- x: ldc #x // String ()Ljava/lang/String;
- x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
- x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
- x: aload_0
- x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- x: areturn
- LineNumberTable:
- LocalVariableTable:
- Start Length Slot Name Signature
- 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
- RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-}
-SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
-RuntimeVisibleAnnotations:
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
- x: #x()
- com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
@@ -1424,6 +1167,175 @@
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.class
+ Compiled from "TinyFrameworkClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 6, attributes: 3
+ public int stub;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAnnotations();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addOne(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String addOne
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public int addTwo(int);
+ descriptor: (I)I
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=2, args_size=2
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String addTwo
+ x: ldc #x // String (I)I
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ 11 4 1 value I
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ public java.lang.String unsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestThrow
+
+ public java.lang.String visibleButUsesUnsupportedMethod();
+ descriptor: ()Ljava/lang/String;
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations
+ x: ldc #x // String visibleButUsesUnsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+SourceFile: "TinyFrameworkClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault.class
Compiled from "TinyFrameworkClassWithInitializerDefault.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializerDefault
@@ -4280,7 +4192,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 2, methods: 2, attributes: 5
+ interfaces: 0, fields: 2, methods: 2, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -4350,9 +4262,6 @@
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -4458,6 +4367,70 @@
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass.class
+ Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ minor version: 0
+ major version: 61
+ flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+ this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ super_class: #x // java/lang/Object
+ interfaces: 0, fields: 1, methods: 2, attributes: 4
+ public int value;
+ descriptor: I
+ flags: (0x0001) ACC_PUBLIC
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+
+ public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 8
+ x: putfield #x // Field value:I
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+}
+InnerClasses:
+ public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
Compiled from "TinyFrameworkNestedClasses.java"
public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
@@ -4466,7 +4439,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 3, attributes: 5
+ interfaces: 0, fields: 1, methods: 3, attributes: 4
public int value;
descriptor: I
flags: (0x0001) ACC_PUBLIC
@@ -4537,15 +4510,13 @@
InnerClasses:
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
-RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -4741,6 +4712,7 @@
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public static #x= #x of #x; // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+ public static #x= #x of #x; // Double$NestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
@@ -4755,6 +4727,7 @@
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+ com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
similarity index 96%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
rename to tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
index 6d8a48a..30dfc80 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations.java
@@ -28,9 +28,9 @@
@HostSideTestStub
@HostSideTestClassLoadHook(
"com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
-public class TinyFrameworkClassAnnotations {
+public class TinyFrameworkAnnotations {
@HostSideTestStub
- public TinyFrameworkClassAnnotations() {
+ public TinyFrameworkAnnotations() {
}
@HostSideTestStub
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.java
similarity index 64%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java
rename to tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.java
index 145b65a..a626bc9 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations.java
@@ -15,38 +15,21 @@
*/
package com.android.hoststubgen.test.tinyframework;
-import android.hosttest.annotation.HostSideTestStub;
import android.hosttest.annotation.HostSideTestSubstitute;
+import android.hosttest.annotation.HostSideTestThrow;
import android.hosttest.annotation.HostSideTestWholeClassStub;
@HostSideTestWholeClassStub
-public class TinyFrameworkClassClassWideAnnotations {
- public TinyFrameworkClassClassWideAnnotations() {
+public class TinyFrameworkClassWideAnnotations {
+ public TinyFrameworkClassWideAnnotations() {
}
public int stub = 1;
- public int keep = 2;
-
- // Cannot have an initial value, because otherwise .ctor will fail to set it at runtime.
- public int remove;
-
- // @Stub
public int addOne(int value) {
- return addOneInner(value);
- }
-
- // @Keep
- public int addOneInner(int value) {
return value + 1;
}
- // @Remove
- public void toBeRemoved(String foo) {
- throw new RuntimeException();
- }
-
- @HostSideTestStub
@HostSideTestSubstitute(suffix = "_host")
public int addTwo(int value) {
throw new RuntimeException("not supported on host side");
@@ -56,14 +39,7 @@
return value + 2;
}
- @HostSideTestStub
- @HostSideTestSubstitute(suffix = "_host")
- public static native int nativeAddThree(int value);
-
- public static int nativeAddThree_host(int value) {
- return value + 3;
- }
-
+ @HostSideTestThrow
public String unsupportedMethod() {
return "This value shouldn't be seen on the host side.";
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
index e1c48bb..fec307a 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
@@ -34,6 +34,7 @@
return 2;
}
};
+
public Supplier<Integer> getSupplier() {
return new Supplier<Integer>() {
@Override
@@ -52,12 +53,10 @@
};
}
- @HostSideTestWholeClassStub
public class InnerClass {
public int value = 5;
}
- @HostSideTestWholeClassStub
public static class StaticNestedClass {
public int value = 6;
@@ -70,6 +69,10 @@
}
};
}
+
+ public static class Double$NestedClass {
+ public int value = 8;
+ }
}
public static class BaseClass {
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotationsTest.java
similarity index 79%
rename from tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java
rename to tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotationsTest.java
index 288c716..181902a 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotationsTest.java
@@ -21,20 +21,20 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;
-public class TinyFrameworkClassWithAnnotTest {
+public class TinyFrameworkAnnotationsTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testSimple() {
- TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+ TinyFrameworkAnnotations tfc = new TinyFrameworkAnnotations();
assertThat(tfc.addOne(1)).isEqualTo(2);
assertThat(tfc.stub).isEqualTo(1);
}
// @Test
// public void testDoesntCompile() {
-// TinyFrameworkClassWithAnnot tfc = new TinyFrameworkClassWithAnnot();
+// TinyFrameworkAnnotations tfc = new TinyFrameworkAnnotations();
//
// tfc.addOneInner(1); // Shouldn't compile.
// tfc.toBeRemoved("abc"); // Shouldn't compile.
@@ -45,19 +45,19 @@
@Test
public void testSubstitute() {
- TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+ TinyFrameworkAnnotations tfc = new TinyFrameworkAnnotations();
assertThat(tfc.addTwo(1)).isEqualTo(3);
}
@Test
public void testSubstituteNative() {
- TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+ TinyFrameworkAnnotations tfc = new TinyFrameworkAnnotations();
assertThat(tfc.nativeAddThree(1)).isEqualTo(4);
}
@Test
public void testVisibleButUsesUnsupportedMethod() {
- TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+ TinyFrameworkAnnotations tfc = new TinyFrameworkAnnotations();
thrown.expect(RuntimeException.class);
thrown.expectMessage("not yet supported");
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index 1692c6e89..dda5a05 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.fail;
import com.android.hoststubgen.test.tinyframework.R.Nested;
-import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass;
import org.junit.Rule;
import org.junit.Test;
@@ -88,42 +87,6 @@
}
@Test
- public void testNestedClass1() {
- assertThat(new TinyFrameworkNestedClasses().mSupplier.get()).isEqualTo(1);
- }
-
- @Test
- public void testNestedClass2() {
- assertThat(TinyFrameworkNestedClasses.sSupplier.get()).isEqualTo(2);
- }
-
- @Test
- public void testNestedClass3() {
- assertThat(new TinyFrameworkNestedClasses().getSupplier().get()).isEqualTo(3);
- }
-
- @Test
- public void testNestedClass4() {
- assertThat(TinyFrameworkNestedClasses.getSupplier_static().get()).isEqualTo(4);
- }
-
- @Test
- public void testNestedClass5() {
- assertThat((new TinyFrameworkNestedClasses()).new InnerClass().value).isEqualTo(5);
- }
-
- @Test
- public void testNestedClass6() {
- assertThat(new TinyFrameworkNestedClasses.StaticNestedClass().value).isEqualTo(6);
- }
-
- @Test
- public void testNestedClass7() {
- assertThat(TinyFrameworkNestedClasses.StaticNestedClass.getSupplier_static().get())
- .isEqualTo(7);
- }
-
- @Test
public void testLambda1() {
assertThat(new TinyFrameworkLambdas().mSupplier.get()).isEqualTo(1);
}
@@ -220,18 +183,13 @@
}
@Test
- public void testMethodCallBeforeSuperCall() {
- assertThat(new SubClass(3).value).isEqualTo(3);
- }
-
- @Test
public void testClassLoadHook() {
assertThat(TinyFrameworkClassWithInitializerStub.sInitialized).isTrue();
// Having this line before assertThat() will ensure these class are already loaded.
var classes = new Class[]{
TinyFrameworkClassWithInitializerStub.class,
- TinyFrameworkClassAnnotations.class,
+ TinyFrameworkAnnotations.class,
TinyFrameworkForTextPolicy.class,
};
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
new file mode 100644
index 0000000..83753b5
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotationsTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 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.hoststubgen.test.tinyframework;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class TinyFrameworkClassWideAnnotationsTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testSimple() {
+ var tfc = new TinyFrameworkClassWideAnnotations();
+ assertThat(tfc.addOne(1)).isEqualTo(2);
+ assertThat(tfc.stub).isEqualTo(1);
+ }
+
+ @Test
+ public void testSubstitute() {
+ var tfc = new TinyFrameworkClassWideAnnotations();
+ assertThat(tfc.addTwo(1)).isEqualTo(3);
+ }
+
+ @Test
+ public void testVisibleButUsesUnsupportedMethod() {
+ var tfc = new TinyFrameworkClassWideAnnotations();
+
+ thrown.expect(RuntimeException.class);
+ thrown.expectMessage("not yet supported");
+ tfc.visibleButUsesUnsupportedMethod();
+ }
+
+ @Test
+ public void testMethodCallBeforeSuperCall() {
+ assertThat(new TinyFrameworkNestedClasses.SubClass(3).value).isEqualTo(3);
+ }
+
+ @Test
+ public void testNestedClass1() {
+ assertThat(new TinyFrameworkNestedClasses().mSupplier.get()).isEqualTo(1);
+ }
+
+ @Test
+ public void testNestedClass2() {
+ assertThat(TinyFrameworkNestedClasses.sSupplier.get()).isEqualTo(2);
+ }
+
+ @Test
+ public void testNestedClass3() {
+ assertThat(new TinyFrameworkNestedClasses().getSupplier().get()).isEqualTo(3);
+ }
+
+ @Test
+ public void testNestedClass4() {
+ assertThat(TinyFrameworkNestedClasses.getSupplier_static().get()).isEqualTo(4);
+ }
+
+ @Test
+ public void testNestedClass5() {
+ assertThat((new TinyFrameworkNestedClasses()).new InnerClass().value).isEqualTo(5);
+ }
+
+ @Test
+ public void testNestedClass6() {
+ assertThat(new TinyFrameworkNestedClasses.StaticNestedClass().value).isEqualTo(6);
+ }
+
+ @Test
+ public void testNestedClass7() {
+ assertThat(TinyFrameworkNestedClasses.StaticNestedClass.getSupplier_static().get())
+ .isEqualTo(7);
+ }
+
+ @Test
+ public void testNestedClass8() {
+ assertThat(new TinyFrameworkNestedClasses.StaticNestedClass.Double$NestedClass().value)
+ .isEqualTo(8);
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt
index 6b46c84..5b2795c 100644
--- a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt
+++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt
@@ -23,18 +23,6 @@
import org.objectweb.asm.Opcodes.ACC_STATIC
class AsmUtilsTest {
- private fun checkGetDirectOuterClassName(input: String, expected: String?) {
- assertThat(getDirectOuterClassName(input)).isEqualTo(expected)
- }
-
- @Test
- fun testGetDirectOuterClassName() {
- checkGetDirectOuterClassName("a", null)
- checkGetDirectOuterClassName("a\$x", "a")
- checkGetDirectOuterClassName("a.b.c\$x", "a.b.c")
- checkGetDirectOuterClassName("a.b.c\$x\$y", "a.b.c\$x")
- }
-
@Test
fun testVisibility() {
fun test(access: Int, expected: Visibility) {