diff options
570 files changed, 19216 insertions, 5882 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 1fb5f34650cb..20f879c7fc2c 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -428,7 +428,10 @@ java_aconfig_library { aconfig_declarations { name: "com.android.media.flags.bettertogether-aconfig", package: "com.android.media.flags", - srcs: ["media/java/android/media/flags/media_better_together.aconfig"], + srcs: [ + "media/java/android/media/flags/media_better_together.aconfig", + "media/java/android/media/flags/fade_manager_configuration.aconfig", + ], } java_aconfig_library { diff --git a/Android.bp b/Android.bp index c1fb41f845e3..fa7c97d3d21a 100644 --- a/Android.bp +++ b/Android.bp @@ -95,7 +95,7 @@ filegroup { ":platform-compat-native-aidl", // AIDL sources from external directories - ":android.hardware.biometrics.common-V3-java-source", + ":android.hardware.biometrics.common-V4-java-source", ":android.hardware.biometrics.fingerprint-V3-java-source", ":android.hardware.gnss-V2-java-source", ":android.hardware.graphics.common-V3-java-source", @@ -379,6 +379,7 @@ java_defaults { // system propagates "required" properly. "gps_debug.conf", "protolog.conf.json.gz", + "framework-res", // any install dependencies should go into framework-minus-apex-install-dependencies // rather than here to avoid bloating incremental build time ], diff --git a/apex/jobscheduler/framework/aconfig/job.aconfig b/apex/jobscheduler/framework/aconfig/job.aconfig index f5e33a80211b..e73b434042af 100644 --- a/apex/jobscheduler/framework/aconfig/job.aconfig +++ b/apex/jobscheduler/framework/aconfig/job.aconfig @@ -1,6 +1,13 @@ package: "android.app.job" flag { + name: "enforce_minimum_time_windows" + namespace: "backstage_power" + description: "Enforce a minimum time window for job latencies & deadlines" + bug: "311402873" +} + +flag { name: "job_debug_info_apis" namespace: "backstage_power" description: "Add APIs to let apps attach debug information to jobs" diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 742ed5f2eeb7..4bc73130db29 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.util.TimeUtils.formatDuration; import android.annotation.BytesLong; @@ -36,6 +37,7 @@ import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.EnabledSince; +import android.compat.annotation.Overridable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ComponentName; @@ -48,7 +50,9 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import android.os.Process; import android.os.Trace; +import android.os.UserHandle; import android.util.ArraySet; import android.util.Log; @@ -113,6 +117,16 @@ public class JobInfo implements Parcelable { @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long REJECT_NEGATIVE_NETWORK_ESTIMATES = 253665015L; + /** + * Enforce a minimum time window between job latencies and deadlines. + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Overridable // Aid in testing + public static final long ENFORCE_MINIMUM_TIME_WINDOWS = 311402873L; + /** @hide */ @IntDef(prefix = { "NETWORK_TYPE_" }, value = { NETWORK_TYPE_NONE, @@ -1866,10 +1880,40 @@ public class JobInfo implements Parcelable { * Set deadline which is the maximum scheduling latency. The job will be run by this * deadline even if other requirements (including a delay set through * {@link #setMinimumLatency(long)}) are not met. + * {@link JobParameters#isOverrideDeadlineExpired()} will return {@code true} if the job's + * deadline has passed. + * * <p> * Because it doesn't make sense setting this property on a periodic job, doing so will * throw an {@link java.lang.IllegalArgumentException} when * {@link android.app.job.JobInfo.Builder#build()} is called. + * + * <p class="note"> + * Since a job will run once the deadline has passed regardless of the status of other + * constraints, setting a deadline of 0 with other constraints makes those constraints + * meaningless when it comes to execution decisions. Avoid doing this. + * </p> + * + * <p> + * Short deadlines hinder the system's ability to optimize scheduling behavior and may + * result in running jobs at inopportune times. Therefore, starting in Android version + * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, minimum time windows will be + * enforced to help make it easier to better optimize job execution. Time windows are + * defined as the time between a job's {@link #setMinimumLatency(long) minimum latency} + * and its deadline. If the minimum latency is not set, it is assumed to be 0. + * The following minimums will be enforced: + * <ul> + * <li> + * Jobs with {@link #PRIORITY_DEFAULT} or higher priorities have a minimum time + * window of one hour. + * </li> + * <li>Jobs with {@link #PRIORITY_LOW} have a minimum time window of 6 hours.</li> + * <li>Jobs with {@link #PRIORITY_MIN} have a minimum time window of 12 hours.</li> + * </ul> + * + * Work that must happen immediately should use {@link #setExpedited(boolean)} or + * {@link #setUserInitiated(boolean)} in the appropriate manner. + * * @see JobInfo#getMaxExecutionDelayMillis() */ public Builder setOverrideDeadline(long maxExecutionDelayMillis) { @@ -2143,12 +2187,14 @@ public class JobInfo implements Parcelable { */ public JobInfo build() { return build(Compatibility.isChangeEnabled(DISALLOW_DEADLINES_FOR_PREFETCH_JOBS), - Compatibility.isChangeEnabled(REJECT_NEGATIVE_NETWORK_ESTIMATES)); + Compatibility.isChangeEnabled(REJECT_NEGATIVE_NETWORK_ESTIMATES), + Compatibility.isChangeEnabled(ENFORCE_MINIMUM_TIME_WINDOWS)); } /** @hide */ public JobInfo build(boolean disallowPrefetchDeadlines, - boolean rejectNegativeNetworkEstimates) { + boolean rejectNegativeNetworkEstimates, + boolean enforceMinimumTimeWindows) { // This check doesn't need to be inside enforceValidity. It's an unnecessary legacy // check that would ideally be phased out instead. if (mBackoffPolicySet && (mConstraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0) { @@ -2157,7 +2203,8 @@ public class JobInfo implements Parcelable { " setRequiresDeviceIdle is an error."); } JobInfo jobInfo = new JobInfo(this); - jobInfo.enforceValidity(disallowPrefetchDeadlines, rejectNegativeNetworkEstimates); + jobInfo.enforceValidity(disallowPrefetchDeadlines, rejectNegativeNetworkEstimates, + enforceMinimumTimeWindows); return jobInfo; } @@ -2176,7 +2223,8 @@ public class JobInfo implements Parcelable { * @hide */ public final void enforceValidity(boolean disallowPrefetchDeadlines, - boolean rejectNegativeNetworkEstimates) { + boolean rejectNegativeNetworkEstimates, + boolean enforceMinimumTimeWindows) { // Check that network estimates require network type and are reasonable values. if ((networkDownloadBytes > 0 || networkUploadBytes > 0 || minimumNetworkChunkBytes > 0) && networkRequest == null) { @@ -2291,6 +2339,39 @@ public class JobInfo implements Parcelable { throw new IllegalArgumentException("Invalid priority level provided: " + mPriority); } + if (enforceMinimumTimeWindows + && Flags.enforceMinimumTimeWindows() + // TODO(312197030): remove exemption for the system + && !UserHandle.isCore(Process.myUid()) + && hasLateConstraint && !isPeriodic) { + final long windowStart = hasEarlyConstraint ? minLatencyMillis : 0; + if (mPriority >= PRIORITY_DEFAULT) { + if (maxExecutionDelayMillis - windowStart < HOUR_IN_MILLIS) { + throw new IllegalArgumentException( + getPriorityString(mPriority) + + " cannot have a time window less than 1 hour." + + " Delay=" + windowStart + + ", deadline=" + maxExecutionDelayMillis); + } + } else if (mPriority >= PRIORITY_LOW) { + if (maxExecutionDelayMillis - windowStart < 6 * HOUR_IN_MILLIS) { + throw new IllegalArgumentException( + getPriorityString(mPriority) + + " cannot have a time window less than 6 hours." + + " Delay=" + windowStart + + ", deadline=" + maxExecutionDelayMillis); + } + } else { + if (maxExecutionDelayMillis - windowStart < 12 * HOUR_IN_MILLIS) { + throw new IllegalArgumentException( + getPriorityString(mPriority) + + " cannot have a time window less than 12 hours." + + " Delay=" + windowStart + + ", deadline=" + maxExecutionDelayMillis); + } + } + } + if (isExpedited) { if (hasEarlyConstraint) { throw new IllegalArgumentException("An expedited job cannot have a time delay"); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 2d972d0eebe4..f97100bf2e9b 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -268,6 +268,7 @@ public class JobSchedulerService extends com.android.server.SystemService /** Master list of jobs. */ final JobStore mJobs; private final CountDownLatch mJobStoreLoadedLatch; + private final CountDownLatch mStartControllerTrackingLatch; /** Tracking the standby bucket state of each app */ final StandbyTracker mStandbyTracker; /** Tracking amount of time each package runs for. */ @@ -2521,6 +2522,7 @@ public class JobSchedulerService extends com.android.server.SystemService mBatteryStateTracker.startTracking(); // Create the controllers. + mStartControllerTrackingLatch = new CountDownLatch(1); mControllers = new ArrayList<StateController>(); mPrefetchController = new PrefetchController(this); mControllers.add(mPrefetchController); @@ -2552,6 +2554,8 @@ public class JobSchedulerService extends com.android.server.SystemService new TareController(this, backgroundJobsController, mConnectivityController); mControllers.add(mTareController); + startControllerTrackingAsync(); + mRestrictiveControllers = new ArrayList<>(); mRestrictiveControllers.add(batteryController); mRestrictiveControllers.add(mConnectivityController); @@ -2623,16 +2627,22 @@ public class JobSchedulerService extends com.android.server.SystemService public void onBootPhase(int phase) { if (PHASE_LOCK_SETTINGS_READY == phase) { // This is the last phase before PHASE_SYSTEM_SERVICES_READY. We need to ensure that + // controllers have started tracking and that // persisted jobs are loaded before we can proceed to PHASE_SYSTEM_SERVICES_READY. try { + mStartControllerTrackingLatch.await(); + } catch (InterruptedException e) { + Slog.e(TAG, "Couldn't wait on controller tracking start latch"); + } + try { mJobStoreLoadedLatch.await(); } catch (InterruptedException e) { Slog.e(TAG, "Couldn't wait on job store loading latch"); } } else if (PHASE_SYSTEM_SERVICES_READY == phase) { mConstantsObserver.start(); - for (StateController controller : mControllers) { - controller.onSystemServicesReady(); + for (int i = mControllers.size() - 1; i >= 0; --i) { + mControllers.get(i).onSystemServicesReady(); } mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull( @@ -2695,6 +2705,17 @@ public class JobSchedulerService extends com.android.server.SystemService } } + private void startControllerTrackingAsync() { + mHandler.post(() -> { + synchronized (mLock) { + for (int i = mControllers.size() - 1; i >= 0; --i) { + mControllers.get(i).startTrackingLocked(); + } + } + mStartControllerTrackingLatch.countDown(); + }); + } + /** * Called when we have a job status object that we need to insert in our * {@link com.android.server.job.JobStore}, and make sure all the relevant controllers know @@ -4367,7 +4388,7 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.w(TAG, "Uid " + uid + " set bias on its job"); return new JobInfo.Builder(job) .setBias(JobInfo.BIAS_DEFAULT) - .build(false, false); + .build(false, false, false); } } @@ -4389,7 +4410,9 @@ public class JobSchedulerService extends com.android.server.SystemService job.enforceValidity( CompatChanges.isChangeEnabled( JobInfo.DISALLOW_DEADLINES_FOR_PREFETCH_JOBS, callingUid), - rejectNegativeNetworkEstimates); + rejectNegativeNetworkEstimates, + CompatChanges.isChangeEnabled( + JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS, callingUid)); if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG); @@ -5176,6 +5199,12 @@ public class JobSchedulerService extends com.android.server.SystemService return mTareController; } + @VisibleForTesting + protected void waitOnAsyncLoadingForTesting() throws Exception { + mStartControllerTrackingLatch.await(); + // Ignore the job store loading for testing. + } + // Shell command infrastructure int getJobState(PrintWriter pw, String pkgName, int userId, @Nullable String namespace, int jobId) { diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index afcbddad611e..53b14d616ecc 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -1495,7 +1495,7 @@ public final class JobStore { // return value), the deadline is dropped. Periodic jobs require all constraints // to be met, so there's no issue with their deadlines. // The same logic applies for other target SDK-based validation checks. - builtJob = jobBuilder.build(false, false); + builtJob = jobBuilder.build(false, false, false); } catch (Exception e) { Slog.w(TAG, "Unable to build job from XML, ignoring: " + jobBuilder.summarize(), e); return null; diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java index 25b3421a55f0..cd3ba6b9e13e 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -73,6 +73,10 @@ public final class BackgroundJobsController extends StateController { LocalServices.getService(ActivityManagerInternal.class)); mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull( LocalServices.getService(AppStateTracker.class)); + } + + @Override + public void startTrackingLocked() { mAppStateTracker.addListener(mForceAppStandbyListener); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java index 5246f2bf838b..ddbc2ecf5e3e 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java @@ -78,11 +78,15 @@ public final class BatteryController extends RestrictingController { FlexibilityController flexibilityController) { super(service); mPowerTracker = new PowerTracker(); - mPowerTracker.startTracking(); mFlexibilityController = flexibilityController; } @Override + public void startTrackingLocked() { + mPowerTracker.startTracking(); + } + + @Override public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) { if (taskStatus.hasPowerConstraint()) { final long nowElapsed = sElapsedRealtimeClock.millis(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java index b029e0075dc2..9d4cba18b4b1 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java @@ -106,7 +106,10 @@ public class ComponentController extends StateController { public ComponentController(JobSchedulerService service) { super(service); + } + @Override + public void startTrackingLocked() { final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java index a900d162ab96..13a474ccf451 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java @@ -201,6 +201,10 @@ public final class FlexibilityController extends StateController { mPercentToDropConstraints = mFcConfig.DEFAULT_PERCENT_TO_DROP_FLEXIBLE_CONSTRAINTS; mPrefetchController = prefetchController; + } + + @Override + public void startTrackingLocked() { if (mFlexibilityEnabled) { mPrefetchController.registerPrefetchChangedListener(mPrefetchChangedListener); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java index 47d3fd5bc8c4..adee322f60cf 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java @@ -19,7 +19,6 @@ package com.android.server.job.controllers; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.NonNull; -import android.content.Context; import android.content.pm.PackageManager; import android.os.UserHandle; import android.provider.DeviceConfig; @@ -56,7 +55,7 @@ public final class IdleController extends RestrictingController implements Idlen public IdleController(JobSchedulerService service, FlexibilityController flexibilityController) { super(service); - initIdleStateTracking(mContext); + initIdleStateTracker(); mFlexibilityController = flexibilityController; } @@ -127,7 +126,7 @@ public final class IdleController extends RestrictingController implements Idlen * Idle state tracking, and messaging with the task manager when * significant state changes occur */ - private void initIdleStateTracking(Context ctx) { + private void initIdleStateTracker() { final boolean isCar = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_AUTOMOTIVE); if (isCar) { @@ -135,7 +134,11 @@ public final class IdleController extends RestrictingController implements Idlen } else { mIdleTracker = new DeviceIdlenessTracker(); } - mIdleTracker.startTracking(ctx, mService, this); + } + + @Override + public void startTrackingLocked() { + mIdleTracker.startTracking(mContext, mService, this); } @Override diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index 13bea6bd1dd1..b74806494a60 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -636,7 +636,7 @@ public final class JobStatus { .build()); // Don't perform validation checks at this point since we've already passed the // initial validation check. - job = builder.build(false, false); + job = builder.build(false, false, false); } this.job = job; diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java index fdeb072cacb3..865e5417faf2 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java @@ -134,7 +134,10 @@ public class PrefetchController extends StateController { mThresholdAlarmListener = new ThresholdAlarmListener( mContext, AppSchedulingModuleThread.get().getLooper()); mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class); + } + @Override + public void startTrackingLocked() { mUsageStatsManagerInternal .registerLaunchTimeChangedListener(mEstimatedLaunchTimeChangedListener); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java index 44ac798c2912..2b9205117316 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java @@ -56,6 +56,12 @@ public abstract class StateController { } /** + * Called to get the controller to start tracking relevant information. This is called before + * {@link #onSystemServicesReady()}. + */ + public void startTrackingLocked() {} + + /** * Called when the system boot phase has reached * {@link com.android.server.SystemService#PHASE_SYSTEM_SERVICES_READY}. */ @@ -67,6 +73,7 @@ public abstract class StateController { * This logic is put here so the JobManager can be completely agnostic of Controller logic. * Also called when updating a task, so implementing controllers have to be aware of * preexisting tasks. + * This will never be called before {@link #onSystemServicesReady()}. */ public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java index 11e2ff7bd77f..0c48c4e5a766 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java @@ -55,6 +55,10 @@ public final class StorageController extends StateController { public StorageController(JobSchedulerService service) { super(service); mStorageTracker = new StorageTracker(); + } + + @Override + public void startTrackingLocked() { mStorageTracker.startTracking(); } diff --git a/core/api/current.txt b/core/api/current.txt index f01563a90fb3..119a3de6835e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12428,7 +12428,7 @@ package android.content.pm { method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback, @NonNull android.os.Handler); method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public void reportUnarchivalStatus(int, int, long, @Nullable android.app.PendingIntent) throws android.content.pm.PackageManager.NameNotFoundException; - method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void requestArchive(@NonNull String, @NonNull android.content.IntentSender) throws android.content.pm.PackageManager.NameNotFoundException; + method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void requestArchive(@NonNull String, @NonNull android.content.IntentSender, int) throws android.content.pm.PackageManager.NameNotFoundException; method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public void requestUnarchive(@NonNull String, @NonNull android.content.IntentSender) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull String, @NonNull android.content.IntentSender); method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull android.content.pm.VersionedPackage, @NonNull android.content.IntentSender); @@ -12853,6 +12853,8 @@ package android.content.pm { field public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4; // 0x4 field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3 field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1 + field @FlaggedApi("android.content.pm.archiving") public static final int DELETE_ARCHIVE = 16; // 0x10 + field @FlaggedApi("android.content.pm.archiving") public static final int DELETE_SHOW_DIALOG = 32; // 0x20 field public static final int DONT_KILL_APP = 1; // 0x1 field public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID"; field public static final String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT"; @@ -19508,6 +19510,7 @@ package android.hardware.camera2 { field @Deprecated @NonNull public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.String> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID; + field @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH; @@ -19533,6 +19536,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_FACE_DETECT_MODE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Point[]> STATISTICS_HOT_PIXEL_MAP; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE; + field @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensIntrinsicsSample[]> STATISTICS_LENS_INTRINSICS_SAMPLES; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensShadingMap> STATISTICS_LENS_SHADING_CORRECTION_MAP; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE; field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_OIS_DATA_MODE; @@ -19689,6 +19693,12 @@ package android.hardware.camera2.params { method public boolean isMultiResolution(); } + @FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class LensIntrinsicsSample { + ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public LensIntrinsicsSample(long, @NonNull float[]); + method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public float[] getLensIntrinsics(); + method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public long getTimestamp(); + } + public final class LensShadingMap { method public void copyGainFactors(float[], int); method public int getColumnCount(); @@ -33205,6 +33215,7 @@ package android.os { public static class PerformanceHintManager.Session implements java.io.Closeable { method public void close(); method public void reportActualWorkDuration(long); + method @FlaggedApi("android.os.adpf_gpu_report_actual_work_duration") public void reportActualWorkDuration(@NonNull android.os.WorkDuration); method @FlaggedApi("android.os.adpf_prefer_power_efficiency") public void setPreferPowerEfficiency(boolean); method public void setThreads(@NonNull int[]); method public void updateTargetWorkDuration(long); @@ -33554,6 +33565,7 @@ package android.os { method public static boolean setCurrentTimeMillis(long); method public static void sleep(long); method public static long uptimeMillis(); + method @FlaggedApi("android.os.adpf_gpu_report_actual_work_duration") public static long uptimeNanos(); } public class TestLooperManager { @@ -33819,6 +33831,22 @@ package android.os { method @RequiresPermission(android.Manifest.permission.VIBRATE) public final void vibrate(@NonNull android.os.CombinedVibration, @Nullable android.os.VibrationAttributes); } + @FlaggedApi("android.os.adpf_gpu_report_actual_work_duration") public final class WorkDuration implements android.os.Parcelable { + ctor public WorkDuration(); + ctor public WorkDuration(long, long, long, long); + method public int describeContents(); + method public long getActualCpuDurationNanos(); + method public long getActualGpuDurationNanos(); + method public long getActualTotalDurationNanos(); + method public long getWorkPeriodStartTimestampNanos(); + method public void setActualCpuDurationNanos(long); + method public void setActualGpuDurationNanos(long); + method public void setActualTotalDurationNanos(long); + method public void setWorkPeriodStartTimestampNanos(long); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.os.WorkDuration> CREATOR; + } + public class WorkSource implements android.os.Parcelable { ctor public WorkSource(); ctor public WorkSource(android.os.WorkSource); @@ -39264,7 +39292,7 @@ package android.security.keystore { method @Nullable public java.util.Date getKeyValidityStart(); method @NonNull public String getKeystoreAlias(); method public int getMaxUsageCount(); - method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests(); + method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public java.util.Set<java.lang.String> getMgf1Digests(); method public int getPurposes(); method @NonNull public String[] getSignaturePaddings(); method public int getUserAuthenticationType(); @@ -39272,7 +39300,7 @@ package android.security.keystore { method public boolean isDevicePropertiesAttestationIncluded(); method @NonNull public boolean isDigestsSpecified(); method public boolean isInvalidatedByBiometricEnrollment(); - method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified(); + method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public boolean isMgf1DigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isStrongBoxBacked(); method public boolean isUnlockedDeviceRequired(); @@ -39304,7 +39332,7 @@ package android.security.keystore { method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int); - method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...); + method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMgf1Digests(@NonNull java.lang.String...); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean); @@ -39409,14 +39437,14 @@ package android.security.keystore { method @Nullable public java.util.Date getKeyValidityForOriginationEnd(); method @Nullable public java.util.Date getKeyValidityStart(); method public int getMaxUsageCount(); - method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public java.util.Set<java.lang.String> getMgf1Digests(); + method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public java.util.Set<java.lang.String> getMgf1Digests(); method public int getPurposes(); method @NonNull public String[] getSignaturePaddings(); method public int getUserAuthenticationType(); method public int getUserAuthenticationValidityDurationSeconds(); method public boolean isDigestsSpecified(); method public boolean isInvalidatedByBiometricEnrollment(); - method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public boolean isMgf1DigestsSpecified(); + method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public boolean isMgf1DigestsSpecified(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUnlockedDeviceRequired(); method public boolean isUserAuthenticationRequired(); @@ -39438,7 +39466,7 @@ package android.security.keystore { method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date); method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date); method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int); - method @FlaggedApi("android.security.mgf1_digest_setter") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...); + method @FlaggedApi("MGF1_DIGEST_SETTER") @NonNull public android.security.keystore.KeyProtection.Builder setMgf1Digests(@Nullable java.lang.String...); method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean); @@ -47195,7 +47223,7 @@ package android.text { method public void getSelectionPath(int, int, android.graphics.Path); method public final float getSpacingAdd(); method public final float getSpacingMultiplier(); - method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public final CharSequence getText(); + method @NonNull public final CharSequence getText(); method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public final android.text.TextDirectionHeuristic getTextDirectionHeuristic(); method public abstract int getTopPadding(); method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public boolean getUseBoundsForWidth(); diff --git a/core/api/removed.txt b/core/api/removed.txt index b7714f118766..12b1f6a1fba3 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -30,20 +30,6 @@ package android.app { } -package android.app.usage { - - public class StorageStatsManager { - method @Deprecated public long getFreeBytes(String) throws java.io.IOException; - method @Deprecated public long getTotalBytes(String) throws java.io.IOException; - method @Deprecated public boolean isQuotaSupported(String); - method @Deprecated public android.app.usage.ExternalStorageStats queryExternalStatsForUser(String, android.os.UserHandle) throws java.io.IOException; - method @Deprecated public android.app.usage.StorageStats queryStatsForPackage(String, String, android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; - method @Deprecated public android.app.usage.StorageStats queryStatsForUid(String, int) throws java.io.IOException; - method @Deprecated public android.app.usage.StorageStats queryStatsForUser(String, android.os.UserHandle) throws java.io.IOException; - } - -} - package android.content { public abstract class ContentProvider implements android.content.ComponentCallbacks2 { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 847edd13bb05..30d57bb190be 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -351,6 +351,7 @@ package android { field public static final String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER"; field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT"; field public static final String SET_WALLPAPER_DIM_AMOUNT = "android.permission.SET_WALLPAPER_DIM_AMOUNT"; + field @FlaggedApi("android.service.chooser.support_nfc_resolver") public static final String SHOW_CUSTOMIZED_RESOLVER = "android.permission.SHOW_CUSTOMIZED_RESOLVER"; field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE"; field public static final String SHUTDOWN = "android.permission.SHUTDOWN"; field public static final String SIGNAL_REBOOT_READINESS = "android.permission.SIGNAL_REBOOT_READINESS"; @@ -3872,6 +3873,7 @@ package android.content.pm { field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1 field public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE"; + field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_DELETE_FLAGS = "android.content.pm.extra.DELETE_FLAGS"; field public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; field @Deprecated public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH"; field public static final int LOCATION_DATA_APP = 0; // 0x0 @@ -11782,6 +11784,14 @@ package android.service.carrier { } +package android.service.chooser { + + @FlaggedApi("android.service.chooser.support_nfc_resolver") public class CustomChoosers { + method @FlaggedApi("android.service.chooser.support_nfc_resolver") @NonNull public static android.content.Intent createNfcResolverIntent(@NonNull android.content.Intent, @Nullable CharSequence, @NonNull java.util.List<android.content.pm.ResolveInfo>); + } + +} + package android.service.cloudsearch { public abstract class CloudSearchService extends android.app.Service { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 00432dcf152c..c52d27ea6608 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -971,6 +971,7 @@ public class Activity extends ContextThemeWrapper private final ActivityManager.TaskDescription mTaskDescription = new ActivityManager.TaskDescription(); + private int mLastTaskDescriptionHashCode; protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused}; @@ -7612,6 +7613,13 @@ public class Activity extends ContextThemeWrapper mTaskDescription.setIcon(Icon.createWithBitmap(icon)); } } + if (mLastTaskDescriptionHashCode == mTaskDescription.hashCode()) { + // Early return if the hashCode is the same. + // Note that we do not use #equals() to perform the check because there are several + // places in this class that directly sets the value to mTaskDescription. + return; + } + mLastTaskDescriptionHashCode = mTaskDescription.hashCode(); ActivityClient.getInstance().setTaskDescription(mToken, mTaskDescription); } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 854e12177fb5..6b7f4880e2f0 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2309,6 +2309,32 @@ public class ActivityManager { } @Override + public int hashCode() { + int result = 17; + if (mLabel != null) { + result = result * 31 + mLabel.hashCode(); + } + if (mIcon != null) { + result = result * 31 + mIcon.hashCode(); + } + if (mIconFilename != null) { + result = result * 31 + mIconFilename.hashCode(); + } + result = result * 31 + mColorPrimary; + result = result * 31 + mColorBackground; + result = result * 31 + mColorBackgroundFloating; + result = result * 31 + mStatusBarColor; + result = result * 31 + mNavigationBarColor; + result = result * 31 + mStatusBarAppearance; + result = result * 31 + (mEnsureStatusBarContrastWhenTransparent ? 1 : 0); + result = result * 31 + (mEnsureNavigationBarContrastWhenTransparent ? 1 : 0); + result = result * 31 + mResizeMode; + result = result * 31 + mMinWidth; + result = result * 31 + mMinHeight; + return result; + } + + @Override public boolean equals(@Nullable Object obj) { if (!(obj instanceof TaskDescription)) { return false; diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 32c40df32585..ea9bb396f83c 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -46,7 +46,6 @@ import android.os.TransactionTooLargeException; import android.os.WorkSource; import android.util.ArraySet; import android.util.Pair; -import android.util.StatsEvent; import com.android.internal.os.TimeoutRecord; @@ -1224,7 +1223,8 @@ public abstract class ActivityManagerInternal { * @return The stats event for the cached apps high watermark since last pull. */ @NonNull - public abstract StatsEvent getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull); + // TODO: restore to android.util.StatsEvent once Ravenwood includes Mainline stubs + public abstract Object getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull); /** * Internal method for clearing app data, with the extra param that is used to indicate restore. diff --git a/core/java/android/app/Person.java b/core/java/android/app/Person.java index 18fc0ce6af15..04186600125f 100644 --- a/core/java/android/app/Person.java +++ b/core/java/android/app/Person.java @@ -189,6 +189,11 @@ public final class Person implements Parcelable { */ public void visitUris(@NonNull Consumer<Uri> visitor) { visitor.accept(getIconUri()); + if (Flags.visitRiskyUris()) { + if (mUri != null && !mUri.isEmpty()) { + visitor.accept(Uri.parse(mUri)); + } + } } /** Builder for the immutable {@link Person} class. */ diff --git a/core/java/android/app/time/TEST_MAPPING b/core/java/android/app/time/TEST_MAPPING index 0f7a0700b370..7673acacbfbe 100644 --- a/core/java/android/app/time/TEST_MAPPING +++ b/core/java/android/app/time/TEST_MAPPING @@ -15,10 +15,7 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] - } - ], - // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows. - "postsubmit": [ + }, { "name": "FrameworksTimeServicesTests", "options": [ diff --git a/core/java/android/app/timedetector/TEST_MAPPING b/core/java/android/app/timedetector/TEST_MAPPING index 43dd82f8a26e..c7ca6a230d43 100644 --- a/core/java/android/app/timedetector/TEST_MAPPING +++ b/core/java/android/app/timedetector/TEST_MAPPING @@ -15,10 +15,7 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] - } - ], - // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows. - "postsubmit": [ + }, { "name": "FrameworksTimeServicesTests", "options": [ diff --git a/core/java/android/app/timezonedetector/TEST_MAPPING b/core/java/android/app/timezonedetector/TEST_MAPPING index 2be5614b54a5..c8d0bb2306cd 100644 --- a/core/java/android/app/timezonedetector/TEST_MAPPING +++ b/core/java/android/app/timezonedetector/TEST_MAPPING @@ -15,10 +15,7 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] - } - ], - // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows. - "postsubmit": [ + }, { "name": "FrameworksTimeServicesTests", "options": [ diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java index 1ef15637d578..a4b17537f4b2 100644 --- a/core/java/android/app/usage/StorageStatsManager.java +++ b/core/java/android/app/usage/StorageStatsManager.java @@ -35,8 +35,6 @@ import android.os.UserHandle; import android.os.storage.CrateInfo; import android.os.storage.StorageManager; -import com.android.internal.util.Preconditions; - import java.io.File; import java.io.IOException; import java.util.Collection; @@ -77,7 +75,7 @@ public class StorageStatsManager { } } - /** @removed */ + /** {@hide} */ @Deprecated public boolean isQuotaSupported(String uuid) { return isQuotaSupported(convert(uuid)); @@ -120,7 +118,7 @@ public class StorageStatsManager { } } - /** @removed */ + /** {@hide} */ @Deprecated public long getTotalBytes(String uuid) throws IOException { return getTotalBytes(convert(uuid)); @@ -152,7 +150,7 @@ public class StorageStatsManager { } } - /** @removed */ + /** {@hide} */ @Deprecated public long getFreeBytes(String uuid) throws IOException { return getFreeBytes(convert(uuid)); @@ -221,7 +219,7 @@ public class StorageStatsManager { } } - /** @removed */ + /** {@hide} */ @Deprecated public StorageStats queryStatsForPackage(String uuid, String packageName, UserHandle user) throws PackageManager.NameNotFoundException, IOException { @@ -262,7 +260,7 @@ public class StorageStatsManager { } } - /** @removed */ + /** {@hide} */ @Deprecated public StorageStats queryStatsForUid(String uuid, int uid) throws IOException { return queryStatsForUid(convert(uuid), uid); @@ -300,7 +298,7 @@ public class StorageStatsManager { } } - /** @removed */ + /** {@hide} */ @Deprecated public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException { return queryStatsForUser(convert(uuid), user); @@ -337,7 +335,7 @@ public class StorageStatsManager { } } - /** @removed */ + /** {@hide} */ @Deprecated public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user) throws IOException { diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 1f25fd039dd8..32ecb58ce241 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -80,7 +80,7 @@ interface IPackageInstaller { long timeout); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES,android.Manifest.permission.REQUEST_DELETE_PACKAGES})") - void requestArchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle); + void requestArchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle, int flags); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})") void requestUnarchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index d35c3922e9b7..457fd63fa3d8 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -323,6 +323,14 @@ public class PackageInstaller { */ @SystemApi public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; + /** + * Key for passing extra delete flags during archiving. + * + * @hide + */ + @SystemApi + @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) + public static final String EXTRA_DELETE_FLAGS = "android.content.pm.extra.DELETE_FLAGS"; /** * Type of DataLoader for this session. Will be one of @@ -2330,6 +2338,7 @@ public class PackageInstaller { * communicated. * * @param statusReceiver Callback used to notify when the operation is completed. + * @param flags Flags for archiving. Can be 0 or {@link PackageManager#DELETE_SHOW_DIALOG}. * @throws PackageManager.NameNotFoundException If {@code packageName} isn't found or not * available to the caller or isn't archived. */ @@ -2337,11 +2346,12 @@ public class PackageInstaller { Manifest.permission.DELETE_PACKAGES, Manifest.permission.REQUEST_DELETE_PACKAGES}) @FlaggedApi(Flags.FLAG_ARCHIVING) - public void requestArchive(@NonNull String packageName, @NonNull IntentSender statusReceiver) + public void requestArchive(@NonNull String packageName, @NonNull IntentSender statusReceiver, + @DeleteFlags int flags) throws PackageManager.NameNotFoundException { try { mInstaller.requestArchive(packageName, mInstallerPackageName, statusReceiver, - new UserHandle(mUserId)); + new UserHandle(mUserId), flags); } catch (ParcelableException e) { e.maybeRethrow(PackageManager.NameNotFoundException.class); } catch (RemoteException e) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a22fe3f1452b..7bb673ac998d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2552,6 +2552,7 @@ public abstract class PackageManager { DELETE_SYSTEM_APP, DELETE_DONT_KILL_APP, DELETE_CHATTY, + DELETE_SHOW_DIALOG, }) @Retention(RetentionPolicy.SOURCE) public @interface DeleteFlags {} @@ -2595,15 +2596,21 @@ public abstract class PackageManager { public static final int DELETE_DONT_KILL_APP = 0x00000008; /** - * Flag parameter for {@link #deletePackage} to indicate that the deletion is an archival. This + * Flag parameter for {@link PackageInstaller#uninstall(VersionedPackage, int, IntentSender)} to + * indicate that the deletion is an archival. This * flag is only for internal usage as part of - * {@link PackageInstaller#requestArchive(String, IntentSender)}. - * - * @hide + * {@link PackageInstaller#requestArchive}. */ + @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) public static final int DELETE_ARCHIVE = 0x00000010; /** + * Show a confirmation dialog to the user when app is being deleted. + */ + @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) + public static final int DELETE_SHOW_DIALOG = 0x00000020; + + /** * Flag parameter for {@link #deletePackage} to indicate that package deletion * should be chatty. * @@ -8964,7 +8971,7 @@ public abstract class PackageManager { * Returns true if an app is archivable. * * @throws NameNotFoundException if the given package name is not available to the caller. - * @see PackageInstaller#requestArchive(String, IntentSender) + * @see PackageInstaller#requestArchive */ @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) public boolean isAppArchivable(@NonNull String packageName) throws NameNotFoundException { diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 12ab0f6e50e1..35f295a36d87 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -5226,6 +5226,60 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { new Key<android.hardware.camera2.params.OisSample[]>("android.statistics.oisSamples", android.hardware.camera2.params.OisSample[].class); /** + * <p>An array of intra-frame lens intrinsic samples.</p> + * <p>Contains an array of intra-frame {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} updates. This must + * not be confused or compared to {@link CaptureResult#STATISTICS_OIS_SAMPLES android.statistics.oisSamples}. Although OIS could be the + * main driver, all relevant factors such as focus distance and optical zoom must also + * be included. Do note that OIS samples must not be applied on top of the lens intrinsic + * samples. + * Support for this capture result can be queried via + * {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }. + * If available, clients can expect multiple samples per capture result. The specific + * amount will depend on current frame duration and sampling rate. Generally a sampling rate + * greater than or equal to 200Hz is considered sufficient for high quality results.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * + * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION + * @see CaptureResult#STATISTICS_OIS_SAMPLES + */ + @PublicKey + @NonNull + @SyntheticKey + @FlaggedApi(Flags.FLAG_CONCERT_MODE) + public static final Key<android.hardware.camera2.params.LensIntrinsicsSample[]> STATISTICS_LENS_INTRINSICS_SAMPLES = + new Key<android.hardware.camera2.params.LensIntrinsicsSample[]>("android.statistics.lensIntrinsicsSamples", android.hardware.camera2.params.LensIntrinsicsSample[].class); + + /** + * <p>An array of timestamps of lens intrinsics samples, in nanoseconds.</p> + * <p>The array contains the timestamps of lens intrinsics samples. The timestamps are in the + * same timebase as and comparable to {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp}.</p> + * <p><b>Units</b>: nanoseconds</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * + * @see CaptureResult#SENSOR_TIMESTAMP + * @hide + */ + @FlaggedApi(Flags.FLAG_CONCERT_MODE) + public static final Key<long[]> STATISTICS_LENS_INTRINSIC_TIMESTAMPS = + new Key<long[]>("android.statistics.lensIntrinsicTimestamps", long[].class); + + /** + * <p>An array of intra-frame lens intrinsics.</p> + * <p>The data layout and contents of individual array entries matches with + * {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}.</p> + * <p><b>Units</b>: + * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} coordinate system.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * + * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE + * @hide + */ + @FlaggedApi(Flags.FLAG_CONCERT_MODE) + public static final Key<float[]> STATISTICS_LENS_INTRINSIC_SAMPLES = + new Key<float[]>("android.statistics.lensIntrinsicSamples", float[].class); + + /** * <p>Tonemapping / contrast / gamma curve for the blue * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is * CONTRAST_CURVE.</p> @@ -5668,6 +5722,55 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { new Key<String>("android.logicalMultiCamera.activePhysicalId", String.class); /** + * <p>The current region of the active physical sensor that will be read out for this + * capture.</p> + * <p>This capture result matches with {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} on non-logical single + * camera sensor devices. In case of logical cameras that can switch between several + * physical devices in response to {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, this capture result will + * not behave like {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} and {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, where the + * combination of both reflects the effective zoom and crop of the logical camera output. + * Instead, this capture result value will describe the zoom and crop of the active physical + * device. Some examples of when the value of this capture result will change include + * switches between different physical lenses, switches between regular and maximum + * resolution pixel mode and going through the device digital or optical range. + * This capture result is similar to {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with respect to distortion + * correction. When the distortion correction mode is OFF, the coordinate system follows + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, with (0, 0) being the top-left pixel + * of the pre-correction active array. When the distortion correction mode is not OFF, + * the coordinate system follows {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with (0, 0) being + * the top-left pixel of the active array.</p> + * <p>For camera devices with the + * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR } + * capability or devices where {@link CameraCharacteristics#getAvailableCaptureRequestKeys } + * lists {@link CaptureRequest#SENSOR_PIXEL_MODE {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode}} + * , the current active physical device + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION android.sensor.info.activeArraySizeMaximumResolution} / + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION android.sensor.info.preCorrectionActiveArraySizeMaximumResolution} must be used as the + * coordinate system for requests where {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is set to + * {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }.</p> + * <p><b>Units</b>: Pixel coordinates relative to + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} of the currently + * {@link CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID android.logicalMultiCamera.activePhysicalId} depending on distortion correction capability + * and mode</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * + * @see CaptureRequest#CONTROL_ZOOM_RATIO + * @see CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID + * @see CaptureRequest#SCALER_CROP_REGION + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION + * @see CaptureRequest#SENSOR_PIXEL_MODE + */ + @PublicKey + @NonNull + @FlaggedApi(Flags.FLAG_CONCERT_MODE) + public static final Key<android.graphics.Rect> LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION = + new Key<android.graphics.Rect>("android.logicalMultiCamera.activePhysicalSensorCropRegion", android.graphics.Rect.class); + + /** * <p>Mode of operation for the lens distortion correction block.</p> * <p>The lens distortion correction block attempts to improve image quality by fixing * radial, tangential, or other geometric aberrations in the camera device's optics. If diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 9743c1f80f9d..3affb73d1075 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -55,6 +55,7 @@ import android.hardware.camera2.params.DeviceStateSensorOrientationMap; import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; +import android.hardware.camera2.params.LensIntrinsicsSample; import android.hardware.camera2.params.LensShadingMap; import android.hardware.camera2.params.MandatoryStreamCombination; import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap; @@ -849,6 +850,15 @@ public class CameraMetadataNative implements Parcelable { return (T) metadata.getMultiResolutionStreamConfigurationMap(); } }); + sGetCommandMap.put( + CaptureResult.STATISTICS_LENS_INTRINSICS_SAMPLES.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { + return (T) metadata.getLensIntrinsicSamples(); + } + }); } private int[] getAvailableFormats() { @@ -1780,6 +1790,56 @@ public class CameraMetadataNative implements Parcelable { return samples; } + private boolean setLensIntrinsicsSamples(LensIntrinsicsSample[] samples) { + if (samples == null) { + return false; + } + + long[] tsArray = new long[samples.length]; + float[] intrinsicsArray = new float[samples.length * 5]; + for (int i = 0; i < samples.length; i++) { + tsArray[i] = samples[i].getTimestamp(); + System.arraycopy(samples[i].getLensIntrinsics(), 0, intrinsicsArray, 5*i, 5); + + } + setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES, intrinsicsArray); + setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS, tsArray); + + return true; + } + + private LensIntrinsicsSample[] getLensIntrinsicSamples() { + long[] timestamps = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS); + float[] intrinsics = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES); + + if (timestamps == null) { + if (intrinsics != null) { + throw new AssertionError("timestamps is null but intrinsics is not"); + } + + return null; + } + + if (intrinsics == null) { + throw new AssertionError("timestamps is not null but intrinsics is"); + } else if((intrinsics.length % 5) != 0) { + throw new AssertionError("intrinsics are not multiple of 5"); + } + + if ((intrinsics.length / 5) != timestamps.length) { + throw new AssertionError(String.format( + "timestamps has %d entries but intrinsics has %d", timestamps.length, + intrinsics.length / 5)); + } + + LensIntrinsicsSample[] samples = new LensIntrinsicsSample[timestamps.length]; + for (int i = 0; i < timestamps.length; i++) { + float[] currentIntrinsic = Arrays.copyOfRange(intrinsics, 5*i, 5*i + 5); + samples[i] = new LensIntrinsicsSample(timestamps[i], currentIntrinsic); + } + return samples; + } + private Capability[] getExtendedSceneModeCapabilities() { int[] maxSizes = getBase(CameraCharacteristics.CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES); @@ -1947,6 +2007,15 @@ public class CameraMetadataNative implements Parcelable { metadata.setLensShadingMap((LensShadingMap) value); } }); + sSetCommandMap.put( + CaptureResult.STATISTICS_LENS_INTRINSICS_SAMPLES.getNativeKey(), + new SetCommand() { + @Override + @SuppressWarnings("unchecked") + public <T> void setValue(CameraMetadataNative metadata, T value) { + metadata.setLensIntrinsicsSamples((LensIntrinsicsSample []) value); + } + }); } private boolean setAvailableFormats(int[] value) { diff --git a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java new file mode 100644 index 000000000000..575cbfae34e3 --- /dev/null +++ b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java @@ -0,0 +1,125 @@ +/* + * 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 android.hardware.camera2.params; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.utils.HashCodeHelpers; +import android.text.TextUtils; + +import com.android.internal.camera.flags.Flags; +import com.android.internal.util.Preconditions; + +import java.util.Arrays; + +/** + * Immutable class to store an + * {@link CaptureResult#STATISTICS_LENS_INTRINSICS_SAMPLES lens intrinsics intra-frame sample}. + */ +@FlaggedApi(Flags.FLAG_CONCERT_MODE) +public final class LensIntrinsicsSample { + /** + * Create a new {@link LensIntrinsicsSample}. + * + * <p>{@link LensIntrinsicsSample} contains the timestamp and the + * {@link CaptureResult#LENS_INTRINSIC_CALIBRATION} sample. + * + * @param timestamp timestamp of the lens intrinsics sample. + * @param lensIntrinsics the lens intrinsic calibration for the sample. + * + * @throws IllegalArgumentException if lensIntrinsics length is different from 5 + */ + @FlaggedApi(Flags.FLAG_CONCERT_MODE) + public LensIntrinsicsSample(final long timestamp, @NonNull final float[] lensIntrinsics) { + mTimestampNs = timestamp; + Preconditions.checkArgument(lensIntrinsics.length == 5); + mLensIntrinsics = lensIntrinsics; + } + + /** + * Get the timestamp in nanoseconds. + * + *<p>The timestamps are in the same timebase as and comparable to + *{@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp}.</p> + * + * @return a long value (guaranteed to be finite) + */ + @FlaggedApi(Flags.FLAG_CONCERT_MODE) + public long getTimestamp() { + return mTimestampNs; + } + + /** + * Get the lens intrinsics calibration + * + * @return a floating point value (guaranteed to be finite) + * @see CaptureResult#LENS_INTRINSIC_CALIBRATION + */ + @FlaggedApi(Flags.FLAG_CONCERT_MODE) + @NonNull + public float[] getLensIntrinsics() { + return mLensIntrinsics; + } + + /** + * Check if this {@link LensIntrinsicsSample} is equal to another {@link LensIntrinsicsSample}. + * + * <p>Two samples are only equal if and only if each of the lens intrinsics are equal.</p> + * + * @return {@code true} if the objects were equal, {@code false} otherwise + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } else if (this == obj) { + return true; + } else if (obj instanceof LensIntrinsicsSample) { + final LensIntrinsicsSample other = (LensIntrinsicsSample) obj; + return mTimestampNs == other.mTimestampNs + && Arrays.equals(mLensIntrinsics, other.getLensIntrinsics()); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + int timestampHash = HashCodeHelpers.hashCode(((float)mTimestampNs)); + return HashCodeHelpers.hashCode(Arrays.hashCode(mLensIntrinsics), timestampHash); + } + + /** + * Return the LensIntrinsicsSample as a string representation. + * + * <p> {@code "LensIntrinsicsSample{timestamp:%l, sample:%s}"} represents the LensIntrinsics + * sample's timestamp, and calibration data.</p> + * + * @return string representation of {@link LensIntrinsicsSample} + */ + @Override + public String toString() { + return TextUtils.formatSimple("LensIntrinsicsSample{timestamp:%d, sample:%s}", mTimestampNs, + Arrays.toString(mLensIntrinsics)); + } + + private final long mTimestampNs; + private final float [] mLensIntrinsics; +} diff --git a/core/java/android/os/IHintSession.aidl b/core/java/android/os/IHintSession.aidl index 6b43e73d10e7..fe85da26e610 100644 --- a/core/java/android/os/IHintSession.aidl +++ b/core/java/android/os/IHintSession.aidl @@ -17,6 +17,8 @@ package android.os; +import android.os.WorkDuration; + /** {@hide} */ oneway interface IHintSession { void updateTargetWorkDuration(long targetDurationNanos); @@ -24,4 +26,5 @@ oneway interface IHintSession { void close(); void sendHint(int hint); void setMode(int mode, boolean enabled); + void reportActualWorkDuration2(in WorkDuration[] workDurations); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 86628d95b25a..f2930fe45295 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -27,6 +27,10 @@ import android.annotation.SuppressLint; import android.annotation.TestApi; import android.app.AppOpsManager; import android.compat.annotation.UnsupportedAppUsage; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass; +import android.ravenwood.annotation.RavenwoodReplace; +import android.ravenwood.annotation.RavenwoodThrow; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -228,6 +232,8 @@ import java.util.function.IntFunction; * {@link #readMap(Map, ClassLoader, Class, Class)}, * {@link #readSparseArray(ClassLoader, Class)}. */ +@RavenwoodKeepWholeClass +@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.Parcel_host") public final class Parcel { private static final boolean DEBUG_RECYCLE = false; @@ -382,8 +388,10 @@ public final class Parcel { @CriticalNative private static native void nativeMarkSensitive(long nativePtr); @FastNative + @RavenwoodThrow private static native void nativeMarkForBinder(long nativePtr, IBinder binder); @CriticalNative + @RavenwoodThrow private static native boolean nativeIsForRpc(long nativePtr); @CriticalNative private static native int nativeDataSize(long nativePtr); @@ -415,14 +423,17 @@ public final class Parcel { private static native int nativeWriteFloat(long nativePtr, float val); @CriticalNative private static native int nativeWriteDouble(long nativePtr, double val); + @RavenwoodThrow private static native void nativeSignalExceptionForError(int error); @FastNative private static native void nativeWriteString8(long nativePtr, String val); @FastNative private static native void nativeWriteString16(long nativePtr, String val); @FastNative + @RavenwoodThrow private static native void nativeWriteStrongBinder(long nativePtr, IBinder val); @FastNative + @RavenwoodThrow private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val); private static native byte[] nativeCreateByteArray(long nativePtr); @@ -441,8 +452,10 @@ public final class Parcel { @FastNative private static native String nativeReadString16(long nativePtr); @FastNative + @RavenwoodThrow private static native IBinder nativeReadStrongBinder(long nativePtr); @FastNative + @RavenwoodThrow private static native FileDescriptor nativeReadFileDescriptor(long nativePtr); private static native long nativeCreate(); @@ -452,7 +465,9 @@ public final class Parcel { private static native byte[] nativeMarshall(long nativePtr); private static native void nativeUnmarshall( long nativePtr, byte[] data, int offset, int length); + @RavenwoodThrow private static native int nativeCompareData(long thisNativePtr, long otherNativePtr); + @RavenwoodThrow private static native boolean nativeCompareDataInRange( long ptrA, int offsetA, long ptrB, int offsetB, int length); private static native void nativeAppendFrom( @@ -461,13 +476,17 @@ public final class Parcel { private static native boolean nativeHasFileDescriptors(long nativePtr); private static native boolean nativeHasFileDescriptorsInRange( long nativePtr, int offset, int length); + @RavenwoodThrow private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName); + @RavenwoodThrow private static native void nativeEnforceInterface(long nativePtr, String interfaceName); @CriticalNative + @RavenwoodThrow private static native boolean nativeReplaceCallingWorkSourceUid( long nativePtr, int workSourceUid); @CriticalNative + @RavenwoodThrow private static native int nativeReadCallingWorkSourceUid(long nativePtr); /** Last time exception with a stack trace was written */ @@ -476,6 +495,7 @@ public final class Parcel { private static final int WRITE_EXCEPTION_STACK_TRACE_THRESHOLD_MS = 1000; @CriticalNative + @RavenwoodThrow private static native long nativeGetOpenAshmemSize(long nativePtr); public final static Parcelable.Creator<String> STRING_CREATOR @@ -634,10 +654,12 @@ public final class Parcel { /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @RavenwoodThrow public static native long getGlobalAllocSize(); /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @RavenwoodThrow public static native long getGlobalAllocCount(); /** @@ -2918,6 +2940,7 @@ public final class Parcel { * @see #writeNoException * @see #readException */ + @RavenwoodReplace public final void writeException(@NonNull Exception e) { AppOpsManager.prefixParcelWithAppOpsIfNeeded(this); @@ -3017,6 +3040,7 @@ public final class Parcel { * @see #writeException * @see #readException */ + @RavenwoodReplace public final void writeNoException() { AppOpsManager.prefixParcelWithAppOpsIfNeeded(this); diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java index f2b60a4e3988..b5c09bb09f46 100644 --- a/core/java/android/os/Parcelable.java +++ b/core/java/android/os/Parcelable.java @@ -19,6 +19,7 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -86,6 +87,7 @@ import java.lang.annotation.RetentionPolicy; * } * }</pre></section></div></div> */ +@RavenwoodKeepWholeClass public interface Parcelable { /** @hide */ @IntDef(flag = true, prefix = { "PARCELABLE_" }, value = { diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java index 11084b88fad1..e0059105c21f 100644 --- a/core/java/android/os/PerformanceHintManager.java +++ b/core/java/android/os/PerformanceHintManager.java @@ -103,7 +103,7 @@ public final class PerformanceHintManager { * Any call in this class will change its internal data, so you must do your own thread * safety to protect from racing. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public static class Session implements Closeable { private long mNativeSessionPtr; @@ -269,6 +269,40 @@ public final class PerformanceHintManager { public @Nullable int[] getThreadIds() { return nativeGetThreadIds(mNativeSessionPtr); } + + /** + * Reports the work duration for the last cycle of work. + * + * The system will attempt to adjust the core placement of the threads within the thread + * group and/or the frequency of the core on which they are run to bring the actual duration + * close to the target duration. + * + * @param workDuration the work duration of each component. + * @throws IllegalArgumentException if work period start timestamp is not positive, or + * actual total duration is not positive, or actual CPU duration is not positive, + * or actual GPU duration is negative. + */ + @FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) + public void reportActualWorkDuration(@NonNull WorkDuration workDuration) { + if (workDuration.mWorkPeriodStartTimestampNanos <= 0) { + throw new IllegalArgumentException( + "the work period start timestamp should be positive."); + } + if (workDuration.mActualTotalDurationNanos <= 0) { + throw new IllegalArgumentException("the actual total duration should be positive."); + } + if (workDuration.mActualCpuDurationNanos <= 0) { + throw new IllegalArgumentException("the actual CPU duration should be positive."); + } + if (workDuration.mActualGpuDurationNanos < 0) { + throw new IllegalArgumentException( + "the actual GPU duration should be non negative."); + } + nativeReportActualWorkDuration(mNativeSessionPtr, + workDuration.mWorkPeriodStartTimestampNanos, + workDuration.mActualTotalDurationNanos, + workDuration.mActualCpuDurationNanos, workDuration.mActualGpuDurationNanos); + } } private static native long nativeAcquireManager(); @@ -285,4 +319,7 @@ public final class PerformanceHintManager { private static native void nativeSetThreads(long nativeSessionPtr, int[] tids); private static native void nativeSetPreferPowerEfficiency(long nativeSessionPtr, boolean enabled); + private static native void nativeReportActualWorkDuration(long nativeSessionPtr, + long workPeriodStartTimestampNanos, long actualTotalDurationNanos, + long actualCpuDurationNanos, long actualGpuDurationNanos); } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 11660f9930c3..7e07e1f2e499 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -853,6 +853,7 @@ public class Process { args.argi2 = pid; args.argi3 = Long.hashCode(Thread.currentThread().getId()); args.argi4 = THREAD_PRIORITY_DEFAULT; + args.arg1 = Boolean.TRUE; // backgroundOk return args; }); } @@ -1105,6 +1106,11 @@ public class Process { final SomeArgs args = Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); if (args.argi3 == tid) { + boolean backgroundOk = (args.arg1 == Boolean.TRUE); + if (priority >= THREAD_PRIORITY_BACKGROUND && !backgroundOk) { + throw new IllegalArgumentException( + "Priority " + priority + " blocked by setCanSelfBackground()"); + } args.argi4 = priority; } else { throw new UnsupportedOperationException( @@ -1119,8 +1125,16 @@ public class Process { * * @hide */ + @android.ravenwood.annotation.RavenwoodReplace public static final native void setCanSelfBackground(boolean backgroundOk); + /** @hide */ + public static final void setCanSelfBackground$ravenwood(boolean backgroundOk) { + final SomeArgs args = + Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); + args.arg1 = Boolean.valueOf(backgroundOk); + } + /** * Sets the scheduling group for a thread. * @hide diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java index 2e6cccbd435f..23bd30a21c4c 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.app.IAlarmManager; import android.app.time.UnixEpochTime; @@ -205,8 +206,8 @@ public final class SystemClock { * Returns nanoseconds since boot, not counting time spent in deep sleep. * * @return nanoseconds of non-sleep uptime since boot. - * @hide */ + @FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) @CriticalNative @android.ravenwood.annotation.RavenwoodReplace public static native long uptimeNanos(); diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 0d0d1da2fb7d..5d7e04d4ed26 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -444,7 +444,8 @@ public final class Trace { * these characters they will be replaced with a space character in the trace. * * @param sectionName The name of the code section to appear in the trace. This may be at - * most 127 Unicode code units long. + * most 127 Unicode code units long. + * @throws IllegalArgumentException if {@code sectionName} is too long. */ public static void beginSection(@NonNull String sectionName) { if (isTagEnabled(TRACE_TAG_APP)) { diff --git a/core/java/android/os/WorkDuration.aidl b/core/java/android/os/WorkDuration.aidl new file mode 100644 index 000000000000..0f61204d72c4 --- /dev/null +++ b/core/java/android/os/WorkDuration.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.os; + +parcelable WorkDuration cpp_header "android/WorkDuration.h";
\ No newline at end of file diff --git a/core/java/android/os/WorkDuration.java b/core/java/android/os/WorkDuration.java new file mode 100644 index 000000000000..4fdc34fb60d1 --- /dev/null +++ b/core/java/android/os/WorkDuration.java @@ -0,0 +1,213 @@ +/* + * 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 android.os; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; + +import java.util.Objects; + +/** + * WorkDuration contains the measured time in nano seconds of the workload + * in each component, see + * {@link PerformanceHintManager.Session#reportActualWorkDuration(WorkDuration)}. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ +@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) +public final class WorkDuration implements Parcelable { + long mWorkPeriodStartTimestampNanos = 0; + long mActualTotalDurationNanos = 0; + long mActualCpuDurationNanos = 0; + long mActualGpuDurationNanos = 0; + long mTimestampNanos = 0; + + public static final @NonNull Creator<WorkDuration> CREATOR = new Creator<>() { + @Override + public WorkDuration createFromParcel(Parcel in) { + return new WorkDuration(in); + } + + @Override + public WorkDuration[] newArray(int size) { + return new WorkDuration[size]; + } + }; + + public WorkDuration() {} + + public WorkDuration(long workPeriodStartTimestampNanos, + long actualTotalDurationNanos, + long actualCpuDurationNanos, + long actualGpuDurationNanos) { + mWorkPeriodStartTimestampNanos = workPeriodStartTimestampNanos; + mActualTotalDurationNanos = actualTotalDurationNanos; + mActualCpuDurationNanos = actualCpuDurationNanos; + mActualGpuDurationNanos = actualGpuDurationNanos; + } + + /** + * @hide + */ + public WorkDuration(long workPeriodStartTimestampNanos, + long actualTotalDurationNanos, + long actualCpuDurationNanos, + long actualGpuDurationNanos, + long timestampNanos) { + mWorkPeriodStartTimestampNanos = workPeriodStartTimestampNanos; + mActualTotalDurationNanos = actualTotalDurationNanos; + mActualCpuDurationNanos = actualCpuDurationNanos; + mActualGpuDurationNanos = actualGpuDurationNanos; + mTimestampNanos = timestampNanos; + } + + WorkDuration(@NonNull Parcel in) { + mWorkPeriodStartTimestampNanos = in.readLong(); + mActualTotalDurationNanos = in.readLong(); + mActualCpuDurationNanos = in.readLong(); + mActualGpuDurationNanos = in.readLong(); + mTimestampNanos = in.readLong(); + } + + /** + * Sets the work period start timestamp in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public void setWorkPeriodStartTimestampNanos(long workPeriodStartTimestampNanos) { + if (workPeriodStartTimestampNanos <= 0) { + throw new IllegalArgumentException( + "the work period start timestamp should be positive."); + } + mWorkPeriodStartTimestampNanos = workPeriodStartTimestampNanos; + } + + /** + * Sets the actual total duration in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public void setActualTotalDurationNanos(long actualTotalDurationNanos) { + if (actualTotalDurationNanos <= 0) { + throw new IllegalArgumentException("the actual total duration should be positive."); + } + mActualTotalDurationNanos = actualTotalDurationNanos; + } + + /** + * Sets the actual CPU duration in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public void setActualCpuDurationNanos(long actualCpuDurationNanos) { + if (actualCpuDurationNanos <= 0) { + throw new IllegalArgumentException("the actual CPU duration should be positive."); + } + mActualCpuDurationNanos = actualCpuDurationNanos; + } + + /** + * Sets the actual GPU duration in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public void setActualGpuDurationNanos(long actualGpuDurationNanos) { + if (actualGpuDurationNanos < 0) { + throw new IllegalArgumentException("the actual GPU duration should be non negative."); + } + mActualGpuDurationNanos = actualGpuDurationNanos; + } + + /** + * Returns the work period start timestamp based in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public long getWorkPeriodStartTimestampNanos() { + return mWorkPeriodStartTimestampNanos; + } + + /** + * Returns the actual total duration in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public long getActualTotalDurationNanos() { + return mActualTotalDurationNanos; + } + + /** + * Returns the actual CPU duration in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public long getActualCpuDurationNanos() { + return mActualCpuDurationNanos; + } + + /** + * Returns the actual GPU duration in nanoseconds. + * + * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + */ + public long getActualGpuDurationNanos() { + return mActualGpuDurationNanos; + } + + /** + * @hide + */ + public long getTimestampNanos() { + return mTimestampNanos; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mWorkPeriodStartTimestampNanos); + dest.writeLong(mActualTotalDurationNanos); + dest.writeLong(mActualCpuDurationNanos); + dest.writeLong(mActualGpuDurationNanos); + dest.writeLong(mTimestampNanos); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof WorkDuration)) { + return false; + } + WorkDuration workDuration = (WorkDuration) obj; + return workDuration.mTimestampNanos == this.mTimestampNanos + && workDuration.mWorkPeriodStartTimestampNanos == this.mWorkPeriodStartTimestampNanos + && workDuration.mActualTotalDurationNanos == this.mActualTotalDurationNanos + && workDuration.mActualCpuDurationNanos == this.mActualCpuDurationNanos + && workDuration.mActualGpuDurationNanos == this.mActualGpuDurationNanos; + } + + @Override + public int hashCode() { + return Objects.hash(mWorkPeriodStartTimestampNanos, mActualTotalDurationNanos, + mActualCpuDurationNanos, mActualGpuDurationNanos, mTimestampNanos); + } +} diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index c085f334457a..980c13c5c2d6 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -68,4 +68,11 @@ flag { namespace: "backstage_power" description: "Guards a new API in PowerManager to check if battery saver is supported or not." bug: "305067031" -}
\ No newline at end of file +} + +flag { + name: "adpf_gpu_report_actual_work_duration" + namespace: "game" + description: "Guards the ADPF GPU APIs." + bug: "284324521" +} diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index 28ef70b14026..0dc04133e664 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -8,13 +8,6 @@ flag { } flag { - name: "mgf1_digest_setter" - namespace: "hardware_backed_security" - description: "Feature flag for mgf1 digest setter in key generation and import parameters." - bug: "308378912" -} - -flag { name: "fix_unlocked_device_required_keys_v2" namespace: "hardware_backed_security" description: "Fix bugs in behavior of UnlockedDeviceRequired keystore keys" diff --git a/core/java/android/service/chooser/CustomChoosers.java b/core/java/android/service/chooser/CustomChoosers.java new file mode 100644 index 000000000000..5b89432b956d --- /dev/null +++ b/core/java/android/service/chooser/CustomChoosers.java @@ -0,0 +1,84 @@ +/* + * 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 android.service.chooser; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.content.Intent; +import android.content.pm.ResolveInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * Static helper methods that privileged clients can use to initiate Share sessions with extra + * customization options that aren't usually available in the stock "Resolver/Chooser" flows. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_SUPPORT_NFC_RESOLVER) +@SystemApi +public class CustomChoosers { + /** + * Intent action to start a Share session with additional customization options. Clients should + * use the helper methods in this class to configure their customized share intents, and should + * avoid using this action to construct their own intents directly. + */ + private static final String ACTION_SHOW_CUSTOMIZED_RESOLVER = + "android.service.chooser.action.SHOW_CUSTOMIZED_RESOLVER"; + + /** + * "Extras" key for an ArrayList of {@link ResolveInfo} records which are to be shown as the + * targets in the customized share session. + * + * @hide + */ + public static final String EXTRA_RESOLVE_INFOS = "android.service.chooser.extra.RESOLVE_INFOS"; + + /** + * Build an {@link Intent} to dispatch a "Chooser flow" that picks a target resolution for the + * specified {@code target} intent, styling the Chooser UI according to the specified + * customization parameters. + * + * @param target The ambiguous intent that should be resolved to a specific target selected + * via the Chooser flow. + * @param title An optional "headline" string to display at the top of the Chooser UI, or null + * to use the system default. + * @param resolutionList Explicit resolution info for targets that should be shown in the + * dispatched Share UI. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_SUPPORT_NFC_RESOLVER) + @SystemApi + @NonNull + public static Intent createNfcResolverIntent( + @NonNull Intent target, + @Nullable CharSequence title, + @NonNull List<ResolveInfo> resolutionList) { + Intent resolverIntent = new Intent(ACTION_SHOW_CUSTOMIZED_RESOLVER); + resolverIntent.putExtra(Intent.EXTRA_INTENT, target); + resolverIntent.putExtra(Intent.EXTRA_TITLE, title); + resolverIntent.putParcelableArrayListExtra( + EXTRA_RESOLVE_INFOS, new ArrayList<>(resolutionList)); + return resolverIntent; + } + + private CustomChoosers() {} +} diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java index 3a4a0c5dcd30..b1680abfadeb 100644 --- a/core/java/android/service/notification/ZenPolicy.java +++ b/core/java/android/service/notification/ZenPolicy.java @@ -1241,7 +1241,7 @@ public final class ZenPolicy implements Parcelable { * @hide */ public byte[] toProto() { - // TODO: b/308672510 - log new ZenPolicy fields to DNDPolicyProto. + // TODO: b/308672510 - log user-customized ZenPolicy fields to DNDPolicyProto. ByteArrayOutputStream bytes = new ByteArrayOutputStream(); ProtoOutputStream proto = new ProtoOutputStream(bytes); @@ -1267,6 +1267,10 @@ public final class ZenPolicy implements Parcelable { proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, getPriorityMessageSenders()); proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders()); + if (Flags.modesApi()) { + proto.write(DNDPolicyProto.ALLOW_CHANNELS, getAllowedChannels()); + } + proto.flush(); return bytes.toByteArray(); } diff --git a/core/java/android/service/timezone/TEST_MAPPING b/core/java/android/service/timezone/TEST_MAPPING index e5910ea4a1fa..bf46ff2ffe06 100644 --- a/core/java/android/service/timezone/TEST_MAPPING +++ b/core/java/android/service/timezone/TEST_MAPPING @@ -7,10 +7,7 @@ "include-filter": "android.service." } ] - } - ], - // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows. - "postsubmit": [ + }, { "name": "CtsLocationTimeZoneManagerHostTest" } diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java index e6fcc0c391b2..388f08a92c95 100644 --- a/core/java/android/speech/SpeechRecognizer.java +++ b/core/java/android/speech/SpeechRecognizer.java @@ -28,31 +28,15 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; -import android.os.Binder; import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.CloseGuard; -import android.util.Log; -import android.util.Slog; import com.android.internal.R; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.ref.Reference; import java.util.List; -import java.util.Objects; -import java.util.Queue; import java.util.concurrent.Executor; -import java.util.concurrent.LinkedBlockingQueue; /** * This class provides access to the speech recognition service. This service allows access to the @@ -72,11 +56,6 @@ import java.util.concurrent.LinkedBlockingQueue; * permission to use this class. */ public class SpeechRecognizer { - /** DEBUG value to enable verbose debug prints */ - private static final boolean DBG = false; - - /** Log messages identifier */ - private static final String TAG = "SpeechRecognizer"; /** * Key used to retrieve an {@code ArrayList<String>} from the {@link Bundle} passed to the @@ -303,106 +282,17 @@ public class SpeechRecognizer { private static final int MSG_CHECK_RECOGNITION_SUPPORT = 6; private static final int MSG_TRIGGER_MODEL_DOWNLOAD = 7; - /** The actual RecognitionService endpoint */ - private IRecognitionService mService; - - private final CloseGuard mCloseGuard = new CloseGuard(); - - /** Context with which the manager was created */ - private final Context mContext; - - /** Component to direct service intent to */ - private final ComponentName mServiceComponent; - - /** Whether to use on-device speech recognizer. */ - private final boolean mOnDevice; - - private IRecognitionServiceManager mManagerService; - - /** Handler that will execute the main tasks */ - private Handler mHandler = new Handler(Looper.getMainLooper()) { - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_START: - handleStartListening((Intent) msg.obj); - break; - case MSG_STOP: - handleStopMessage(); - break; - case MSG_CANCEL: - handleCancelMessage(); - break; - case MSG_CHANGE_LISTENER: - handleChangeListener((RecognitionListener) msg.obj); - break; - case MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT: - handleSetTemporaryComponent((ComponentName) msg.obj); - break; - case MSG_CHECK_RECOGNITION_SUPPORT: - CheckRecognitionSupportArgs args = (CheckRecognitionSupportArgs) msg.obj; - handleCheckRecognitionSupport( - args.mIntent, args.mCallbackExecutor, args.mCallback); - break; - case MSG_TRIGGER_MODEL_DOWNLOAD: - ModelDownloadListenerArgs modelDownloadListenerArgs = - (ModelDownloadListenerArgs) msg.obj; - handleTriggerModelDownload( - modelDownloadListenerArgs.mIntent, - modelDownloadListenerArgs.mExecutor, - modelDownloadListenerArgs.mModelDownloadListener); - break; - } - } - }; - - /** - * Temporary queue, saving the messages until the connection will be established, afterwards, - * only mHandler will receive the messages - */ - private final Queue<Message> mPendingTasks = new LinkedBlockingQueue<>(); - - /** The Listener that will receive all the callbacks */ - private final InternalRecognitionListener mListener = new InternalRecognitionListener(); - - private final IBinder mClientToken = new Binder(); - - /** - * The right way to create a {@code SpeechRecognizer} is by using - * {@link #createSpeechRecognizer} static factory method - */ - private SpeechRecognizer(final Context context, final ComponentName serviceComponent) { - this(context, serviceComponent, false); - } - - /** - * The right way to create a {@code SpeechRecognizer} is by using - * {@link #createOnDeviceSpeechRecognizer} static factory method - */ - private SpeechRecognizer(final Context context, boolean onDevice) { - this(context, null, onDevice); - } - - private SpeechRecognizer( - final Context context, - final ComponentName serviceComponent, - final boolean onDevice) { - mContext = context; - mServiceComponent = serviceComponent; - mOnDevice = onDevice; - mCloseGuard.open("SpeechRecognizer#destroy()"); - } + SpeechRecognizer() { } /** * Checks whether a speech recognition service is available on the system. If this method * returns {@code false}, {@link SpeechRecognizer#createSpeechRecognizer(Context)} will * fail. - * + * * @param context with which {@code SpeechRecognizer} will be created * @return {@code true} if recognition is available, {@code false} otherwise */ - public static boolean isRecognitionAvailable(@NonNull final Context context) { + public static boolean isRecognitionAvailable(@NonNull Context context) { // TODO(b/176578753): make sure this works well with system speech recognizers. final List<ResolveInfo> list = context.getPackageManager().queryIntentServices( new Intent(RecognitionService.SERVICE_INTERFACE), 0); @@ -418,7 +308,7 @@ public class SpeechRecognizer { * @param context with which on-device {@code SpeechRecognizer} will be created * @return {@code true} if on-device recognition is available, {@code false} otherwise */ - public static boolean isOnDeviceRecognitionAvailable(@NonNull final Context context) { + public static boolean isOnDeviceRecognitionAvailable(@NonNull Context context) { ComponentName componentName = ComponentName.unflattenFromString( context.getString(R.string.config_defaultOnDeviceSpeechRecognitionService)); @@ -449,7 +339,7 @@ public class SpeechRecognizer { * @return a new {@code SpeechRecognizer} */ @MainThread - public static SpeechRecognizer createSpeechRecognizer(final Context context) { + public static SpeechRecognizer createSpeechRecognizer(Context context) { return createSpeechRecognizer(context, null); } @@ -483,19 +373,19 @@ public class SpeechRecognizer { * </queries> * }</pre> * - * @param context in which to create {@code SpeechRecognizer} + * @param context in which to create {@code SpeechRecognizer} * @param serviceComponent the {@link ComponentName} of a specific service to direct this - * {@code SpeechRecognizer} to + * {@code SpeechRecognizer} to * @return a new {@code SpeechRecognizer} */ @MainThread - public static SpeechRecognizer createSpeechRecognizer(final Context context, - final ComponentName serviceComponent) { + public static SpeechRecognizer createSpeechRecognizer(Context context, + ComponentName serviceComponent) { if (context == null) { throw new IllegalArgumentException("Context cannot be null"); } - checkIsCalledFromMainThread(); - return new SpeechRecognizer(context, serviceComponent); + SpeechRecognizerImpl.checkIsCalledFromMainThread(); + return wrapWithProxy(new SpeechRecognizerImpl(context, serviceComponent)); } /** @@ -515,11 +405,15 @@ public class SpeechRecognizer { */ @NonNull @MainThread - public static SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull final Context context) { + public static SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull Context context) { if (!isOnDeviceRecognitionAvailable(context)) { throw new UnsupportedOperationException("On-device recognition is not available"); } - return lenientlyCreateOnDeviceSpeechRecognizer(context); + return wrapWithProxy(SpeechRecognizerImpl.lenientlyCreateOnDeviceSpeechRecognizer(context)); + } + + private static SpeechRecognizer wrapWithProxy(SpeechRecognizer delegate) { + return new SpeechRecognizerProxy(delegate); } /** @@ -532,42 +426,21 @@ public class SpeechRecognizer { @NonNull @MainThread public static SpeechRecognizer createOnDeviceTestingSpeechRecognizer( - @NonNull final Context context) { - return lenientlyCreateOnDeviceSpeechRecognizer(context); - } - - @NonNull - @MainThread - private static SpeechRecognizer lenientlyCreateOnDeviceSpeechRecognizer( - @NonNull final Context context) { - if (context == null) { - throw new IllegalArgumentException("Context cannot be null"); - } - checkIsCalledFromMainThread(); - return new SpeechRecognizer(context, /* onDevice */ true); + @NonNull Context context) { + return wrapWithProxy(SpeechRecognizerImpl.lenientlyCreateOnDeviceSpeechRecognizer(context)); } /** * Sets the listener that will receive all the callbacks. The previous unfinished commands will * be executed with the old listener, while any following command will be executed with the new * listener. - * + * * @param listener listener that will receive all the callbacks from the created - * {@link SpeechRecognizer}, this must not be null. + * {@link SpeechRecognizer}, this must not be null. */ @MainThread public void setRecognitionListener(RecognitionListener listener) { - checkIsCalledFromMainThread(); - if (mListener.mInternalListener == null) { - // This shortcut is needed because otherwise, if there's an error connecting, it never - // gets delivered. I.e., the onSuccess callback set up in connectToSystemService does - // not get called, MSG_CHANGE_LISTENER does not get executed, so the onError in the same - // place does not get forwarded anywhere. - // Thread-wise, this is safe as both this method and the handler are on the UI thread. - handleChangeListener(listener); - } else { - putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener)); - } + throw new UnsupportedOperationException(); } /** @@ -576,28 +449,13 @@ public class SpeechRecognizer { * no notifications will be received. * * @param recognizerIntent contains parameters for the recognition to be performed. The intent - * may also contain optional extras, see {@link RecognizerIntent}. If these values are - * not set explicitly, default values will be used by the recognizer. + * may also contain optional extras, see {@link RecognizerIntent}. If + * these values are not set explicitly, default values will be used by + * the recognizer. */ @MainThread - public void startListening(final Intent recognizerIntent) { - if (recognizerIntent == null) { - throw new IllegalArgumentException("intent must not be null"); - } - checkIsCalledFromMainThread(); - - if (DBG) { - Slog.i(TAG, "#startListening called"); - if (mService == null) { - Slog.i(TAG, "Connection is not established yet"); - } - } - - if (mService == null) { - // First time connection: first establish a connection, then dispatch #startListening. - connectToSystemService(); - } - putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent)); + public void startListening(Intent recognizerIntent) { + throw new UnsupportedOperationException(); } /** @@ -621,16 +479,7 @@ public class SpeechRecognizer { */ @MainThread public void stopListening() { - checkIsCalledFromMainThread(); - - if (DBG) { - Slog.i(TAG, "#stopListening called"); - if (mService == null) { - Slog.i(TAG, "Connection is not established yet"); - } - } - - putMessage(Message.obtain(mHandler, MSG_STOP)); + throw new UnsupportedOperationException(); } /** @@ -640,8 +489,7 @@ public class SpeechRecognizer { */ @MainThread public void cancel() { - checkIsCalledFromMainThread(); - putMessage(Message.obtain(mHandler, MSG_CANCEL)); + throw new UnsupportedOperationException(); } /** @@ -649,30 +497,15 @@ public class SpeechRecognizer { * {@link SpeechRecognizer#startListening(Intent)}. * * @param recognizerIntent contains parameters for the recognition to be performed. The intent - * may also contain optional extras. See {@link RecognizerIntent} for the list of - * supported extras, any unlisted extra might be ignored. - * @param supportListener the listener on which to receive the support query results. + * may also contain optional extras. See {@link RecognizerIntent} for + * the list of supported extras, any unlisted extra might be ignored. + * @param supportListener the listener on which to receive the support query results. */ public void checkRecognitionSupport( @NonNull Intent recognizerIntent, @NonNull @CallbackExecutor Executor executor, @NonNull RecognitionSupportCallback supportListener) { - Objects.requireNonNull(recognizerIntent, "intent must not be null"); - Objects.requireNonNull(supportListener, "listener must not be null"); - - if (DBG) { - Slog.i(TAG, "#checkRecognitionSupport called"); - if (mService == null) { - Slog.i(TAG, "Connection is not established yet"); - } - } - - if (mService == null) { - // First time connection: first establish a connection, then dispatch. - connectToSystemService(); - } - putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT, - new CheckRecognitionSupportArgs(recognizerIntent, executor, supportListener))); + throw new UnsupportedOperationException(); } /** @@ -681,23 +514,10 @@ public class SpeechRecognizer { * {@link #checkRecognitionSupport(Intent, Executor, RecognitionSupportCallback)}. * * @param recognizerIntent contains parameters for the recognition to be performed. The intent - * may also contain optional extras, see {@link RecognizerIntent}. + * may also contain optional extras, see {@link RecognizerIntent}. */ public void triggerModelDownload(@NonNull Intent recognizerIntent) { - Objects.requireNonNull(recognizerIntent, "intent must not be null"); - if (DBG) { - Slog.i(TAG, "#triggerModelDownload without a listener called"); - if (mService == null) { - Slog.i(TAG, "Connection is not established yet"); - } - } - if (mService == null) { - // First time connection: first establish a connection, then dispatch. - connectToSystemService(); - } - putMessage(Message.obtain( - mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, - new ModelDownloadListenerArgs(recognizerIntent, null, null))); + throw new UnsupportedOperationException(); } /** @@ -725,28 +545,15 @@ public class SpeechRecognizer { * {@link ModelDownloadListener#onError(int)} will be called. * * @param recognizerIntent contains parameters for the recognition to be performed. The intent - * may also contain optional extras, see {@link RecognizerIntent}. - * @param executor for dispatching listener callbacks - * @param listener on which to receive updates about the model download request. + * may also contain optional extras, see {@link RecognizerIntent}. + * @param executor for dispatching listener callbacks + * @param listener on which to receive updates about the model download request. */ public void triggerModelDownload( @NonNull Intent recognizerIntent, @NonNull @CallbackExecutor Executor executor, @NonNull ModelDownloadListener listener) { - Objects.requireNonNull(recognizerIntent, "intent must not be null"); - if (DBG) { - Slog.i(TAG, "#triggerModelDownload with a listener called"); - if (mService == null) { - Slog.i(TAG, "Connection is not established yet"); - } - } - if (mService == null) { - // First time connection: first establish a connection, then dispatch. - connectToSystemService(); - } - putMessage(Message.obtain( - mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, - new ModelDownloadListenerArgs(recognizerIntent, executor, listener))); + throw new UnsupportedOperationException(); } /** @@ -755,479 +562,19 @@ public class SpeechRecognizer { * <p>This is only expected to be called in tests, system would reject calls from client apps. * * @param componentName name of the component to set temporary replace speech recognizer. {@code - * null} value resets the recognizer to default. - * + * null} value resets the recognizer to default. * @hide */ @TestApi @RequiresPermission(Manifest.permission.MANAGE_SPEECH_RECOGNITION) public void setTemporaryOnDeviceRecognizer(@Nullable ComponentName componentName) { - mHandler.sendMessage( - Message.obtain(mHandler, MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT, componentName)); - } - - private static void checkIsCalledFromMainThread() { - if (Looper.myLooper() != Looper.getMainLooper()) { - throw new RuntimeException( - "SpeechRecognizer should be used only from the application's main thread"); - } - } - - private void putMessage(Message msg) { - if (mService == null) { - mPendingTasks.offer(msg); - } else { - mHandler.sendMessage(msg); - } - } - - /** sends the actual message to the service */ - private void handleStartListening(Intent recognizerIntent) { - if (!checkOpenConnection()) { - return; - } - try { - mService.startListening(recognizerIntent, mListener, mContext.getAttributionSource()); - if (DBG) Log.d(TAG, "service start listening command succeeded"); - } catch (final Exception e) { - Log.e(TAG, "startListening() failed", e); - mListener.onError(ERROR_CLIENT); - } - } - - /** sends the actual message to the service */ - private void handleStopMessage() { - if (!checkOpenConnection()) { - return; - } - try { - mService.stopListening(mListener); - if (DBG) Log.d(TAG, "service stop listening command succeeded"); - } catch (final Exception e) { - Log.e(TAG, "stopListening() failed", e); - mListener.onError(ERROR_CLIENT); - } - } - - /** sends the actual message to the service */ - private void handleCancelMessage() { - if (!checkOpenConnection()) { - return; - } - try { - mService.cancel(mListener, /*isShutdown*/ false); - if (DBG) Log.d(TAG, "service cancel command succeeded"); - } catch (final Exception e) { - Log.e(TAG, "cancel() failed", e); - mListener.onError(ERROR_CLIENT); - } - } - - private void handleSetTemporaryComponent(ComponentName componentName) { - if (DBG) { - Log.d(TAG, "handleSetTemporaryComponent, componentName=" + componentName); - } - - if (!maybeInitializeManagerService()) { - return; - } - - try { - mManagerService.setTemporaryComponent(componentName); - } catch (final RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - private void handleCheckRecognitionSupport( - Intent recognizerIntent, - Executor callbackExecutor, - RecognitionSupportCallback recognitionSupportCallback) { - if (!maybeInitializeManagerService() || !checkOpenConnection()) { - return; - } - try { - mService.checkRecognitionSupport( - recognizerIntent, - mContext.getAttributionSource(), - new InternalSupportCallback(callbackExecutor, recognitionSupportCallback)); - if (DBG) Log.d(TAG, "service support command succeeded"); - } catch (final Exception e) { - Log.e(TAG, "checkRecognitionSupport() failed", e); - callbackExecutor.execute(() -> recognitionSupportCallback.onError(ERROR_CLIENT)); - } - } - - private void handleTriggerModelDownload( - Intent recognizerIntent, - @Nullable Executor callbackExecutor, - @Nullable ModelDownloadListener modelDownloadListener) { - if (!maybeInitializeManagerService() || !checkOpenConnection()) { - return; - } - - // Trigger model download without a listener. - if (modelDownloadListener == null) { - try { - mService.triggerModelDownload( - recognizerIntent, mContext.getAttributionSource(), null); - if (DBG) Log.d(TAG, "triggerModelDownload() without a listener"); - } catch (final Exception e) { - Log.e(TAG, "triggerModelDownload() without a listener failed", e); - mListener.onError(ERROR_CLIENT); - } - } - // Trigger model download with a listener. - else { - try { - mService.triggerModelDownload( - recognizerIntent, mContext.getAttributionSource(), - new InternalModelDownloadListener(callbackExecutor, modelDownloadListener)); - if (DBG) Log.d(TAG, "triggerModelDownload() with a listener"); - } catch (final Exception e) { - Log.e(TAG, "triggerModelDownload() with a listener failed", e); - callbackExecutor.execute(() -> modelDownloadListener.onError(ERROR_CLIENT)); - } - } - } - - private boolean checkOpenConnection() { - if (mService != null && mService.asBinder().isBinderAlive()) { - return true; - } - mListener.onError(ERROR_CLIENT); - Log.e(TAG, "not connected to the recognition service"); - return false; - } - - /** changes the listener */ - private void handleChangeListener(RecognitionListener listener) { - if (DBG) Log.d(TAG, "handleChangeListener, listener=" + listener); - mListener.mInternalListener = listener; - } - - /** Destroys the {@code SpeechRecognizer} object. */ - public void destroy() { - try { - if (mService != null) { - try { - mService.cancel(mListener, /*isShutdown*/ true); - } catch (final Exception e) { - // Not important - } - } - - mService = null; - mPendingTasks.clear(); - mListener.mInternalListener = null; - mCloseGuard.close(); - } finally { - Reference.reachabilityFence(this); - } - } - - @Override - protected void finalize() throws Throwable { - try { - mCloseGuard.warnIfOpen(); - destroy(); - } finally { - super.finalize(); - } - } - - /** Establishes a connection to system server proxy and initializes the session. */ - private void connectToSystemService() { - if (!maybeInitializeManagerService()) { - return; - } - - ComponentName componentName = getSpeechRecognizerComponentName(); - - if (!mOnDevice && componentName == null) { - mListener.onError(ERROR_CLIENT); - return; - } - - try { - mManagerService.createSession( - componentName, - mClientToken, - mOnDevice, - new IRecognitionServiceManagerCallback.Stub(){ - @Override - public void onSuccess(IRecognitionService service) throws RemoteException { - if (DBG) { - Log.i(TAG, "Connected to speech recognition service"); - } - mService = service; - while (!mPendingTasks.isEmpty()) { - mHandler.sendMessage(mPendingTasks.poll()); - } - } - - @Override - public void onError(int errorCode) throws RemoteException { - Log.e(TAG, "Bind to system recognition service failed with error " - + errorCode); - mListener.onError(errorCode); - } - }); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - private synchronized boolean maybeInitializeManagerService() { - if (DBG) { - Log.i(TAG, "#maybeInitializeManagerService found = " + mManagerService); - } - if (mManagerService != null) { - return true; - } - - IBinder service = ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE); - if (service == null && mOnDevice) { - service = (IBinder) mContext.getSystemService(Context.SPEECH_RECOGNITION_SERVICE); - } - mManagerService = IRecognitionServiceManager.Stub.asInterface(service); - - if (mManagerService == null) { - if (mListener != null) { - mListener.onError(ERROR_CLIENT); - } - return false; - } - return true; + throw new UnsupportedOperationException(); } /** - * Returns the component name to be used for establishing a connection, based on the parameters - * used during initialization. - * - * <p>Note the 3 different scenarios: - * <ol> - * <li>On-device speech recognizer which is determined by the manufacturer and not - * changeable by the user - * <li>Default user-selected speech recognizer as specified by - * {@code Settings.Secure.VOICE_RECOGNITION_SERVICE} - * <li>Custom speech recognizer supplied by the client. + * Destroys the {@code SpeechRecognizer} object. */ - private ComponentName getSpeechRecognizerComponentName() { - if (mOnDevice) { - return null; - } - - if (mServiceComponent != null) { - return mServiceComponent; - } - - String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE); - - if (TextUtils.isEmpty(serviceComponent)) { - Log.e(TAG, "no selected voice recognition service"); - mListener.onError(ERROR_CLIENT); - return null; - } - - return ComponentName.unflattenFromString(serviceComponent); - } - - private static class CheckRecognitionSupportArgs { - final Intent mIntent; - final Executor mCallbackExecutor; - final RecognitionSupportCallback mCallback; - - private CheckRecognitionSupportArgs( - Intent intent, - Executor callbackExecutor, - RecognitionSupportCallback callback) { - mIntent = intent; - mCallbackExecutor = callbackExecutor; - mCallback = callback; - } - } - - private static class ModelDownloadListenerArgs { - final Intent mIntent; - final Executor mExecutor; - final ModelDownloadListener mModelDownloadListener; - - private ModelDownloadListenerArgs(Intent intent, Executor executor, - ModelDownloadListener modelDownloadListener) { - mIntent = intent; - mExecutor = executor; - mModelDownloadListener = modelDownloadListener; - } - } - - /** - * Internal wrapper of IRecognitionListener which will propagate the results to - * RecognitionListener - */ - private static class InternalRecognitionListener extends IRecognitionListener.Stub { - private RecognitionListener mInternalListener; - - private static final int MSG_BEGINNING_OF_SPEECH = 1; - private static final int MSG_BUFFER_RECEIVED = 2; - private static final int MSG_END_OF_SPEECH = 3; - private static final int MSG_ERROR = 4; - private static final int MSG_READY_FOR_SPEECH = 5; - private static final int MSG_RESULTS = 6; - private static final int MSG_PARTIAL_RESULTS = 7; - private static final int MSG_RMS_CHANGED = 8; - private static final int MSG_ON_EVENT = 9; - private static final int MSG_SEGMENT_RESULTS = 10; - private static final int MSG_SEGMENT_END_SESSION = 11; - private static final int MSG_LANGUAGE_DETECTION = 12; - - private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - if (mInternalListener == null) { - return; - } - switch (msg.what) { - case MSG_BEGINNING_OF_SPEECH: - mInternalListener.onBeginningOfSpeech(); - break; - case MSG_BUFFER_RECEIVED: - mInternalListener.onBufferReceived((byte[]) msg.obj); - break; - case MSG_END_OF_SPEECH: - mInternalListener.onEndOfSpeech(); - break; - case MSG_ERROR: - mInternalListener.onError((Integer) msg.obj); - break; - case MSG_READY_FOR_SPEECH: - mInternalListener.onReadyForSpeech((Bundle) msg.obj); - break; - case MSG_RESULTS: - mInternalListener.onResults((Bundle) msg.obj); - break; - case MSG_PARTIAL_RESULTS: - mInternalListener.onPartialResults((Bundle) msg.obj); - break; - case MSG_RMS_CHANGED: - mInternalListener.onRmsChanged((Float) msg.obj); - break; - case MSG_ON_EVENT: - mInternalListener.onEvent(msg.arg1, (Bundle) msg.obj); - break; - case MSG_SEGMENT_RESULTS: - mInternalListener.onSegmentResults((Bundle) msg.obj); - break; - case MSG_SEGMENT_END_SESSION: - mInternalListener.onEndOfSegmentedSession(); - break; - case MSG_LANGUAGE_DETECTION: - mInternalListener.onLanguageDetection((Bundle) msg.obj); - break; - } - } - }; - - public void onBeginningOfSpeech() { - Message.obtain(mInternalHandler, MSG_BEGINNING_OF_SPEECH).sendToTarget(); - } - - public void onBufferReceived(final byte[] buffer) { - Message.obtain(mInternalHandler, MSG_BUFFER_RECEIVED, buffer).sendToTarget(); - } - - public void onEndOfSpeech() { - Message.obtain(mInternalHandler, MSG_END_OF_SPEECH).sendToTarget(); - } - - public void onError(final int error) { - Message.obtain(mInternalHandler, MSG_ERROR, error).sendToTarget(); - } - - public void onReadyForSpeech(final Bundle noiseParams) { - Message.obtain(mInternalHandler, MSG_READY_FOR_SPEECH, noiseParams).sendToTarget(); - } - - public void onResults(final Bundle results) { - Message.obtain(mInternalHandler, MSG_RESULTS, results).sendToTarget(); - } - - public void onPartialResults(final Bundle results) { - Message.obtain(mInternalHandler, MSG_PARTIAL_RESULTS, results).sendToTarget(); - } - - public void onRmsChanged(final float rmsdB) { - Message.obtain(mInternalHandler, MSG_RMS_CHANGED, rmsdB).sendToTarget(); - } - - public void onSegmentResults(final Bundle bundle) { - Message.obtain(mInternalHandler, MSG_SEGMENT_RESULTS, bundle).sendToTarget(); - } - - public void onEndOfSegmentedSession() { - Message.obtain(mInternalHandler, MSG_SEGMENT_END_SESSION).sendToTarget(); - } - - public void onLanguageDetection(final Bundle results) { - Message.obtain(mInternalHandler, MSG_LANGUAGE_DETECTION, results).sendToTarget(); - } - - public void onEvent(final int eventType, final Bundle params) { - Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params) - .sendToTarget(); - } - } - - private static class InternalSupportCallback extends IRecognitionSupportCallback.Stub { - private final Executor mExecutor; - private final RecognitionSupportCallback mCallback; - - private InternalSupportCallback(Executor executor, RecognitionSupportCallback callback) { - this.mExecutor = executor; - this.mCallback = callback; - } - - @Override - public void onSupportResult(RecognitionSupport recognitionSupport) throws RemoteException { - mExecutor.execute(() -> mCallback.onSupportResult(recognitionSupport)); - } - - @Override - public void onError(int errorCode) throws RemoteException { - mExecutor.execute(() -> mCallback.onError(errorCode)); - } - } - - private static class InternalModelDownloadListener extends IModelDownloadListener.Stub { - private final Executor mExecutor; - private final ModelDownloadListener mModelDownloadListener; - - private InternalModelDownloadListener( - Executor executor, - @NonNull ModelDownloadListener modelDownloadListener) { - mExecutor = executor; - mModelDownloadListener = modelDownloadListener; - } - - @Override - public void onProgress(int completedPercent) throws RemoteException { - mExecutor.execute(() -> mModelDownloadListener.onProgress(completedPercent)); - } - - @Override - public void onSuccess() throws RemoteException { - mExecutor.execute(() -> mModelDownloadListener.onSuccess()); - } - - @Override - public void onScheduled() throws RemoteException { - mExecutor.execute(() -> mModelDownloadListener.onScheduled()); - } - - @Override - public void onError(int error) throws RemoteException { - mExecutor.execute(() -> mModelDownloadListener.onError(error)); - } + public void destroy() { + throw new UnsupportedOperationException(); } } diff --git a/core/java/android/speech/SpeechRecognizerImpl.java b/core/java/android/speech/SpeechRecognizerImpl.java new file mode 100644 index 000000000000..6c008743f07a --- /dev/null +++ b/core/java/android/speech/SpeechRecognizerImpl.java @@ -0,0 +1,745 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.speech; + +import android.Manifest; +import android.annotation.CallbackExecutor; +import android.annotation.MainThread; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.util.Slog; + +import java.util.Objects; +import java.util.Queue; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * @hide + */ +class SpeechRecognizerImpl extends SpeechRecognizer { + /** DEBUG value to enable verbose debug prints */ + private static final boolean DBG = false; + + /** Log messages identifier */ + private static final String TAG = "SpeechRecognizer"; + + /** action codes */ + private static final int MSG_START = 1; + private static final int MSG_STOP = 2; + private static final int MSG_CANCEL = 3; + private static final int MSG_CHANGE_LISTENER = 4; + private static final int MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT = 5; + private static final int MSG_CHECK_RECOGNITION_SUPPORT = 6; + private static final int MSG_TRIGGER_MODEL_DOWNLOAD = 7; + + /** The actual RecognitionService endpoint */ + private IRecognitionService mService; + + /** Context with which the manager was created */ + private final Context mContext; + + /** Component to direct service intent to */ + private final ComponentName mServiceComponent; + + /** Whether to use on-device speech recognizer. */ + private final boolean mOnDevice; + + private IRecognitionServiceManager mManagerService; + + /** Handler that will execute the main tasks */ + private Handler mHandler = new Handler(Looper.getMainLooper()) { + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_START: + handleStartListening((Intent) msg.obj); + break; + case MSG_STOP: + handleStopMessage(); + break; + case MSG_CANCEL: + handleCancelMessage(); + break; + case MSG_CHANGE_LISTENER: + handleChangeListener((RecognitionListener) msg.obj); + break; + case MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT: + handleSetTemporaryComponent((ComponentName) msg.obj); + break; + case MSG_CHECK_RECOGNITION_SUPPORT: + CheckRecognitionSupportArgs args = (CheckRecognitionSupportArgs) msg.obj; + handleCheckRecognitionSupport( + args.mIntent, args.mCallbackExecutor, args.mCallback); + break; + case MSG_TRIGGER_MODEL_DOWNLOAD: + ModelDownloadListenerArgs modelDownloadListenerArgs = + (ModelDownloadListenerArgs) msg.obj; + handleTriggerModelDownload( + modelDownloadListenerArgs.mIntent, + modelDownloadListenerArgs.mExecutor, + modelDownloadListenerArgs.mModelDownloadListener); + break; + } + } + }; + + /** + * Temporary queue, saving the messages until the connection will be established, afterwards, + * only mHandler will receive the messages + */ + private final Queue<Message> mPendingTasks = new LinkedBlockingQueue<>(); + + /** The Listener that will receive all the callbacks */ + private final InternalRecognitionListener mListener = new InternalRecognitionListener(); + + private final IBinder mClientToken = new Binder(); + + /** + * The right way to create a {@code SpeechRecognizer} is by using + * {@link #createSpeechRecognizer} static factory method + */ + /* package */ SpeechRecognizerImpl( + final Context context, + final ComponentName serviceComponent) { + this(context, serviceComponent, false); + } + + /** + * The right way to create a {@code SpeechRecognizer} is by using + * {@link #createOnDeviceSpeechRecognizer} static factory method + */ + /* package */ SpeechRecognizerImpl(final Context context, boolean onDevice) { + this(context, null, onDevice); + } + + private SpeechRecognizerImpl( + final Context context, + final ComponentName serviceComponent, + final boolean onDevice) { + mContext = context; + mServiceComponent = serviceComponent; + mOnDevice = onDevice; + } + + @NonNull + @MainThread + /* package */ static SpeechRecognizerImpl lenientlyCreateOnDeviceSpeechRecognizer( + @NonNull final Context context) { + if (context == null) { + throw new IllegalArgumentException("Context cannot be null"); + } + checkIsCalledFromMainThread(); + return new SpeechRecognizerImpl(context, /* onDevice */ true); + } + + @Override + @MainThread + public void setRecognitionListener(RecognitionListener listener) { + checkIsCalledFromMainThread(); + if (mListener.mInternalListener == null) { + // This shortcut is needed because otherwise, if there's an error connecting, it never + // gets delivered. I.e., the onSuccess callback set up in connectToSystemService does + // not get called, MSG_CHANGE_LISTENER does not get executed, so the onError in the same + // place does not get forwarded anywhere. + // Thread-wise, this is safe as both this method and the handler are on the UI thread. + handleChangeListener(listener); + } else { + putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener)); + } + } + + @Override + @MainThread + public void startListening(final Intent recognizerIntent) { + if (recognizerIntent == null) { + throw new IllegalArgumentException("intent must not be null"); + } + checkIsCalledFromMainThread(); + + if (DBG) { + Slog.i(TAG, "#startListening called"); + if (mService == null) { + Slog.i(TAG, "Connection is not established yet"); + } + } + + if (mService == null) { + // First time connection: first establish a connection, then dispatch #startListening. + connectToSystemService(); + } + putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent)); + } + + @Override + @MainThread + public void stopListening() { + checkIsCalledFromMainThread(); + + if (DBG) { + Slog.i(TAG, "#stopListening called"); + if (mService == null) { + Slog.i(TAG, "Connection is not established yet"); + } + } + + putMessage(Message.obtain(mHandler, MSG_STOP)); + } + + @Override + @MainThread + public void cancel() { + checkIsCalledFromMainThread(); + putMessage(Message.obtain(mHandler, MSG_CANCEL)); + } + + @Override + public void checkRecognitionSupport( + @NonNull Intent recognizerIntent, + @NonNull @CallbackExecutor Executor executor, + @NonNull RecognitionSupportCallback supportListener) { + Objects.requireNonNull(recognizerIntent, "intent must not be null"); + Objects.requireNonNull(supportListener, "listener must not be null"); + + if (DBG) { + Slog.i(TAG, "#checkRecognitionSupport called"); + if (mService == null) { + Slog.i(TAG, "Connection is not established yet"); + } + } + + if (mService == null) { + // First time connection: first establish a connection, then dispatch. + connectToSystemService(); + } + putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT, + new CheckRecognitionSupportArgs(recognizerIntent, executor, supportListener))); + } + + @Override + public void triggerModelDownload(@NonNull Intent recognizerIntent) { + Objects.requireNonNull(recognizerIntent, "intent must not be null"); + if (DBG) { + Slog.i(TAG, "#triggerModelDownload without a listener called"); + if (mService == null) { + Slog.i(TAG, "Connection is not established yet"); + } + } + if (mService == null) { + // First time connection: first establish a connection, then dispatch. + connectToSystemService(); + } + putMessage(Message.obtain( + mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, + new ModelDownloadListenerArgs(recognizerIntent, null, null))); + } + + @Override + public void triggerModelDownload( + @NonNull Intent recognizerIntent, + @NonNull @CallbackExecutor Executor executor, + @NonNull ModelDownloadListener listener) { + Objects.requireNonNull(recognizerIntent, "intent must not be null"); + if (DBG) { + Slog.i(TAG, "#triggerModelDownload with a listener called"); + if (mService == null) { + Slog.i(TAG, "Connection is not established yet"); + } + } + if (mService == null) { + // First time connection: first establish a connection, then dispatch. + connectToSystemService(); + } + putMessage(Message.obtain( + mHandler, MSG_TRIGGER_MODEL_DOWNLOAD, + new ModelDownloadListenerArgs(recognizerIntent, executor, listener))); + } + + @Override + @RequiresPermission(Manifest.permission.MANAGE_SPEECH_RECOGNITION) + public void setTemporaryOnDeviceRecognizer(@Nullable ComponentName componentName) { + mHandler.sendMessage( + Message.obtain(mHandler, MSG_SET_TEMPORARY_ON_DEVICE_COMPONENT, componentName)); + } + + /* package */ static void checkIsCalledFromMainThread() { + if (Looper.myLooper() != Looper.getMainLooper()) { + throw new RuntimeException( + "SpeechRecognizer should be used only from the application's main thread"); + } + } + + private void putMessage(Message msg) { + if (mService == null) { + mPendingTasks.offer(msg); + } else { + mHandler.sendMessage(msg); + } + } + + /** sends the actual message to the service */ + private void handleStartListening(Intent recognizerIntent) { + if (!checkOpenConnection()) { + return; + } + try { + mService.startListening(recognizerIntent, mListener, mContext.getAttributionSource()); + if (DBG) Log.d(TAG, "service start listening command succeeded"); + } catch (final Exception e) { + Log.e(TAG, "startListening() failed", e); + mListener.onError(ERROR_CLIENT); + } + } + + /** sends the actual message to the service */ + private void handleStopMessage() { + if (!checkOpenConnection()) { + return; + } + try { + mService.stopListening(mListener); + if (DBG) Log.d(TAG, "service stop listening command succeeded"); + } catch (final Exception e) { + Log.e(TAG, "stopListening() failed", e); + mListener.onError(ERROR_CLIENT); + } + } + + /** sends the actual message to the service */ + private void handleCancelMessage() { + if (!checkOpenConnection()) { + return; + } + try { + mService.cancel(mListener, /*isShutdown*/ false); + if (DBG) Log.d(TAG, "service cancel command succeeded"); + } catch (final Exception e) { + Log.e(TAG, "cancel() failed", e); + mListener.onError(ERROR_CLIENT); + } + } + + private void handleSetTemporaryComponent(ComponentName componentName) { + if (DBG) { + Log.d(TAG, "handleSetTemporaryComponent, componentName=" + componentName); + } + + if (!maybeInitializeManagerService()) { + return; + } + + try { + mManagerService.setTemporaryComponent(componentName); + } catch (final RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + private void handleCheckRecognitionSupport( + Intent recognizerIntent, + Executor callbackExecutor, + RecognitionSupportCallback recognitionSupportCallback) { + if (!maybeInitializeManagerService() || !checkOpenConnection()) { + return; + } + try { + mService.checkRecognitionSupport( + recognizerIntent, + mContext.getAttributionSource(), + new InternalSupportCallback(callbackExecutor, recognitionSupportCallback)); + if (DBG) Log.d(TAG, "service support command succeeded"); + } catch (final Exception e) { + Log.e(TAG, "checkRecognitionSupport() failed", e); + callbackExecutor.execute(() -> recognitionSupportCallback.onError(ERROR_CLIENT)); + } + } + + private void handleTriggerModelDownload( + Intent recognizerIntent, + @Nullable Executor callbackExecutor, + @Nullable ModelDownloadListener modelDownloadListener) { + if (!maybeInitializeManagerService() || !checkOpenConnection()) { + return; + } + + if (modelDownloadListener == null) { + // Trigger model download without a listener. + try { + mService.triggerModelDownload( + recognizerIntent, mContext.getAttributionSource(), null); + if (DBG) Log.d(TAG, "triggerModelDownload() without a listener"); + } catch (final Exception e) { + Log.e(TAG, "triggerModelDownload() without a listener failed", e); + mListener.onError(ERROR_CLIENT); + } + } else { + // Trigger model download with a listener. + try { + mService.triggerModelDownload( + recognizerIntent, mContext.getAttributionSource(), + new InternalModelDownloadListener(callbackExecutor, modelDownloadListener)); + if (DBG) Log.d(TAG, "triggerModelDownload() with a listener"); + } catch (final Exception e) { + Log.e(TAG, "triggerModelDownload() with a listener failed", e); + callbackExecutor.execute(() -> modelDownloadListener.onError(ERROR_CLIENT)); + } + } + } + + private boolean checkOpenConnection() { + if (mService != null && mService.asBinder().isBinderAlive()) { + return true; + } + mListener.onError(ERROR_CLIENT); + Log.e(TAG, "not connected to the recognition service"); + return false; + } + + /** changes the listener */ + private void handleChangeListener(RecognitionListener listener) { + if (DBG) Log.d(TAG, "handleChangeListener, listener=" + listener); + mListener.mInternalListener = listener; + } + + @Override + public void destroy() { + if (mService != null) { + try { + mService.cancel(mListener, /*isShutdown*/ true); + } catch (final Exception e) { + // Not important + } + } + + mService = null; + mPendingTasks.clear(); + mListener.mInternalListener = null; + } + + /** Establishes a connection to system server proxy and initializes the session. */ + private void connectToSystemService() { + if (!maybeInitializeManagerService()) { + return; + } + + ComponentName componentName = getSpeechRecognizerComponentName(); + + if (!mOnDevice && componentName == null) { + mListener.onError(ERROR_CLIENT); + return; + } + + try { + mManagerService.createSession( + componentName, + mClientToken, + mOnDevice, + new IRecognitionServiceManagerCallback.Stub(){ + @Override + public void onSuccess(IRecognitionService service) throws RemoteException { + if (DBG) { + Log.i(TAG, "Connected to speech recognition service"); + } + mService = service; + while (!mPendingTasks.isEmpty()) { + mHandler.sendMessage(mPendingTasks.poll()); + } + } + + @Override + public void onError(int errorCode) throws RemoteException { + Log.e(TAG, "Bind to system recognition service failed with error " + + errorCode); + mListener.onError(errorCode); + } + }); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + private synchronized boolean maybeInitializeManagerService() { + if (DBG) { + Log.i(TAG, "#maybeInitializeManagerService found = " + mManagerService); + } + if (mManagerService != null) { + return true; + } + + IBinder service = ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE); + if (service == null && mOnDevice) { + service = (IBinder) mContext.getSystemService(Context.SPEECH_RECOGNITION_SERVICE); + } + mManagerService = IRecognitionServiceManager.Stub.asInterface(service); + + if (mManagerService == null) { + if (mListener != null) { + mListener.onError(ERROR_CLIENT); + } + return false; + } + return true; + } + + /** + * Returns the component name to be used for establishing a connection, based on the parameters + * used during initialization. + * + * <p>Note the 3 different scenarios: + * <ol> + * <li>On-device speech recognizer which is determined by the manufacturer and not + * changeable by the user + * <li>Default user-selected speech recognizer as specified by + * {@code Settings.Secure.VOICE_RECOGNITION_SERVICE} + * <li>Custom speech recognizer supplied by the client. + * </ol> + */ + @SuppressWarnings("NonUserGetterCalled") + private ComponentName getSpeechRecognizerComponentName() { + if (mOnDevice) { + return null; + } + + if (mServiceComponent != null) { + return mServiceComponent; + } + + String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE); + + if (TextUtils.isEmpty(serviceComponent)) { + Log.e(TAG, "no selected voice recognition service"); + mListener.onError(ERROR_CLIENT); + return null; + } + + return ComponentName.unflattenFromString(serviceComponent); + } + + private static class CheckRecognitionSupportArgs { + final Intent mIntent; + final Executor mCallbackExecutor; + final RecognitionSupportCallback mCallback; + + private CheckRecognitionSupportArgs( + Intent intent, + Executor callbackExecutor, + RecognitionSupportCallback callback) { + mIntent = intent; + mCallbackExecutor = callbackExecutor; + mCallback = callback; + } + } + + private static class ModelDownloadListenerArgs { + final Intent mIntent; + final Executor mExecutor; + final ModelDownloadListener mModelDownloadListener; + + private ModelDownloadListenerArgs(Intent intent, Executor executor, + ModelDownloadListener modelDownloadListener) { + mIntent = intent; + mExecutor = executor; + mModelDownloadListener = modelDownloadListener; + } + } + + /** + * Internal wrapper of IRecognitionListener which will propagate the results to + * RecognitionListener + */ + private static class InternalRecognitionListener extends IRecognitionListener.Stub { + private RecognitionListener mInternalListener; + + private static final int MSG_BEGINNING_OF_SPEECH = 1; + private static final int MSG_BUFFER_RECEIVED = 2; + private static final int MSG_END_OF_SPEECH = 3; + private static final int MSG_ERROR = 4; + private static final int MSG_READY_FOR_SPEECH = 5; + private static final int MSG_RESULTS = 6; + private static final int MSG_PARTIAL_RESULTS = 7; + private static final int MSG_RMS_CHANGED = 8; + private static final int MSG_ON_EVENT = 9; + private static final int MSG_SEGMENT_RESULTS = 10; + private static final int MSG_SEGMENT_END_SESSION = 11; + private static final int MSG_LANGUAGE_DETECTION = 12; + + private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + if (mInternalListener == null) { + return; + } + switch (msg.what) { + case MSG_BEGINNING_OF_SPEECH: + mInternalListener.onBeginningOfSpeech(); + break; + case MSG_BUFFER_RECEIVED: + mInternalListener.onBufferReceived((byte[]) msg.obj); + break; + case MSG_END_OF_SPEECH: + mInternalListener.onEndOfSpeech(); + break; + case MSG_ERROR: + mInternalListener.onError((Integer) msg.obj); + break; + case MSG_READY_FOR_SPEECH: + mInternalListener.onReadyForSpeech((Bundle) msg.obj); + break; + case MSG_RESULTS: + mInternalListener.onResults((Bundle) msg.obj); + break; + case MSG_PARTIAL_RESULTS: + mInternalListener.onPartialResults((Bundle) msg.obj); + break; + case MSG_RMS_CHANGED: + mInternalListener.onRmsChanged((Float) msg.obj); + break; + case MSG_ON_EVENT: + mInternalListener.onEvent(msg.arg1, (Bundle) msg.obj); + break; + case MSG_SEGMENT_RESULTS: + mInternalListener.onSegmentResults((Bundle) msg.obj); + break; + case MSG_SEGMENT_END_SESSION: + mInternalListener.onEndOfSegmentedSession(); + break; + case MSG_LANGUAGE_DETECTION: + mInternalListener.onLanguageDetection((Bundle) msg.obj); + break; + } + } + }; + + public void onBeginningOfSpeech() { + Message.obtain(mInternalHandler, MSG_BEGINNING_OF_SPEECH).sendToTarget(); + } + + public void onBufferReceived(final byte[] buffer) { + Message.obtain(mInternalHandler, MSG_BUFFER_RECEIVED, buffer).sendToTarget(); + } + + public void onEndOfSpeech() { + Message.obtain(mInternalHandler, MSG_END_OF_SPEECH).sendToTarget(); + } + + public void onError(final int error) { + Message.obtain(mInternalHandler, MSG_ERROR, error).sendToTarget(); + } + + public void onReadyForSpeech(final Bundle noiseParams) { + Message.obtain(mInternalHandler, MSG_READY_FOR_SPEECH, noiseParams).sendToTarget(); + } + + public void onResults(final Bundle results) { + Message.obtain(mInternalHandler, MSG_RESULTS, results).sendToTarget(); + } + + public void onPartialResults(final Bundle results) { + Message.obtain(mInternalHandler, MSG_PARTIAL_RESULTS, results).sendToTarget(); + } + + public void onRmsChanged(final float rmsdB) { + Message.obtain(mInternalHandler, MSG_RMS_CHANGED, rmsdB).sendToTarget(); + } + + public void onSegmentResults(final Bundle bundle) { + Message.obtain(mInternalHandler, MSG_SEGMENT_RESULTS, bundle).sendToTarget(); + } + + public void onEndOfSegmentedSession() { + Message.obtain(mInternalHandler, MSG_SEGMENT_END_SESSION).sendToTarget(); + } + + public void onLanguageDetection(final Bundle results) { + Message.obtain(mInternalHandler, MSG_LANGUAGE_DETECTION, results).sendToTarget(); + } + + public void onEvent(final int eventType, final Bundle params) { + Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params) + .sendToTarget(); + } + } + + private static class InternalSupportCallback extends IRecognitionSupportCallback.Stub { + private final Executor mExecutor; + private final RecognitionSupportCallback mCallback; + + private InternalSupportCallback(Executor executor, RecognitionSupportCallback callback) { + this.mExecutor = executor; + this.mCallback = callback; + } + + @Override + public void onSupportResult(RecognitionSupport recognitionSupport) throws RemoteException { + mExecutor.execute(() -> mCallback.onSupportResult(recognitionSupport)); + } + + @Override + public void onError(int errorCode) throws RemoteException { + mExecutor.execute(() -> mCallback.onError(errorCode)); + } + } + + private static class InternalModelDownloadListener extends IModelDownloadListener.Stub { + private final Executor mExecutor; + private final ModelDownloadListener mModelDownloadListener; + + private InternalModelDownloadListener( + Executor executor, + @NonNull ModelDownloadListener modelDownloadListener) { + mExecutor = executor; + mModelDownloadListener = modelDownloadListener; + } + + @Override + public void onProgress(int completedPercent) throws RemoteException { + mExecutor.execute(() -> mModelDownloadListener.onProgress(completedPercent)); + } + + @Override + public void onSuccess() throws RemoteException { + mExecutor.execute(() -> mModelDownloadListener.onSuccess()); + } + + @Override + public void onScheduled() throws RemoteException { + mExecutor.execute(() -> mModelDownloadListener.onScheduled()); + } + + @Override + public void onError(int error) throws RemoteException { + mExecutor.execute(() -> mModelDownloadListener.onError(error)); + } + } +} diff --git a/core/java/android/speech/SpeechRecognizerProxy.java b/core/java/android/speech/SpeechRecognizerProxy.java new file mode 100644 index 000000000000..be9be9a94538 --- /dev/null +++ b/core/java/android/speech/SpeechRecognizerProxy.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.speech; + +import android.content.ComponentName; +import android.content.Intent; +import android.util.CloseGuard; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.lang.ref.Reference; +import java.util.concurrent.Executor; + +/** + * @hide + */ +class SpeechRecognizerProxy extends SpeechRecognizer { + + private final CloseGuard mCloseGuard = new CloseGuard(); + + private final SpeechRecognizer mDelegate; + + SpeechRecognizerProxy(final SpeechRecognizer delegate) { + mDelegate = delegate; + mCloseGuard.open("SpeechRecognizer#destroy()"); + } + + @Override + public void setRecognitionListener(RecognitionListener listener) { + mDelegate.setRecognitionListener(listener); + } + + @Override + public void startListening(Intent recognizerIntent) { + mDelegate.startListening(recognizerIntent); + } + + @Override + public void stopListening() { + mDelegate.stopListening(); + } + + @Override + public void cancel() { + mDelegate.cancel(); + } + + @Override + public void destroy() { + try { + mCloseGuard.close(); + mDelegate.destroy(); + } finally { + Reference.reachabilityFence(this); + } + } + + @Override + public void checkRecognitionSupport( + @NonNull Intent recognizerIntent, + @NonNull Executor executor, + @NonNull RecognitionSupportCallback supportListener) { + mDelegate.checkRecognitionSupport(recognizerIntent, executor, supportListener); + } + + @Override + public void triggerModelDownload(@NonNull Intent recognizerIntent) { + mDelegate.triggerModelDownload(recognizerIntent); + } + + @Override + public void triggerModelDownload( + @NonNull Intent recognizerIntent, + @NonNull Executor executor, + @NonNull ModelDownloadListener listener) { + mDelegate.triggerModelDownload(recognizerIntent, executor, listener); + } + + @Override + public void setTemporaryOnDeviceRecognizer(@Nullable ComponentName componentName) { + mDelegate.setTemporaryOnDeviceRecognizer(componentName); + } + + @Override + protected void finalize() throws Throwable { + try { + mCloseGuard.warnIfOpen(); + destroy(); + } finally { + super.finalize(); + } + } +} diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 47c29d968558..89aceb9d76e9 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -3913,7 +3913,6 @@ public abstract class Layout { * @see Layout.Builder */ @NonNull - @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH) public final CharSequence getText() { return mText; } diff --git a/core/java/android/tracing/OWNERS b/core/java/android/tracing/OWNERS index 079d4c545f25..2ebe2e9e2761 100644 --- a/core/java/android/tracing/OWNERS +++ b/core/java/android/tracing/OWNERS @@ -1,3 +1,6 @@ carmenjackson@google.com kevinjeon@google.com +pablogamito@google.com +natanieljr@google.com +keanmariotti@google.com include platform/external/perfetto:/OWNERS diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig index 4b4f6d661e31..c6e8844bc47a 100644 --- a/core/java/android/tracing/flags.aconfig +++ b/core/java/android/tracing/flags.aconfig @@ -5,4 +5,11 @@ flag { namespace: "windowing_tools" description: "Move transition tracing to Perfetto" bug: "309630341" -}
\ No newline at end of file +} + +flag { + name: "perfetto_protolog" + namespace: "windowing_tools" + description: "Migrate protolog to Perfetto" + bug: "276432490" +} diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java index fd5517d29d74..f28574ecb3b2 100644 --- a/core/java/android/view/AttachedSurfaceControl.java +++ b/core/java/android/view/AttachedSurfaceControl.java @@ -27,9 +27,6 @@ import android.window.SurfaceSyncGroup; import com.android.window.flags.Flags; -import java.util.concurrent.Executor; -import java.util.function.Consumer; - /** * Provides an interface to the root-Surface of a View Hierarchy or Window. This * is used in combination with the {@link android.view.SurfaceControl} API to enable @@ -197,42 +194,6 @@ public interface AttachedSurfaceControl { } /** - * Add a trusted presentation listener on the SurfaceControl associated with this window. - * - * @param t Transaction that the trusted presentation listener is added on. This should - * be applied by the caller. - * @param thresholds The {@link SurfaceControl.TrustedPresentationThresholds} that will specify - * when the to invoke the callback. - * @param executor The {@link Executor} where the callback will be invoked on. - * @param listener The {@link Consumer} that will receive the callbacks when entered or - * exited the threshold. - * - * @see SurfaceControl.Transaction#setTrustedPresentationCallback(SurfaceControl, - * SurfaceControl.TrustedPresentationThresholds, Executor, Consumer) - * - * @hide b/287076178 un-hide with API bump - */ - default void addTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t, - @NonNull SurfaceControl.TrustedPresentationThresholds thresholds, - @NonNull Executor executor, @NonNull Consumer<Boolean> listener) { - } - - /** - * Remove a trusted presentation listener on the SurfaceControl associated with this window. - * - * @param t Transaction that the trusted presentation listener removed on. This should - * be applied by the caller. - * @param listener The {@link Consumer} that was previously registered with - * addTrustedPresentationCallback that should be removed. - * - * @see SurfaceControl.Transaction#clearTrustedPresentationCallback(SurfaceControl) - * @hide b/287076178 un-hide with API bump - */ - default void removeTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t, - @NonNull Consumer<Boolean> listener) { - } - - /** * Transfer the currently in progress touch gesture from the host to the requested * {@link SurfaceControlViewHost.SurfacePackage}. This requires that the * SurfaceControlViewHost was created with the current host's inputToken. diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 17bbee6d020f..36b74e39072a 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -73,6 +73,8 @@ import android.window.ISurfaceSyncGroupCompletedListener; import android.window.ITaskFpsCallback; import android.window.ScreenCapture; import android.window.WindowContextInfo; +import android.window.ITrustedPresentationListener; +import android.window.TrustedPresentationThresholds; /** * System private interface to the window manager. @@ -1075,4 +1077,10 @@ interface IWindowManager @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MONITOR_INPUT)") void unregisterDecorViewGestureListener(IDecorViewGestureListener listener, int displayId); + + void registerTrustedPresentationListener(in IBinder window, in ITrustedPresentationListener listener, + in TrustedPresentationThresholds thresholds, int id); + + + void unregisterTrustedPresentationListener(in ITrustedPresentationListener listener, int id); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 9d2ab1fe2085..d27f787072e2 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -123,6 +123,7 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.database.ContentObserver; import android.graphics.BLASTBufferQueue; import android.graphics.Canvas; import android.graphics.Color; @@ -392,6 +393,9 @@ public final class ViewRootImpl implements ViewParent, */ private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback; + @Nullable + private ContentObserver mForceInvertObserver; + /** * Callback for notifying about global configuration changes. */ @@ -1597,6 +1601,24 @@ public final class ViewRootImpl implements ViewParent, | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, mBasePackageName); + + if (forceInvertColor()) { + if (mForceInvertObserver == null) { + mForceInvertObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + updateForceDarkMode(); + } + }; + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED + ), + false, + mForceInvertObserver, + UserHandle.myUserId()); + } + } } /** @@ -1610,6 +1632,14 @@ public final class ViewRootImpl implements ViewParent, DisplayManagerGlobal .getInstance() .unregisterDisplayListener(mDisplayListener); + + if (forceInvertColor()) { + if (mForceInvertObserver != null) { + mContext.getContentResolver().unregisterContentObserver(mForceInvertObserver); + mForceInvertObserver = null; + } + } + if (mExtraDisplayListenerLogging) { Slog.w(mTag, "Unregister listeners: " + mBasePackageName, new Throwable()); } @@ -2182,8 +2212,14 @@ public final class ViewRootImpl implements ViewParent, } } - void notifyInsetsAnimationRunningStateChanged(boolean running) { - mInsetsAnimationRunning = running; + /** + * Notify the when the running state of a insets animation changed. + */ + @VisibleForTesting + public void notifyInsetsAnimationRunningStateChanged(boolean running) { + if (sToolkitSetFrameRateReadOnlyFlagValue) { + mInsetsAnimationRunning = running; + } } @Override @@ -2443,6 +2479,19 @@ public final class ViewRootImpl implements ViewParent, if (updateBoundsLayer(t)) { applyTransactionOnDraw(t); } + + // Set the frame rate selection strategy to FRAME_RATE_SELECTION_STRATEGY_SELF + // This strategy ensures that the frame rate specifications do not cascade down to + // the descendant layers. This is particularly important for applications like Chrome, + // where child surfaces should adhere to default behavior instead of no preference + if (sToolkitSetFrameRateReadOnlyFlagValue) { + try { + mFrameRateTransaction.setFrameRateSelectionStrategy(sc, + sc.FRAME_RATE_SELECTION_STRATEGY_SELF).applyAsyncUnsafe(); + } catch (Exception e) { + Log.e(mTag, "Unable to set frame rate selection strategy ", e); + } + } } private void destroySurface() { @@ -11924,18 +11973,6 @@ public final class ViewRootImpl implements ViewParent, scheduleTraversals(); } - @Override - public void addTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t, - @NonNull SurfaceControl.TrustedPresentationThresholds thresholds, - @NonNull Executor executor, @NonNull Consumer<Boolean> listener) { - t.setTrustedPresentationCallback(getSurfaceControl(), thresholds, executor, listener); - } - - @Override - public void removeTrustedPresentationCallback(@NonNull SurfaceControl.Transaction t, - @NonNull Consumer<Boolean> listener) { - t.clearTrustedPresentationCallback(getSurfaceControl()); - } private void logAndTrace(String msg) { if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { @@ -11949,7 +11986,7 @@ public final class ViewRootImpl implements ViewParent, return; } - int frameRateCategory = mIsFrameRateBoosting + int frameRateCategory = mIsFrameRateBoosting || mInsetsAnimationRunning ? FRAME_RATE_CATEGORY_HIGH : preferredFrameRateCategory; try { @@ -12063,6 +12100,14 @@ public final class ViewRootImpl implements ViewParent, } /** + * Get the value of mLastPreferredFrameRateCategory + */ + @VisibleForTesting + public int getLastPreferredFrameRateCategory() { + return mLastPreferredFrameRateCategory; + } + + /** * Get the value of mPreferredFrameRate */ @VisibleForTesting diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 046ea77f196d..f668088e6b44 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -122,7 +122,9 @@ import android.view.WindowInsets.Side.InsetsSide; import android.view.WindowInsets.Type; import android.view.WindowInsets.Type.InsetsType; import android.view.accessibility.AccessibilityNodeInfo; +import android.window.ITrustedPresentationListener; import android.window.TaskFpsCallback; +import android.window.TrustedPresentationThresholds; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -5884,4 +5886,35 @@ public interface WindowManager extends ViewManager { default boolean replaceContentOnDisplayWithSc(int displayId, @NonNull SurfaceControl sc) { throw new UnsupportedOperationException(); } + + /** + * Add a trusted presentation listener associated with a window. If the listener has already + * been registered, an AndroidRuntimeException will be thrown. + * + * @param window The Window to add the trusted presentation listener for + * @param thresholds The {@link TrustedPresentationThresholds} that will specify + * when the to invoke the callback. + * @param executor The {@link Executor} where the callback will be invoked on. + * @param listener The {@link ITrustedPresentationListener} that will receive the callbacks + * when entered or exited trusted presentation per the thresholds. + * + * @hide b/287076178 un-hide with API bump + */ + default void registerTrustedPresentationListener(@NonNull IBinder window, + @NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor, + @NonNull Consumer<Boolean> listener) { + throw new UnsupportedOperationException(); + } + + /** + * Removes a presentation listener associated with a window. If the listener was not previously + * registered, the call will be a noop. + * + * @hide + * @see #registerTrustedPresentationListener(IBinder, + * TrustedPresentationThresholds, Executor, Consumer) + */ + default void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) { + throw new UnsupportedOperationException(); + } } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 214f1ec3d1ec..a7d814e9ab8c 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -30,9 +30,13 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.util.AndroidRuntimeException; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import android.util.Pair; import android.view.inputmethod.InputMethodManager; +import android.window.ITrustedPresentationListener; +import android.window.TrustedPresentationThresholds; import com.android.internal.util.FastPrintWriter; @@ -43,6 +47,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.WeakHashMap; import java.util.concurrent.Executor; +import java.util.function.Consumer; import java.util.function.IntConsumer; /** @@ -143,6 +148,9 @@ public final class WindowManagerGlobal { private Runnable mSystemPropertyUpdater; + private final TrustedPresentationListener mTrustedPresentationListener = + new TrustedPresentationListener(); + private WindowManagerGlobal() { } @@ -324,7 +332,7 @@ public final class WindowManagerGlobal { final Context context = view.getContext(); if (context != null && (context.getApplicationInfo().flags - & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { + & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } } @@ -482,7 +490,7 @@ public final class WindowManagerGlobal { if (who != null) { WindowLeaked leak = new WindowLeaked( what + " " + who + " has leaked window " - + root.getView() + " that was originally added here"); + + root.getView() + " that was originally added here"); leak.setStackTrace(root.getLocation().getStackTrace()); Log.e(TAG, "", leak); } @@ -790,6 +798,86 @@ public final class WindowManagerGlobal { } } + public void registerTrustedPresentationListener(@NonNull IBinder window, + @NonNull TrustedPresentationThresholds thresholds, Executor executor, + @NonNull Consumer<Boolean> listener) { + mTrustedPresentationListener.addListener(window, thresholds, listener, executor); + } + + public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) { + mTrustedPresentationListener.removeListener(listener); + } + + private final class TrustedPresentationListener extends + ITrustedPresentationListener.Stub { + private static int sId = 0; + private final ArrayMap<Consumer<Boolean>, Pair<Integer, Executor>> mListeners = + new ArrayMap<>(); + + private final Object mTplLock = new Object(); + + private void addListener(IBinder window, TrustedPresentationThresholds thresholds, + Consumer<Boolean> listener, Executor executor) { + synchronized (mTplLock) { + if (mListeners.containsKey(listener)) { + throw new AndroidRuntimeException("Trying to add duplicate listener"); + } + int id = sId++; + mListeners.put(listener, new Pair<>(id, executor)); + try { + WindowManagerGlobal.getWindowManagerService() + .registerTrustedPresentationListener(window, this, thresholds, id); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + } + + private void removeListener(Consumer<Boolean> listener) { + synchronized (mTplLock) { + var removedListener = mListeners.remove(listener); + if (removedListener == null) { + Log.i(TAG, "listener " + listener + " does not exist."); + return; + } + + try { + WindowManagerGlobal.getWindowManagerService() + .unregisterTrustedPresentationListener(this, removedListener.first); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + } + + @Override + public void onTrustedPresentationChanged(int[] inTrustedStateListenerIds, + int[] outOfTrustedStateListenerIds) { + ArrayList<Runnable> firedListeners = new ArrayList<>(); + synchronized (mTplLock) { + mListeners.forEach((listener, idExecutorPair) -> { + final var listenerId = idExecutorPair.first; + final var executor = idExecutorPair.second; + for (int id : inTrustedStateListenerIds) { + if (listenerId == id) { + firedListeners.add(() -> executor.execute( + () -> listener.accept(/*presentationState*/true))); + } + } + for (int id : outOfTrustedStateListenerIds) { + if (listenerId == id) { + firedListeners.add(() -> executor.execute( + () -> listener.accept(/*presentationState*/false))); + } + } + }); + } + for (int i = 0; i < firedListeners.size(); i++) { + firedListeners.get(i).run(); + } + } + } + /** @hide */ public void addWindowlessRoot(ViewRootImpl impl) { synchronized (mLock) { @@ -801,7 +889,7 @@ public final class WindowManagerGlobal { public void removeWindowlessRoot(ViewRootImpl impl) { synchronized (mLock) { mWindowlessRoots.remove(impl); - } + } } public void setRecentsAppBehindSystemBars(boolean behindSystemBars) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index d7b74b3bcfe2..b4b1fde89a46 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -37,6 +37,7 @@ import android.os.StrictMode; import android.util.Log; import android.window.ITaskFpsCallback; import android.window.TaskFpsCallback; +import android.window.TrustedPresentationThresholds; import android.window.WindowContext; import android.window.WindowMetricsController; import android.window.WindowProvider; @@ -508,4 +509,17 @@ public final class WindowManagerImpl implements WindowManager { } return false; } + + @Override + public void registerTrustedPresentationListener(@NonNull IBinder window, + @NonNull TrustedPresentationThresholds thresholds, @NonNull Executor executor, + @NonNull Consumer<Boolean> listener) { + mGlobal.registerTrustedPresentationListener(window, thresholds, executor, listener); + } + + @Override + public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) { + mGlobal.unregisterTrustedPresentationListener(listener); + + } } diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index aa4275d62046..b29967888312 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -34,7 +34,7 @@ flag { namespace: "accessibility" name: "flash_notification_system_api" description: "Makes flash notification APIs as system APIs for calling from mainline module" - bug: "282821643" + bug: "303131332" } flag { diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java index 6884e639f9c7..6963237fc19b 100644 --- a/core/java/android/widget/ToastPresenter.java +++ b/core/java/android/widget/ToastPresenter.java @@ -91,7 +91,6 @@ public class ToastPresenter { private final WeakReference<Context> mContext; private final Resources mResources; - private final WeakReference<WindowManager> mWindowManager; private final IAccessibilityManager mAccessibilityManagerService; private final INotificationManager mNotificationManager; private final String mPackageName; @@ -104,7 +103,6 @@ public class ToastPresenter { INotificationManager notificationManager, String packageName) { mContext = new WeakReference<>(context); mResources = context.getResources(); - mWindowManager = new WeakReference<>(context.getSystemService(WindowManager.class)); mNotificationManager = notificationManager; mPackageName = packageName; mContextPackageName = context.getPackageName(); @@ -274,7 +272,7 @@ public class ToastPresenter { public void hide(@Nullable ITransientNotificationCallback callback) { checkState(mView != null, "No toast to hide."); - final WindowManager windowManager = mWindowManager.get(); + final WindowManager windowManager = getWindowManager(mView); if (mView.getParent() != null && windowManager != null) { windowManager.removeViewImmediate(mView); } @@ -295,6 +293,17 @@ public class ToastPresenter { mToken = null; } + private WindowManager getWindowManager(View view) { + Context context = mContext.get(); + if (context == null && view != null) { + context = view.getContext(); + } + if (context != null) { + return context.getSystemService(WindowManager.class); + } + return null; + } + /** * Sends {@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED} event if accessibility is * enabled. @@ -331,7 +340,7 @@ public class ToastPresenter { } private void addToastView() { - final WindowManager windowManager = mWindowManager.get(); + final WindowManager windowManager = getWindowManager(mView); if (windowManager == null) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardRootViewVisibilityState.kt b/core/java/android/window/ITrustedPresentationListener.aidl index 9a57aefba329..b33128abb7e5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardRootViewVisibilityState.kt +++ b/core/java/android/window/ITrustedPresentationListener.aidl @@ -12,20 +12,13 @@ * 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.shared.model +package android.window; /** - * Provides a stateful representation of the visibility of the KeyguardRootView - * - * @param statusBarState State of the status bar represented by [StatusBarState] - * @param goingToFullShade Whether status bar is going to full shade - * @param occlusionTransitionRunning Whether the occlusion transition is running in this instant + * @hide */ -data class KeyguardRootViewVisibilityState( - val statusBarState: Int, - val goingToFullShade: Boolean, - val occlusionTransitionRunning: Boolean, -) +oneway interface ITrustedPresentationListener { + void onTrustedPresentationChanged(in int[] enteredTrustedStateIds, in int[] exitedTrustedStateIds); +}
\ No newline at end of file diff --git a/core/java/android/window/TrustedPresentationListener.java b/core/java/android/window/TrustedPresentationListener.java new file mode 100644 index 000000000000..02fd6d98fb0d --- /dev/null +++ b/core/java/android/window/TrustedPresentationListener.java @@ -0,0 +1,26 @@ +/* + * Copyright 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 android.window; + +/** + * @hide + */ +public interface TrustedPresentationListener { + + void onTrustedPresentationChanged(boolean inTrustedPresentationState); + +} diff --git a/core/java/android/window/TrustedPresentationThresholds.aidl b/core/java/android/window/TrustedPresentationThresholds.aidl new file mode 100644 index 000000000000..d7088bf0fddc --- /dev/null +++ b/core/java/android/window/TrustedPresentationThresholds.aidl @@ -0,0 +1,3 @@ +package android.window; + +parcelable TrustedPresentationThresholds; diff --git a/core/java/android/window/TrustedPresentationThresholds.java b/core/java/android/window/TrustedPresentationThresholds.java new file mode 100644 index 000000000000..801d35c49228 --- /dev/null +++ b/core/java/android/window/TrustedPresentationThresholds.java @@ -0,0 +1,127 @@ +/* + * Copyright 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 android.window; + +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.SurfaceControl; + +import androidx.annotation.NonNull; + +/** + * @hide + */ +public final class TrustedPresentationThresholds implements Parcelable { + /** + * The min alpha the {@link SurfaceControl} is required to have to be considered inside the + * threshold. + */ + @FloatRange(from = 0f, fromInclusive = false, to = 1f) + public final float mMinAlpha; + + /** + * The min fraction of the SurfaceControl that was presented to the user to be considered + * inside the threshold. + */ + @FloatRange(from = 0f, fromInclusive = false, to = 1f) + public final float mMinFractionRendered; + + /** + * The time in milliseconds required for the {@link SurfaceControl} to be in the threshold. + */ + @IntRange(from = 1) + public final int mStabilityRequirementMs; + + private void checkValid() { + if (mMinAlpha <= 0 || mMinFractionRendered <= 0 || mStabilityRequirementMs < 1) { + throw new IllegalArgumentException( + "TrustedPresentationThresholds values are invalid"); + } + } + + /** + * Creates a new TrustedPresentationThresholds. + * + * @param minAlpha The min alpha the {@link SurfaceControl} is required to + * have to be considered inside the + * threshold. + * @param minFractionRendered The min fraction of the SurfaceControl that was presented + * to the user to be considered + * inside the threshold. + * @param stabilityRequirementMs The time in milliseconds required for the + * {@link SurfaceControl} to be in the threshold. + */ + public TrustedPresentationThresholds( + @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minAlpha, + @FloatRange(from = 0f, fromInclusive = false, to = 1f) float minFractionRendered, + @IntRange(from = 1) int stabilityRequirementMs) { + this.mMinAlpha = minAlpha; + this.mMinFractionRendered = minFractionRendered; + this.mStabilityRequirementMs = stabilityRequirementMs; + checkValid(); + } + + @Override + public String toString() { + return "TrustedPresentationThresholds { " + + "minAlpha = " + mMinAlpha + ", " + + "minFractionRendered = " + mMinFractionRendered + ", " + + "stabilityRequirementMs = " + mStabilityRequirementMs + + " }"; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeFloat(mMinAlpha); + dest.writeFloat(mMinFractionRendered); + dest.writeInt(mStabilityRequirementMs); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * @hide + */ + TrustedPresentationThresholds(@NonNull Parcel in) { + mMinAlpha = in.readFloat(); + mMinFractionRendered = in.readFloat(); + mStabilityRequirementMs = in.readInt(); + + checkValid(); + } + + /** + * @hide + */ + public static final @NonNull Creator<TrustedPresentationThresholds> CREATOR = + new Creator<TrustedPresentationThresholds>() { + @Override + public TrustedPresentationThresholds[] newArray(int size) { + return new TrustedPresentationThresholds[size]; + } + + @Override + public TrustedPresentationThresholds createFromParcel(@NonNull Parcel in) { + return new TrustedPresentationThresholds(in); + } + }; +} diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig index 9fe30df13036..727bff44017e 100644 --- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig +++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig @@ -14,4 +14,12 @@ flag { description: "Make it possible to move cutout across edges through device config" bug: "302387383" is_fixed_read_only: true -}
\ No newline at end of file +} + +flag { + name: "density_390_api" + namespace: "large_screen_experiences_app_compat" + description: "Whether the API DisplayMetrics.DENSITY_390 is available" + bug: "297550533" + is_fixed_read_only: true +} diff --git a/core/java/com/android/internal/app/NfcResolverActivity.java b/core/java/com/android/internal/app/NfcResolverActivity.java new file mode 100644 index 000000000000..402192abaf0a --- /dev/null +++ b/core/java/com/android/internal/app/NfcResolverActivity.java @@ -0,0 +1,59 @@ +/* + * 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.internal.app; + +import static android.service.chooser.CustomChoosers.EXTRA_RESOLVE_INFOS; +import static android.service.chooser.Flags.supportNfcResolver; + +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.os.Bundle; + +import java.util.ArrayList; + +/** + * Caller-customizable variant of {@link ResolverActivity} to support the + * {@link CustomChoosers#showNfcResolver()} API. + */ +public class NfcResolverActivity extends ResolverActivity { + + @Override + @SuppressWarnings("MissingSuperCall") // Called indirectly via `super_onCreate()`. + protected void onCreate(Bundle savedInstanceState) { + if (!supportNfcResolver()) { + super_onCreate(savedInstanceState); + finish(); + return; + } + + Intent intent = getIntent(); + Intent target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class); + ArrayList<ResolveInfo> rList = + intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS, ResolveInfo.class); + CharSequence title = intent.getExtras().getCharSequence( + Intent.EXTRA_TITLE, + getResources().getText(com.android.internal.R.string.chooseActivity)); + + super.onCreate( + savedInstanceState, + target, + title, + /* initialIntents=*/ null, + rList, + /* supportsAlwaysUseOption=*/ false); + } +} diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index 4bb7c33b41e2..8c2a52560050 100644 --- a/core/java/com/android/internal/protolog/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -93,6 +93,7 @@ public enum ProtoLogGroup implements IProtoLogGroup { WM_DEBUG_DREAM(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM), WM_DEBUG_DIMMER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_TPL(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagerProtoLogTest"); private final boolean mEnabled; diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java index 9c632ea725a9..2a10918a5161 100644 --- a/core/java/com/android/server/LocalServices.java +++ b/core/java/com/android/server/LocalServices.java @@ -29,6 +29,7 @@ import android.util.ArrayMap; * * {@hide} */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class LocalServices { private LocalServices() {} @@ -69,4 +70,14 @@ public final class LocalServices { sLocalServiceObjects.remove(type); } } + + /** + * Remove all known service instances, must be only used in tests. + */ + @VisibleForTesting + public static void removeAllServicesForTest() { + synchronized (sLocalServiceObjects) { + sLocalServiceObjects.clear(); + } + } } diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp index 95bf49fe501e..aebe7ea7ee61 100644 --- a/core/jni/android_os_PerformanceHintManager.cpp +++ b/core/jni/android_os_PerformanceHintManager.cpp @@ -16,15 +16,16 @@ #define LOG_TAG "PerfHint-jni" -#include "jni.h" - +#include <android/performance_hint.h> #include <dlfcn.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedPrimitiveArray.h> #include <utils/Log.h> + #include <vector> #include "core_jni_helpers.h" +#include "jni.h" namespace android { @@ -44,6 +45,11 @@ typedef void (*APH_sendHint)(APerformanceHintSession*, int32_t); typedef int (*APH_setThreads)(APerformanceHintSession*, const pid_t*, size_t); typedef void (*APH_getThreadIds)(APerformanceHintSession*, int32_t* const, size_t* const); typedef void (*APH_setPreferPowerEfficiency)(APerformanceHintSession*, bool); +typedef void (*APH_reportActualWorkDuration2)(APerformanceHintSession*, AWorkDuration*); + +typedef AWorkDuration* (*AWD_create)(); +typedef void (*AWD_setTimeNanos)(AWorkDuration*, int64_t); +typedef void (*AWD_release)(AWorkDuration*); bool gAPerformanceHintBindingInitialized = false; APH_getManager gAPH_getManagerFn = nullptr; @@ -56,6 +62,14 @@ APH_sendHint gAPH_sendHintFn = nullptr; APH_setThreads gAPH_setThreadsFn = nullptr; APH_getThreadIds gAPH_getThreadIdsFn = nullptr; APH_setPreferPowerEfficiency gAPH_setPreferPowerEfficiencyFn = nullptr; +APH_reportActualWorkDuration2 gAPH_reportActualWorkDuration2Fn = nullptr; + +AWD_create gAWD_createFn = nullptr; +AWD_setTimeNanos gAWD_setWorkPeriodStartTimestampNanosFn = nullptr; +AWD_setTimeNanos gAWD_setActualTotalDurationNanosFn = nullptr; +AWD_setTimeNanos gAWD_setActualCpuDurationNanosFn = nullptr; +AWD_setTimeNanos gAWD_setActualGpuDurationNanosFn = nullptr; +AWD_release gAWD_releaseFn = nullptr; void ensureAPerformanceHintBindingInitialized() { if (gAPerformanceHintBindingInitialized) return; @@ -112,9 +126,46 @@ void ensureAPerformanceHintBindingInitialized() { (APH_setPreferPowerEfficiency)dlsym(handle_, "APerformanceHint_setPreferPowerEfficiency"); LOG_ALWAYS_FATAL_IF(gAPH_setPreferPowerEfficiencyFn == nullptr, - "Failed to find required symbol" + "Failed to find required symbol " "APerformanceHint_setPreferPowerEfficiency!"); + gAPH_reportActualWorkDuration2Fn = + (APH_reportActualWorkDuration2)dlsym(handle_, + "APerformanceHint_reportActualWorkDuration2"); + LOG_ALWAYS_FATAL_IF(gAPH_reportActualWorkDuration2Fn == nullptr, + "Failed to find required symbol " + "APerformanceHint_reportActualWorkDuration2!"); + + gAWD_createFn = (AWD_create)dlsym(handle_, "AWorkDuration_create"); + LOG_ALWAYS_FATAL_IF(gAWD_createFn == nullptr, + "Failed to find required symbol AWorkDuration_create!"); + + gAWD_setWorkPeriodStartTimestampNanosFn = + (AWD_setTimeNanos)dlsym(handle_, "AWorkDuration_setWorkPeriodStartTimestampNanos"); + LOG_ALWAYS_FATAL_IF(gAWD_setWorkPeriodStartTimestampNanosFn == nullptr, + "Failed to find required symbol " + "AWorkDuration_setWorkPeriodStartTimestampNanos!"); + + gAWD_setActualTotalDurationNanosFn = + (AWD_setTimeNanos)dlsym(handle_, "AWorkDuration_setActualTotalDurationNanos"); + LOG_ALWAYS_FATAL_IF(gAWD_setActualTotalDurationNanosFn == nullptr, + "Failed to find required symbol " + "AWorkDuration_setActualTotalDurationNanos!"); + + gAWD_setActualCpuDurationNanosFn = + (AWD_setTimeNanos)dlsym(handle_, "AWorkDuration_setActualCpuDurationNanos"); + LOG_ALWAYS_FATAL_IF(gAWD_setActualCpuDurationNanosFn == nullptr, + "Failed to find required symbol AWorkDuration_setActualCpuDurationNanos!"); + + gAWD_setActualGpuDurationNanosFn = + (AWD_setTimeNanos)dlsym(handle_, "AWorkDuration_setActualGpuDurationNanos"); + LOG_ALWAYS_FATAL_IF(gAWD_setActualGpuDurationNanosFn == nullptr, + "Failed to find required symbol AWorkDuration_setActualGpuDurationNanos!"); + + gAWD_releaseFn = (AWD_release)dlsym(handle_, "AWorkDuration_release"); + LOG_ALWAYS_FATAL_IF(gAWD_releaseFn == nullptr, + "Failed to find required symbol AWorkDuration_release!"); + gAPerformanceHintBindingInitialized = true; } @@ -238,6 +289,25 @@ static void nativeSetPreferPowerEfficiency(JNIEnv* env, jclass clazz, jlong nati enabled); } +static void nativeReportActualWorkDuration2(JNIEnv* env, jclass clazz, jlong nativeSessionPtr, + jlong workPeriodStartTimestampNanos, + jlong actualTotalDurationNanos, + jlong actualCpuDurationNanos, + jlong actualGpuDurationNanos) { + ensureAPerformanceHintBindingInitialized(); + + AWorkDuration* workDuration = gAWD_createFn(); + gAWD_setWorkPeriodStartTimestampNanosFn(workDuration, workPeriodStartTimestampNanos); + gAWD_setActualTotalDurationNanosFn(workDuration, actualTotalDurationNanos); + gAWD_setActualCpuDurationNanosFn(workDuration, actualCpuDurationNanos); + gAWD_setActualGpuDurationNanosFn(workDuration, actualGpuDurationNanos); + + gAPH_reportActualWorkDuration2Fn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr), + workDuration); + + gAWD_releaseFn(workDuration); +} + static const JNINativeMethod gPerformanceHintMethods[] = { {"nativeAcquireManager", "()J", (void*)nativeAcquireManager}, {"nativeGetPreferredUpdateRateNanos", "(J)J", (void*)nativeGetPreferredUpdateRateNanos}, @@ -249,6 +319,7 @@ static const JNINativeMethod gPerformanceHintMethods[] = { {"nativeSetThreads", "(J[I)V", (void*)nativeSetThreads}, {"nativeGetThreadIds", "(J)[I", (void*)nativeGetThreadIds}, {"nativeSetPreferPowerEfficiency", "(JZ)V", (void*)nativeSetPreferPowerEfficiency}, + {"nativeReportActualWorkDuration", "(JJJJJ)V", (void*)nativeReportActualWorkDuration2}, }; int register_android_os_PerformanceHintManager(JNIEnv* env) { diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index 17ca7c80707c..a2978bec16b5 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -359,6 +359,8 @@ message DNDPolicyProto { optional PeopleType allow_messages_from = 18; optional ConversationType allow_conversations_from = 19; + + optional ChannelType allow_channels = 20; } // Enum identifying the type of rule that changed; values set to match ones used in the @@ -368,3 +370,11 @@ enum RuleType { RULE_TYPE_MANUAL = 1; RULE_TYPE_AUTOMATIC = 2; } + +// Enum used in DNDPolicyProto to indicate the type of channels permitted to +// break through DND. Mirrors values in ZenPolicy. +enum ChannelType { + CHANNEL_TYPE_UNSET = 0; + CHANNEL_TYPE_PRIORITY = 1; + CHANNEL_TYPE_NONE = 2; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index cf41a06a824e..38fde3dc2469 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -7469,6 +7469,13 @@ <permission android:name="android.permission.SIGNAL_REBOOT_READINESS" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows the holder to launch an Intent Resolver flow with custom presentation + and/or targets. + @FlaggedApi("android.service.chooser.support_nfc_resolver") + @hide --> + <permission android:name="android.permission.SHOW_CUSTOMIZED_RESOLVER" + android:protectionLevel="signature|privileged" /> + <!-- @hide Allows an application to get a People Tile preview for a given shortcut. --> <permission android:name="android.permission.GET_PEOPLE_TILE_PREVIEW" android:protectionLevel="signature|recents" /> @@ -7891,6 +7898,18 @@ <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> + <activity android:name="com.android.internal.app.NfcResolverActivity" + android:theme="@style/Theme.Dialog.Alert" + android:finishOnCloseSystemDialogs="true" + android:excludeFromRecents="true" + android:multiprocess="true" + android:permission="android.permission.SHOW_CUSTOMIZED_RESOLVER" + android:exported="true"> + <intent-filter> + <action android:name="android.service.chooser.action.SHOW_CUSTOMIZED_RESOLVER" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> <activity android:name="com.android.internal.app.IntentForwarderActivity" android:finishOnCloseSystemDialogs="true" android:theme="@style/Theme.DeviceDefault.Resolver" diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java index 20ba4270e6fc..9b4dec4118a1 100644 --- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java +++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java @@ -182,4 +182,42 @@ public class PerformanceHintManagerTest { s.setPreferPowerEfficiency(true); s.setPreferPowerEfficiency(true); } + + @Test + public void testReportActualWorkDurationWithWorkDurationClass() { + Session s = createSession(); + assumeNotNull(s); + s.updateTargetWorkDuration(16); + s.reportActualWorkDuration(new WorkDuration(1, 12, 8, 6)); + s.reportActualWorkDuration(new WorkDuration(1, 33, 14, 20)); + s.reportActualWorkDuration(new WorkDuration(1, 14, 10, 6)); + } + + @Test + public void testReportActualWorkDurationWithWorkDurationClass_IllegalArgument() { + Session s = createSession(); + assumeNotNull(s); + s.updateTargetWorkDuration(16); + assertThrows(IllegalArgumentException.class, () -> { + s.reportActualWorkDuration(new WorkDuration(-1, 12, 8, 6)); + }); + assertThrows(IllegalArgumentException.class, () -> { + s.reportActualWorkDuration(new WorkDuration(0, 12, 8, 6)); + }); + assertThrows(IllegalArgumentException.class, () -> { + s.reportActualWorkDuration(new WorkDuration(1, -1, 8, 6)); + }); + assertThrows(IllegalArgumentException.class, () -> { + s.reportActualWorkDuration(new WorkDuration(1, 0, 8, 6)); + }); + assertThrows(IllegalArgumentException.class, () -> { + s.reportActualWorkDuration(new WorkDuration(1, 12, -1, 6)); + }); + assertThrows(IllegalArgumentException.class, () -> { + s.reportActualWorkDuration(new WorkDuration(1, 12, 0, 6)); + }); + assertThrows(IllegalArgumentException.class, () -> { + s.reportActualWorkDuration(new WorkDuration(1, 12, 8, -1)); + }); + } } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index e0e3a3542cb0..617262203c6b 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -628,6 +628,42 @@ public class ViewRootImplTest { }); } + /** + * We should boost the frame rate if the value of mInsetsAnimationRunning is true. + */ + @Test + @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public void votePreferredFrameRate_insetsAnimation() { + View view = new View(sContext); + WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); + wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check + + sInstrumentation.runOnMainSync(() -> { + WindowManager wm = sContext.getSystemService(WindowManager.class); + Display display = wm.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + wmlp.width = (int) (metrics.widthPixels * 0.9); + wmlp.height = (int) (metrics.heightPixels * 0.9); + wm.addView(view, wmlp); + }); + sInstrumentation.waitForIdleSync(); + + ViewRootImpl viewRootImpl = view.getViewRootImpl(); + sInstrumentation.runOnMainSync(() -> { + view.invalidate(); + assertEquals(viewRootImpl.getLastPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_NORMAL); + viewRootImpl.notifyInsetsAnimationRunningStateChanged(true); + view.invalidate(); + }); + sInstrumentation.waitForIdleSync(); + + sInstrumentation.runOnMainSync(() -> { + assertEquals(viewRootImpl.getLastPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_HIGH); + }); + } @Test public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() { diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 1f08955e5f58..3cf28c919f07 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -383,6 +383,8 @@ applications that come with the platform <!-- Permission required for ShortcutManagerUsageTest CTS test. --> <permission name="android.permission.ACCESS_SHORTCUTS"/> <permission name="android.permission.REBOOT"/> + <!-- Permission required for NfcResolverActivity CTS tests. --> + <permission name="android.permission.SHOW_CUSTOMIZED_RESOLVER"/> <!-- Permission required for access VIBRATOR_STATE. --> <permission name="android.permission.ACCESS_VIBRATOR_STATE"/> <!-- Permission required for UsageStatsTest CTS test. --> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 2237ba1924db..19128212094d 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -595,6 +595,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-1518132958": { + "message": "fractionRendered boundsOverSource=%f", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "-1517908912": { "message": "requestScrollCapture: caught exception dispatching to window.token=%s", "level": "WARN", @@ -961,6 +967,12 @@ "group": "WM_DEBUG_CONTENT_RECORDING", "at": "com\/android\/server\/wm\/ContentRecorder.java" }, + "-1209762265": { + "message": "Registering listener=%s with id=%d for window=%s with %s", + "level": "DEBUG", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "-1209252064": { "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s", "level": "DEBUG", @@ -1333,6 +1345,12 @@ "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/Transition.java" }, + "-888703350": { + "message": "Skipping %s", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "-883738232": { "message": "Adding more than one toast window for UID at a time.", "level": "WARN", @@ -2803,6 +2821,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "360319850": { + "message": "fractionRendered scale=%f", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "364992694": { "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s", "level": "VERBOSE", @@ -2983,6 +3007,12 @@ "group": "WM_DEBUG_BACK_PREVIEW", "at": "com\/android\/server\/wm\/BackNavigationController.java" }, + "532771960": { + "message": "Adding untrusted state listener=%s with id=%d", + "level": "DEBUG", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "535103992": { "message": "Wallpaper may change! Adjusting", "level": "VERBOSE", @@ -3061,6 +3091,12 @@ "group": "WM_DEBUG_DREAM", "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, + "605179032": { + "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "608694300": { "message": " NEW SURFACE SESSION %s", "level": "INFO", @@ -3289,6 +3325,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowState.java" }, + "824532141": { + "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "829434921": { "message": "Draw state now committed in %s", "level": "VERBOSE", @@ -3583,6 +3625,12 @@ "group": "WM_SHOW_SURFACE_ALLOC", "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" }, + "1090378847": { + "message": "Checking %d windows", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "1100065297": { "message": "Attempted to get IME policy of a display that does not exist: %d", "level": "WARN", @@ -3715,6 +3763,12 @@ "group": "WM_DEBUG_FOCUS", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1251721200": { + "message": "unregister failed, couldn't find deathRecipient for %s with id=%d", + "level": "ERROR", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "1252594551": { "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d", "level": "WARN", @@ -3853,6 +3907,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/TaskDisplayArea.java" }, + "1382634842": { + "message": "Unregistering listener=%s with id=%d", + "level": "DEBUG", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "1393721079": { "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]", "level": "VERBOSE", @@ -3901,6 +3961,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1445704347": { + "message": "coveredRegionsAbove updated with %s frame:%s region:%s", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "1448683958": { "message": "Override pending remote transitionSet=%b adapter=%s", "level": "INFO", @@ -4201,6 +4267,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "1786463281": { + "message": "Adding trusted state listener=%s with id=%d", + "level": "DEBUG", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "1789321832": { "message": "Then token:%s is invalid. It might be removed", "level": "WARN", @@ -4375,6 +4447,12 @@ "group": "WM_DEBUG_TASKS", "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, + "1955470028": { + "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + }, "1964565370": { "message": "Starting remote animation", "level": "INFO", @@ -4659,6 +4737,9 @@ "WM_DEBUG_TASKS": { "tag": "WindowManager" }, + "WM_DEBUG_TPL": { + "tag": "WindowManager" + }, "WM_DEBUG_WALLPAPER": { "tag": "WindowManager" }, diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 4982f3732089..231fa4837441 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -618,7 +618,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * @see #isMgf1DigestsSpecified() */ @NonNull - @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER) + @FlaggedApi("MGF1_DIGEST_SETTER") public @KeyProperties.DigestEnum Set<String> getMgf1Digests() { if (mMgf1Digests.isEmpty()) { throw new IllegalStateException("Mask generation function (MGF) not specified"); @@ -633,7 +633,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * @see #getMgf1Digests() */ @NonNull - @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER) + @FlaggedApi("MGF1_DIGEST_SETTER") public boolean isMgf1DigestsSpecified() { return !mMgf1Digests.isEmpty(); } @@ -1292,7 +1292,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * <p>See {@link KeyProperties}.{@code DIGEST} constants. */ @NonNull - @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER) + @FlaggedApi("MGF1_DIGEST_SETTER") public Builder setMgf1Digests(@NonNull @KeyProperties.DigestEnum String... mgf1Digests) { mMgf1Digests = Set.of(mgf1Digests); return this; diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 7b6b2d142f95..c1e3bab5d37c 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -401,7 +401,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { * @see #isMgf1DigestsSpecified() */ @NonNull - @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER) + @FlaggedApi("MGF1_DIGEST_SETTER") public @KeyProperties.DigestEnum Set<String> getMgf1Digests() { if (mMgf1Digests.isEmpty()) { throw new IllegalStateException("Mask generation function (MGF) not specified"); @@ -416,7 +416,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { * @see #getMgf1Digests() */ @NonNull - @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER) + @FlaggedApi("MGF1_DIGEST_SETTER") public boolean isMgf1DigestsSpecified() { return !mMgf1Digests.isEmpty(); } @@ -799,7 +799,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { * <p>See {@link KeyProperties}.{@code DIGEST} constants. */ @NonNull - @FlaggedApi(android.security.Flags.FLAG_MGF1_DIGEST_SETTER) + @FlaggedApi("MGF1_DIGEST_SETTER") public Builder setMgf1Digests(@Nullable @KeyProperties.DigestEnum String... mgf1Digests) { mMgf1Digests = Set.of(mgf1Digests); return this; diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index 02efc2f3539d..ed4b485f3927 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -28,7 +28,6 @@ import android.hardware.security.keymint.SecurityLevel; import android.hardware.security.keymint.Tag; import android.os.Build; import android.os.StrictMode; -import android.security.Flags; import android.security.KeyPairGeneratorSpec; import android.security.KeyStore2; import android.security.KeyStoreException; @@ -854,22 +853,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mgf1Digest )); }); - - /* If the MGF1 Digest setter is not set, fall back to the previous behaviour: - * Add, as MGF1 Digest function, all the primary digests. - * Avoid adding the default MGF1 digest as it will have been included in the - * mKeymasterMgf1Digests field. - */ - if (!Flags.mgf1DigestSetter()) { - final int defaultMgf1Digest = KeyProperties.Digest.toKeymaster( - DEFAULT_MGF1_DIGEST); - ArrayUtils.forEach(mKeymasterDigests, (digest) -> { - if (digest != defaultMgf1Digest) { - params.add(KeyStore2ParameterUtils.makeEnum( - KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, digest)); - } - }); - } } }); ArrayUtils.forEach(mKeymasterSignaturePaddings, (padding) -> { diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java index 4f65884138bd..ddbd93e458fd 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java @@ -25,7 +25,6 @@ import android.hardware.security.keymint.HardwareAuthenticatorType; import android.hardware.security.keymint.KeyParameter; import android.hardware.security.keymint.SecurityLevel; import android.os.StrictMode; -import android.security.Flags; import android.security.GateKeeper; import android.security.KeyStore2; import android.security.KeyStoreParameter; @@ -538,31 +537,11 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { /* Because of default MGF1 digest is SHA-1. It has to be added in Key * characteristics. Otherwise, crypto operations will fail with Incompatible * MGF1 digest. - * If the MGF1 Digest setter flag isn't set, then the condition in the - * if clause above must be false (cannot have MGF1 digests specified if the - * flag was off). In that case, in addition to adding the default MGF1 - * digest, we have to add all the other digests as MGF1 Digests. - * */ importArgs.add(KeyStore2ParameterUtils.makeEnum( KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, KeyProperties.Digest.toKeymaster(DEFAULT_MGF1_DIGEST) )); - if (!Flags.mgf1DigestSetter()) { - final int defaultMgf1Digest = KeyProperties.Digest.toKeymaster( - DEFAULT_MGF1_DIGEST); - for (String digest : spec.getDigests()) { - int digestToAddAsMgf1Digest = KeyProperties.Digest.toKeymaster( - digest); - // Do not add the default MGF1 digest as it has been added above. - if (digestToAddAsMgf1Digest != defaultMgf1Digest) { - importArgs.add(KeyStore2ParameterUtils.makeEnum( - KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, - digestToAddAsMgf1Digest - )); - } - } - } } } } diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index fd4522e02438..5ad144d50b87 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -160,6 +160,7 @@ android_library { "kotlinx-coroutines-core", "iconloader_base", "com_android_wm_shell_flags_lib", + "com.android.window.flags.window-aconfig-java", "WindowManager-Shell-proto", "dagger2", "jsr330", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index baa52a0b5626..5d161962be4a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -397,6 +397,9 @@ public class BubblePositioner { * the screen and the size of the elements around it (e.g. padding, pointer, manage button). */ public int getMaxExpandedViewHeight(boolean isOverflow) { + if (mDeviceConfig.isLargeScreen() && !mDeviceConfig.isSmallTablet() && !isOverflow) { + return getExpandedViewHeightForLargeScreen(); + } // Subtract top insets because availableRect.height would account for that int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top; int paddingTop = showBubblesVertically() @@ -414,6 +417,16 @@ public class BubblePositioner { - bottomPadding; } + private int getExpandedViewHeightForLargeScreen() { + // the expanded view height on large tablets is calculated based on the shortest screen + // size and is the same in both portrait and landscape + int maxVerticalInset = Math.max(mInsets.top, mInsets.bottom); + int shortestScreenSide = Math.min(getScreenRect().height(), getScreenRect().width()); + // Subtract pointer size because it's laid out in LinearLayout with the expanded view. + return shortestScreenSide - maxVerticalInset * 2 + - mManageButtonHeight - mPointerWidth - mExpandedViewPadding * 2; + } + /** * Determines the height for the bubble, ensuring a minimum height. If the height should be as * big as available, returns {@link #MAX_HEIGHT}. @@ -424,15 +437,6 @@ public class BubblePositioner { // overflow in landscape on phone is max return MAX_HEIGHT; } - - if (mDeviceConfig.isLargeScreen() && !mDeviceConfig.isSmallTablet() && !isOverflow) { - // the expanded view height on large tablets is calculated based on the shortest screen - // size and is the same in both portrait and landscape - int maxVerticalInset = Math.max(mInsets.top, mInsets.bottom); - int shortestScreenSide = Math.min(mScreenRect.height(), mScreenRect.width()); - return shortestScreenSide - 2 * maxVerticalInset - mManageButtonHeight; - } - float desiredHeight = isOverflow ? mOverflowHeight : ((Bubble) bubble).getDesiredHeight(mContext); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 91a8ce726c42..ff4da853654d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -1510,6 +1510,11 @@ public class BubbleStackView extends FrameLayout updateExpandedView(); } setUpManageMenu(); + if (mShowingManage) { + // the manage menu location depends on the manage button location which may need a + // layout pass, so post this to the looper + post(() -> showManageMenu(true)); + } } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java index 79f188ab2611..50e1f7311ce0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java @@ -67,6 +67,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView private boolean mIsOverflow; private BubbleTaskViewHelper mBubbleTaskViewHelper; private BubbleBarMenuViewController mMenuViewController; + private BubbleBarExpandedViewDragController mDragController; private @Nullable Supplier<Rect> mLayerBoundsSupplier; private @Nullable Listener mListener; @@ -180,6 +181,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView mHandleView.setOnClickListener(view -> { mMenuViewController.showMenu(true /* animated */); }); + + mDragController = new BubbleBarExpandedViewDragController(this); } public BubbleBarHandleView getHandleView() { @@ -386,4 +389,11 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView setContentVisibility(mIsContentVisible); } } + + /** + * Check whether the view is animating + */ + public boolean isAnimating() { + return mIsAnimating; + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt new file mode 100644 index 000000000000..933794be071e --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt @@ -0,0 +1,100 @@ +/* + * 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.wm.shell.bubbles.bar + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.graphics.PointF +import android.view.MotionEvent +import android.view.View +import com.android.wm.shell.animation.Interpolators +import com.android.wm.shell.common.bubbles.RelativeTouchListener + +/** Controller for handling drag interactions with [BubbleBarExpandedView] */ +class BubbleBarExpandedViewDragController(private val expandedView: BubbleBarExpandedView) { + + init { + expandedView.handleView.setOnTouchListener(HandleDragListener()) + } + + private fun resetExpandedViewPosition(initialX: Float, initialY: Float) { + val listener = object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator) { + expandedView.isAnimating = true + } + + override fun onAnimationEnd(animation: Animator) { + expandedView.isAnimating = false + } + } + expandedView.animate() + .translationX(initialX) + .translationY(initialY) + .setDuration(RESET_POSITION_ANIM_DURATION) + .setInterpolator(Interpolators.EMPHASIZED_DECELERATE) + .setListener(listener) + .start() + } + + private inner class HandleDragListener : RelativeTouchListener() { + + private val expandedViewRestPosition = PointF() + + override fun onDown(v: View, ev: MotionEvent): Boolean { + // While animating, don't allow new touch events + if (expandedView.isAnimating) { + return false + } + expandedViewRestPosition.x = expandedView.translationX + expandedViewRestPosition.y = expandedView.translationY + return true + } + + override fun onMove( + v: View, + ev: MotionEvent, + viewInitialX: Float, + viewInitialY: Float, + dx: Float, + dy: Float + ) { + expandedView.translationX = expandedViewRestPosition.x + dx + expandedView.translationY = expandedViewRestPosition.y + dy + } + + override fun onUp( + v: View, + ev: MotionEvent, + viewInitialX: Float, + viewInitialY: Float, + dx: Float, + dy: Float, + velX: Float, + velY: Float + ) { + resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y) + } + + override fun onCancel(v: View, ev: MotionEvent, viewInitialX: Float, viewInitialY: Float) { + resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y) + } + } + + companion object { + const val RESET_POSITION_ANIM_DURATION = 300L + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt index d45e1265daac..4e55ba23407b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt @@ -78,8 +78,15 @@ abstract class RelativeTouchListener : View.OnTouchListener { velY: Float ) + open fun onCancel( + v: View, + ev: MotionEvent, + viewInitialX: Float, + viewInitialY: Float + ) {} + /** The raw coordinates of the last ACTION_DOWN event. */ - private val touchDown = PointF() + private var touchDown: PointF? = null /** The coordinates of the view, at the time of the last ACTION_DOWN event. */ private val viewPositionOnTouchDown = PointF() @@ -91,12 +98,11 @@ abstract class RelativeTouchListener : View.OnTouchListener { private var performedLongClick = false - @Suppress("UNCHECKED_CAST") override fun onTouch(v: View, ev: MotionEvent): Boolean { addMovement(ev) - val dx = ev.rawX - touchDown.x - val dy = ev.rawY - touchDown.y + val dx = touchDown?.let { ev.rawX - it.x } ?: 0f + val dy = touchDown?.let { ev.rawY - it.y } ?: 0f when (ev.action) { MotionEvent.ACTION_DOWN -> { @@ -108,7 +114,7 @@ abstract class RelativeTouchListener : View.OnTouchListener { // last gesture. touchSlop = ViewConfiguration.get(v.context).scaledTouchSlop - touchDown.set(ev.rawX, ev.rawY) + touchDown = PointF(ev.rawX, ev.rawY) viewPositionOnTouchDown.set(v.translationX, v.translationY) performedLongClick = false @@ -120,6 +126,7 @@ abstract class RelativeTouchListener : View.OnTouchListener { } MotionEvent.ACTION_MOVE -> { + if (touchDown == null) return false if (!movedEnough && hypot(dx, dy) > touchSlop && !performedLongClick) { movedEnough = true v.handler?.removeCallbacksAndMessages(null) @@ -131,6 +138,7 @@ abstract class RelativeTouchListener : View.OnTouchListener { } MotionEvent.ACTION_UP -> { + if (touchDown == null) return false if (movedEnough) { velocityTracker.computeCurrentVelocity(1000 /* units */) onUp(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y, dx, dy, @@ -143,12 +151,16 @@ abstract class RelativeTouchListener : View.OnTouchListener { velocityTracker.clear() movedEnough = false + touchDown = null } MotionEvent.ACTION_CANCEL -> { + if (touchDown == null) return false v.handler?.removeCallbacksAndMessages(null) velocityTracker.clear() movedEnough = false + touchDown = null + onCancel(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index b158f88a68c3..3c6bc1754c5c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -324,13 +324,16 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static SystemPerformanceHinter provideSystemPerformanceHinter(Context context, + static Optional<SystemPerformanceHinter> provideSystemPerformanceHinter(Context context, ShellInit shellInit, ShellCommandHandler shellCommandHandler, RootTaskDisplayAreaOrganizer rootTdaOrganizer) { + if (!com.android.window.flags.Flags.explicitRefreshRateHints()) { + return Optional.empty(); + } final PerfHintController perfHintController = new PerfHintController(context, shellInit, shellCommandHandler, rootTdaOrganizer); - return perfHintController.getHinter(); + return Optional.of(perfHintController.getHinter()); } // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index fdd30448995f..c1164fca22f2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -123,7 +123,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private static final int EXTRA_CONTENT_OVERLAY_FADE_OUT_DELAY_MS = SystemProperties.getInt( - "persist.wm.debug.extra_content_overlay_fade_out_delay_ms", 450); + "persist.wm.debug.extra_content_overlay_fade_out_delay_ms", 400); private final Context mContext; private final SyncTransactionQueue mSyncTransactionQueue; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 36e0eb4dc389..be685b57f779 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -2210,7 +2210,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, * create a top-bottom split. */ boolean isLeftRightSplit() { - return mSplitLayout.isLeftRightSplit(); + return mSplitLayout != null && mSplitLayout.isLeftRightSplit(); } /** diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java index 835ebe2206ad..e5ae6e515566 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java @@ -16,10 +16,15 @@ package com.android.wm.shell.bubbles; +import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT; + import static com.google.common.truth.Truth.assertThat; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static org.mockito.Mockito.mock; + import android.content.Intent; +import android.content.pm.ShortcutInfo; import android.graphics.Insets; import android.graphics.PointF; import android.graphics.Rect; @@ -226,7 +231,7 @@ public class BubblePositionerTest extends ShellTestCase { } @Test - public void testExpandedViewHeight_onLargeTablet() { + public void testGetExpandedViewHeight_max() { Insets insets = Insets.of(10, 20, 5, 15); Rect screenBounds = new Rect(0, 0, 1800, 2600); @@ -240,10 +245,91 @@ public class BubblePositionerTest extends ShellTestCase { Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); + assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT); + } + + @Test + public void testGetExpandedViewHeight_customHeight_valid() { + Insets insets = Insets.of(10, 20, 5, 15); + Rect screenBounds = new Rect(0, 0, 1800, 2600); + + DeviceConfig deviceConfig = new ConfigBuilder() + .setLargeScreen() + .setInsets(insets) + .setScreenBounds(screenBounds) + .build(); + mPositioner.update(deviceConfig); + + final int minHeight = mContext.getResources().getDimensionPixelSize( + R.dimen.bubble_expanded_default_height); + Bubble bubble = new Bubble("key", + mock(ShortcutInfo.class), + minHeight + 100 /* desiredHeight */, + 0 /* desiredHeightResId */, + "title", + 0 /* taskId */, + null /* locus */, + true /* isDismissable */, + directExecutor(), + mock(Bubbles.BubbleMetadataFlagListener.class)); + + // Ensure the height is the same as the desired value + assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo( + bubble.getDesiredHeight(mContext)); + } + + + @Test + public void testGetExpandedViewHeight_customHeight_tooSmall() { + Insets insets = Insets.of(10, 20, 5, 15); + Rect screenBounds = new Rect(0, 0, 1800, 2600); + + DeviceConfig deviceConfig = new ConfigBuilder() + .setLargeScreen() + .setInsets(insets) + .setScreenBounds(screenBounds) + .build(); + mPositioner.update(deviceConfig); + + Bubble bubble = new Bubble("key", + mock(ShortcutInfo.class), + 10 /* desiredHeight */, + 0 /* desiredHeightResId */, + "title", + 0 /* taskId */, + null /* locus */, + true /* isDismissable */, + directExecutor(), + mock(Bubbles.BubbleMetadataFlagListener.class)); + + // Ensure the height is the same as the minimum value + final int minHeight = mContext.getResources().getDimensionPixelSize( + R.dimen.bubble_expanded_default_height); + assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo(minHeight); + } + + @Test + public void testGetMaxExpandedViewHeight_onLargeTablet() { + Insets insets = Insets.of(10, 20, 5, 15); + Rect screenBounds = new Rect(0, 0, 1800, 2600); + + DeviceConfig deviceConfig = new ConfigBuilder() + .setLargeScreen() + .setInsets(insets) + .setScreenBounds(screenBounds) + .build(); + mPositioner.update(deviceConfig); + int manageButtonHeight = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height); - float expectedHeight = 1800 - 2 * 20 - manageButtonHeight; - assertThat(mPositioner.getExpandedViewHeight(bubble)).isWithin(0.1f).of(expectedHeight); + int pointerWidth = mContext.getResources().getDimensionPixelSize( + R.dimen.bubble_pointer_width); + int expandedViewPadding = mContext.getResources().getDimensionPixelSize(R + .dimen.bubble_expanded_view_padding); + float expectedHeight = 1800 - 2 * 20 - manageButtonHeight - pointerWidth + - expandedViewPadding * 2; + assertThat(((float) mPositioner.getMaxExpandedViewHeight(false /* isOverflow */))) + .isWithin(0.1f).of(expectedHeight); } /** diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 47a7f3579764..2f28363aedc7 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -63,15 +63,21 @@ cc_library { "AssetsProvider.cpp", "AttributeResolution.cpp", "BigBuffer.cpp", + "BigBufferStream.cpp", "ChunkIterator.cpp", "ConfigDescription.cpp", + "FileStream.cpp", "Idmap.cpp", "LoadedArsc.cpp", "Locale.cpp", "LocaleData.cpp", "misc.cpp", + "NinePatch.cpp", "ObbFile.cpp", "PosixUtils.cpp", + "Png.cpp", + "PngChunkFilter.cpp", + "PngCrunch.cpp", "ResourceTimer.cpp", "ResourceTypes.cpp", "ResourceUtils.cpp", @@ -84,7 +90,10 @@ cc_library { ], export_include_dirs: ["include"], export_shared_lib_headers: ["libz"], - static_libs: ["libincfs-utils"], + static_libs: [ + "libincfs-utils", + "libpng", + ], whole_static_libs: [ "libandroidfw_pathutils", "libincfs-utils", @@ -198,9 +207,11 @@ cc_test { "tests/ConfigDescription_test.cpp", "tests/ConfigLocale_test.cpp", "tests/DynamicRefTable_test.cpp", + "tests/FileStream_test.cpp", "tests/Idmap_test.cpp", "tests/LoadedArsc_test.cpp", "tests/Locale_test.cpp", + "tests/NinePatch_test.cpp", "tests/ResourceTimer_test.cpp", "tests/ResourceUtils_test.cpp", "tests/ResTable_test.cpp", diff --git a/tools/aapt2/io/BigBufferStream.cpp b/libs/androidfw/BigBufferStream.cpp index 9704caae4719..f18199cfa52b 100644 --- a/tools/aapt2/io/BigBufferStream.cpp +++ b/libs/androidfw/BigBufferStream.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include "io/BigBufferStream.h" +#include "androidfw/BigBufferStream.h" -namespace aapt { -namespace io { +#include <algorithm> + +namespace android { // // BigBufferInputStream @@ -76,6 +77,34 @@ size_t BigBufferInputStream::TotalSize() const { return buffer_->size(); } +bool BigBufferInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) { + if (byte_count == 0) { + return true; + } + if (offset < 0) { + return false; + } + if (offset > std::numeric_limits<off64_t>::max() - byte_count) { + return false; + } + if (offset + byte_count > buffer_->size()) { + return false; + } + auto p = reinterpret_cast<uint8_t*>(data); + for (auto iter = buffer_->begin(); iter != buffer_->end() && byte_count > 0; ++iter) { + if (offset < iter->size) { + size_t to_read = std::min(byte_count, (size_t)(iter->size - offset)); + memcpy(p, iter->buffer.get() + offset, to_read); + byte_count -= to_read; + p += to_read; + offset = 0; + } else { + offset -= iter->size; + } + } + return byte_count == 0; +} + // // BigBufferOutputStream // @@ -97,5 +126,4 @@ bool BigBufferOutputStream::HadError() const { return false; } -} // namespace io -} // namespace aapt +} // namespace android diff --git a/tools/aapt2/io/FileStream.cpp b/libs/androidfw/FileStream.cpp index 27529bc08a16..b86c9cb729d4 100644 --- a/tools/aapt2/io/FileStream.cpp +++ b/libs/androidfw/FileStream.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "io/FileStream.h" +#include "androidfw/FileStream.h" #include <errno.h> // for errno #include <fcntl.h> // for O_RDONLY @@ -34,8 +34,7 @@ using ::android::base::SystemErrorCodeToString; using ::android::base::unique_fd; -namespace aapt { -namespace io { +namespace android { FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity) : buffer_capacity_(buffer_capacity) { @@ -108,6 +107,10 @@ std::string FileInputStream::GetError() const { return error_; } +bool FileInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) { + return base::ReadFullyAtOffset(fd_, data, byte_count, offset); +} + FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity) : buffer_capacity_(buffer_capacity) { int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY; @@ -199,5 +202,4 @@ std::string FileOutputStream::GetError() const { return error_; } -} // namespace io -} // namespace aapt +} // namespace android diff --git a/tools/aapt2/compile/NinePatch.cpp b/libs/androidfw/NinePatch.cpp index 4538ecc56e4c..1fdbebfb6daa 100644 --- a/tools/aapt2/compile/NinePatch.cpp +++ b/libs/androidfw/NinePatch.cpp @@ -14,20 +14,17 @@ * limitations under the License. */ -#include "compile/Image.h" - #include <sstream> #include <string> #include <vector> +#include "androidfw/Image.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" -#include "util/Util.h" - using android::StringPiece; -namespace aapt { +namespace android { // Colors in the format 0xAARRGGBB (the way 9-patch expects it). constexpr static const uint32_t kColorOpaqueWhite = 0xffffffffu; @@ -90,10 +87,8 @@ class ColorValidator { // }; // template <typename ImageLine> -static bool FillRanges(const ImageLine* image_line, - const ColorValidator* color_validator, - std::vector<Range>* primary_ranges, - std::vector<Range>* secondary_ranges, +static bool FillRanges(const ImageLine* image_line, const ColorValidator* color_validator, + std::vector<Range>* primary_ranges, std::vector<Range>* secondary_ranges, std::string* out_err) { const int32_t length = image_line->GetLength(); @@ -133,11 +128,13 @@ static bool FillRanges(const ImageLine* image_line, */ class HorizontalImageLine { public: - explicit HorizontalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, - int32_t length) - : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {} + explicit HorizontalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, int32_t length) + : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) { + } - inline int32_t GetLength() const { return length_; } + inline int32_t GetLength() const { + return length_; + } inline uint32_t GetColor(int32_t idx) const { return NinePatch::PackRGBA(rows_[yoffset_] + (idx + xoffset_) * 4); @@ -156,11 +153,13 @@ class HorizontalImageLine { */ class VerticalImageLine { public: - explicit VerticalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, - int32_t length) - : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) {} + explicit VerticalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, int32_t length) + : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), length_(length) { + } - inline int32_t GetLength() const { return length_; } + inline int32_t GetLength() const { + return length_; + } inline uint32_t GetColor(int32_t idx) const { return NinePatch::PackRGBA(rows_[yoffset_ + idx] + (xoffset_ * 4)); @@ -175,20 +174,22 @@ class VerticalImageLine { class DiagonalImageLine { public: - explicit DiagonalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, - int32_t xstep, int32_t ystep, int32_t length) + explicit DiagonalImageLine(uint8_t** rows, int32_t xoffset, int32_t yoffset, int32_t xstep, + int32_t ystep, int32_t length) : rows_(rows), xoffset_(xoffset), yoffset_(yoffset), xstep_(xstep), ystep_(ystep), - length_(length) {} + length_(length) { + } - inline int32_t GetLength() const { return length_; } + inline int32_t GetLength() const { + return length_; + } inline uint32_t GetColor(int32_t idx) const { - return NinePatch::PackRGBA(rows_[yoffset_ + (idx * ystep_)] + - ((idx + xoffset_) * xstep_) * 4); + return NinePatch::PackRGBA(rows_[yoffset_ + (idx * ystep_)] + ((idx + xoffset_) * xstep_) * 4); } private: @@ -243,8 +244,7 @@ static bool PopulateBounds(const std::vector<Range>& padding, if (layout_bounds.size() > 2) { std::stringstream err_stream; - err_stream << "too many layout bounds sections on " << edge_name - << " border"; + err_stream << "too many layout bounds sections on " << edge_name << " border"; *out_err = err_stream.str(); return false; } @@ -258,8 +258,7 @@ static bool PopulateBounds(const std::vector<Range>& padding, // end at length. if (range.start != 0 && range.end != length) { std::stringstream err_stream; - err_stream << "layout bounds on " << edge_name - << " border must start at edge"; + err_stream << "layout bounds on " << edge_name << " border must start at edge"; *out_err = err_stream.str(); return false; } @@ -269,8 +268,7 @@ static bool PopulateBounds(const std::vector<Range>& padding, const Range& range = layout_bounds.back(); if (range.end != length) { std::stringstream err_stream; - err_stream << "layout bounds on " << edge_name - << " border must start at edge"; + err_stream << "layout bounds on " << edge_name << " border must start at edge"; *out_err = err_stream.str(); return false; } @@ -280,8 +278,7 @@ static bool PopulateBounds(const std::vector<Range>& padding, return true; } -static int32_t CalculateSegmentCount(const std::vector<Range>& stretch_regions, - int32_t length) { +static int32_t CalculateSegmentCount(const std::vector<Range>& stretch_regions, int32_t length) { if (stretch_regions.size() == 0) { return 0; } @@ -299,8 +296,7 @@ static int32_t CalculateSegmentCount(const std::vector<Range>& stretch_regions, static uint32_t GetRegionColor(uint8_t** rows, const Bounds& region) { // Sample the first pixel to compare against. - const uint32_t expected_color = - NinePatch::PackRGBA(rows[region.top] + region.left * 4); + const uint32_t expected_color = NinePatch::PackRGBA(rows[region.top] + region.left * 4); for (int32_t y = region.top; y < region.bottom; y++) { const uint8_t* row = rows[y]; for (int32_t x = region.left; x < region.right; x++) { @@ -336,10 +332,11 @@ static uint32_t GetRegionColor(uint8_t** rows, const Bounds& region) { // the indices must be offset by 1. // // width and height also include the 9-patch 1px border. -static void CalculateRegionColors( - uint8_t** rows, const std::vector<Range>& horizontal_stretch_regions, - const std::vector<Range>& vertical_stretch_regions, const int32_t width, - const int32_t height, std::vector<uint32_t>* out_colors) { +static void CalculateRegionColors(uint8_t** rows, + const std::vector<Range>& horizontal_stretch_regions, + const std::vector<Range>& vertical_stretch_regions, + const int32_t width, const int32_t height, + std::vector<uint32_t>* out_colors) { int32_t next_top = 0; Bounds bounds; auto row_iter = vertical_stretch_regions.begin(); @@ -401,8 +398,7 @@ static void CalculateRegionColors( // alpha value begins // (on both sides). template <typename ImageLine> -static void FindOutlineInsets(const ImageLine* image_line, int32_t* out_start, - int32_t* out_end) { +static void FindOutlineInsets(const ImageLine* image_line, int32_t* out_start, int32_t* out_end) { *out_start = 0; *out_end = 0; @@ -455,10 +451,8 @@ uint32_t NinePatch::PackRGBA(const uint8_t* pixel) { return (pixel[3] << 24) | (pixel[0] << 16) | (pixel[1] << 8) | pixel[2]; } -std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, - const int32_t width, - const int32_t height, - std::string* out_err) { +std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, const int32_t width, + const int32_t height, std::string* out_err) { if (width < 3 || height < 3) { *out_err = "image must be at least 3x3 (1x1 image with 1 pixel border)"; return {}; @@ -472,12 +466,11 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, std::unique_ptr<ColorValidator> color_validator; if (rows[0][3] == 0) { - color_validator = util::make_unique<TransparentNeutralColorValidator>(); + color_validator = std::make_unique<TransparentNeutralColorValidator>(); } else if (PackRGBA(rows[0]) == kColorOpaqueWhite) { - color_validator = util::make_unique<WhiteNeutralColorValidator>(); + color_validator = std::make_unique<WhiteNeutralColorValidator>(); } else { - *out_err = - "top-left corner pixel must be either opaque white or transparent"; + *out_err = "top-left corner pixel must be either opaque white or transparent"; return {}; } @@ -485,9 +478,8 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, auto nine_patch = std::unique_ptr<NinePatch>(new NinePatch()); HorizontalImageLine top_row(rows, 0, 0, width); - if (!FillRanges(&top_row, color_validator.get(), - &nine_patch->horizontal_stretch_regions, &unexpected_ranges, - out_err)) { + if (!FillRanges(&top_row, color_validator.get(), &nine_patch->horizontal_stretch_regions, + &unexpected_ranges, out_err)) { return {}; } @@ -501,9 +493,8 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, } VerticalImageLine left_col(rows, 0, 0, height); - if (!FillRanges(&left_col, color_validator.get(), - &nine_patch->vertical_stretch_regions, &unexpected_ranges, - out_err)) { + if (!FillRanges(&left_col, color_validator.get(), &nine_patch->vertical_stretch_regions, + &unexpected_ranges, out_err)) { return {}; } @@ -522,32 +513,28 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, } if (!PopulateBounds(horizontal_padding, horizontal_layout_bounds, - nine_patch->horizontal_stretch_regions, width - 2, - &nine_patch->padding.left, &nine_patch->padding.right, - &nine_patch->layout_bounds.left, + nine_patch->horizontal_stretch_regions, width - 2, &nine_patch->padding.left, + &nine_patch->padding.right, &nine_patch->layout_bounds.left, &nine_patch->layout_bounds.right, "bottom", out_err)) { return {}; } VerticalImageLine right_col(rows, width - 1, 0, height); - if (!FillRanges(&right_col, color_validator.get(), &vertical_padding, - &vertical_layout_bounds, out_err)) { + if (!FillRanges(&right_col, color_validator.get(), &vertical_padding, &vertical_layout_bounds, + out_err)) { return {}; } if (!PopulateBounds(vertical_padding, vertical_layout_bounds, - nine_patch->vertical_stretch_regions, height - 2, - &nine_patch->padding.top, &nine_patch->padding.bottom, - &nine_patch->layout_bounds.top, + nine_patch->vertical_stretch_regions, height - 2, &nine_patch->padding.top, + &nine_patch->padding.bottom, &nine_patch->layout_bounds.top, &nine_patch->layout_bounds.bottom, "right", out_err)) { return {}; } // Fill the region colors of the 9-patch. - const int32_t num_rows = - CalculateSegmentCount(nine_patch->horizontal_stretch_regions, width - 2); - const int32_t num_cols = - CalculateSegmentCount(nine_patch->vertical_stretch_regions, height - 2); + const int32_t num_rows = CalculateSegmentCount(nine_patch->horizontal_stretch_regions, width - 2); + const int32_t num_cols = CalculateSegmentCount(nine_patch->vertical_stretch_regions, height - 2); if ((int64_t)num_rows * (int64_t)num_cols > 0x7f) { *out_err = "too many regions in 9-patch"; return {}; @@ -555,40 +542,35 @@ std::unique_ptr<NinePatch> NinePatch::Create(uint8_t** rows, nine_patch->region_colors.reserve(num_rows * num_cols); CalculateRegionColors(rows, nine_patch->horizontal_stretch_regions, - nine_patch->vertical_stretch_regions, width - 2, - height - 2, &nine_patch->region_colors); + nine_patch->vertical_stretch_regions, width - 2, height - 2, + &nine_patch->region_colors); // Compute the outline based on opacity. // Find left and right extent of 9-patch content on center row. HorizontalImageLine mid_row(rows, 1, height / 2, width - 2); - FindOutlineInsets(&mid_row, &nine_patch->outline.left, - &nine_patch->outline.right); + FindOutlineInsets(&mid_row, &nine_patch->outline.left, &nine_patch->outline.right); // Find top and bottom extent of 9-patch content on center column. VerticalImageLine mid_col(rows, width / 2, 1, height - 2); - FindOutlineInsets(&mid_col, &nine_patch->outline.top, - &nine_patch->outline.bottom); + FindOutlineInsets(&mid_col, &nine_patch->outline.top, &nine_patch->outline.bottom); - const int32_t outline_width = - (width - 2) - nine_patch->outline.left - nine_patch->outline.right; + const int32_t outline_width = (width - 2) - nine_patch->outline.left - nine_patch->outline.right; const int32_t outline_height = (height - 2) - nine_patch->outline.top - nine_patch->outline.bottom; // Find the largest alpha value within the outline area. - HorizontalImageLine outline_mid_row( - rows, 1 + nine_patch->outline.left, - 1 + nine_patch->outline.top + (outline_height / 2), outline_width); - VerticalImageLine outline_mid_col( - rows, 1 + nine_patch->outline.left + (outline_width / 2), - 1 + nine_patch->outline.top, outline_height); + HorizontalImageLine outline_mid_row(rows, 1 + nine_patch->outline.left, + 1 + nine_patch->outline.top + (outline_height / 2), + outline_width); + VerticalImageLine outline_mid_col(rows, 1 + nine_patch->outline.left + (outline_width / 2), + 1 + nine_patch->outline.top, outline_height); nine_patch->outline_alpha = std::max(FindMaxAlpha(&outline_mid_row), FindMaxAlpha(&outline_mid_col)); // Assuming the image is a round rect, compute the radius by marching // diagonally from the top left corner towards the center. - DiagonalImageLine diagonal(rows, 1 + nine_patch->outline.left, - 1 + nine_patch->outline.top, 1, 1, + DiagonalImageLine diagonal(rows, 1 + nine_patch->outline.left, 1 + nine_patch->outline.top, 1, 1, std::min(outline_width, outline_height)); int32_t top_left, bottom_right; FindOutlineInsets(&diagonal, &top_left, &bottom_right); @@ -614,10 +596,9 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeBase(size_t* outLen) const { data.paddingBottom = padding.bottom; auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[data.serializedSize()]); - android::Res_png_9patch::serialize( - data, (const int32_t*)horizontal_stretch_regions.data(), - (const int32_t*)vertical_stretch_regions.data(), region_colors.data(), - buffer.get()); + android::Res_png_9patch::serialize(data, (const int32_t*)horizontal_stretch_regions.data(), + (const int32_t*)vertical_stretch_regions.data(), + region_colors.data(), buffer.get()); // Convert to file endianness. reinterpret_cast<android::Res_png_9patch*>(buffer.get())->deviceToFile(); @@ -625,8 +606,7 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeBase(size_t* outLen) const { return buffer; } -std::unique_ptr<uint8_t[]> NinePatch::SerializeLayoutBounds( - size_t* out_len) const { +std::unique_ptr<uint8_t[]> NinePatch::SerializeLayoutBounds(size_t* out_len) const { size_t chunk_len = sizeof(uint32_t) * 4; auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunk_len]); uint8_t* cursor = buffer.get(); @@ -647,8 +627,7 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeLayoutBounds( return buffer; } -std::unique_ptr<uint8_t[]> NinePatch::SerializeRoundedRectOutline( - size_t* out_len) const { +std::unique_ptr<uint8_t[]> NinePatch::SerializeRoundedRectOutline(size_t* out_len) const { size_t chunk_len = sizeof(uint32_t) * 6; auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunk_len]); uint8_t* cursor = buffer.get(); @@ -679,20 +658,25 @@ std::unique_ptr<uint8_t[]> NinePatch::SerializeRoundedRectOutline( } ::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds) { - return out << "l=" << bounds.left << " t=" << bounds.top - << " r=" << bounds.right << " b=" << bounds.bottom; + return out << "l=" << bounds.left << " t=" << bounds.top << " r=" << bounds.right + << " b=" << bounds.bottom; +} + +template <typename T> +std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) { + for (int i = 0; i < v.size(); ++i) { + os << v[i]; + if (i != v.size() - 1) os << " "; + } + return os; } ::std::ostream& operator<<(::std::ostream& out, const NinePatch& nine_patch) { - return out << "horizontalStretch:" - << util::Joiner(nine_patch.horizontal_stretch_regions, " ") - << " verticalStretch:" - << util::Joiner(nine_patch.vertical_stretch_regions, " ") - << " padding: " << nine_patch.padding - << ", bounds: " << nine_patch.layout_bounds - << ", outline: " << nine_patch.outline - << " rad=" << nine_patch.outline_radius + return out << "horizontalStretch:" << nine_patch.horizontal_stretch_regions + << " verticalStretch:" << nine_patch.vertical_stretch_regions + << " padding: " << nine_patch.padding << ", bounds: " << nine_patch.layout_bounds + << ", outline: " << nine_patch.outline << " rad=" << nine_patch.outline_radius << " alpha=" << nine_patch.outline_alpha; } -} // namespace aapt +} // namespace android diff --git a/tools/aapt2/compile/Png.cpp b/libs/androidfw/Png.cpp index 76db815129dd..fb45cd9b49d0 100644 --- a/tools/aapt2/compile/Png.cpp +++ b/libs/androidfw/Png.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Png.h" +#include "androidfw/Png.h" #include <png.h> #include <zlib.h> @@ -24,13 +24,12 @@ #include <string> #include <vector> +#include "android-base/strings.h" #include "androidfw/BigBuffer.h" #include "androidfw/ResourceTypes.h" #include "androidfw/Source.h" -#include "trace/TraceBuffer.h" -#include "util/Util.h" -namespace aapt { +namespace android { constexpr bool kDebug = false; @@ -47,9 +46,8 @@ struct PngInfo { } void* serialize9Patch() { - void* serialized = android::Res_png_9patch::serialize(info9Patch, xDivs, - yDivs, colors.data()); - reinterpret_cast<android::Res_png_9patch*>(serialized)->deviceToFile(); + void* serialized = Res_png_9patch::serialize(info9Patch, xDivs, yDivs, colors.data()); + reinterpret_cast<Res_png_9patch*>(serialized)->deviceToFile(); return serialized; } @@ -58,7 +56,7 @@ struct PngInfo { std::vector<png_bytep> rows; bool is9Patch = false; - android::Res_png_9patch info9Patch; + Res_png_9patch info9Patch; int32_t* xDivs = nullptr; int32_t* yDivs = nullptr; std::vector<uint32_t> colors; @@ -79,34 +77,30 @@ struct PngInfo { uint8_t outlineAlpha; }; -static void readDataFromStream(png_structp readPtr, png_bytep data, - png_size_t length) { - std::istream* input = - reinterpret_cast<std::istream*>(png_get_io_ptr(readPtr)); +static void readDataFromStream(png_structp readPtr, png_bytep data, png_size_t length) { + std::istream* input = reinterpret_cast<std::istream*>(png_get_io_ptr(readPtr)); if (!input->read(reinterpret_cast<char*>(data), length)) { png_error(readPtr, strerror(errno)); } } -static void writeDataToStream(png_structp writePtr, png_bytep data, - png_size_t length) { - android::BigBuffer* outBuffer = reinterpret_cast<android::BigBuffer*>(png_get_io_ptr(writePtr)); +static void writeDataToStream(png_structp writePtr, png_bytep data, png_size_t length) { + BigBuffer* outBuffer = reinterpret_cast<BigBuffer*>(png_get_io_ptr(writePtr)); png_bytep buf = outBuffer->NextBlock<png_byte>(length); memcpy(buf, data, length); } -static void flushDataToStream(png_structp /*writePtr*/) {} +static void flushDataToStream(png_structp /*writePtr*/) { +} static void logWarning(png_structp readPtr, png_const_charp warningMessage) { - android::IDiagnostics* diag = - reinterpret_cast<android::IDiagnostics*>(png_get_error_ptr(readPtr)); - diag->Warn(android::DiagMessage() << warningMessage); + IDiagnostics* diag = reinterpret_cast<IDiagnostics*>(png_get_error_ptr(readPtr)); + diag->Warn(DiagMessage() << warningMessage); } -static bool readPng(android::IDiagnostics* diag, png_structp readPtr, png_infop infoPtr, - PngInfo* outInfo) { +static bool readPng(IDiagnostics* diag, png_structp readPtr, png_infop infoPtr, PngInfo* outInfo) { if (setjmp(png_jmpbuf(readPtr))) { - diag->Error(android::DiagMessage() << "failed reading png"); + diag->Error(DiagMessage() << "failed reading png"); return false; } @@ -114,8 +108,8 @@ static bool readPng(android::IDiagnostics* diag, png_structp readPtr, png_infop png_read_info(readPtr, infoPtr); int colorType, bitDepth, interlaceType, compressionType; - png_get_IHDR(readPtr, infoPtr, &outInfo->width, &outInfo->height, &bitDepth, - &colorType, &interlaceType, &compressionType, nullptr); + png_get_IHDR(readPtr, infoPtr, &outInfo->width, &outInfo->height, &bitDepth, &colorType, + &interlaceType, &compressionType, nullptr); if (colorType == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(readPtr); @@ -137,8 +131,7 @@ static bool readPng(android::IDiagnostics* diag, png_structp readPtr, png_infop png_set_add_alpha(readPtr, 0xFF, PNG_FILLER_AFTER); } - if (colorType == PNG_COLOR_TYPE_GRAY || - colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { + if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(readPtr); } @@ -156,12 +149,11 @@ static bool readPng(android::IDiagnostics* diag, png_structp readPtr, png_infop return true; } -static void checkNinePatchSerialization(android::Res_png_9patch* inPatch, - void* data) { +static void checkNinePatchSerialization(Res_png_9patch* inPatch, void* data) { size_t patchSize = inPatch->serializedSize(); void* newData = malloc(patchSize); memcpy(newData, data, patchSize); - android::Res_png_9patch* outPatch = inPatch->deserialize(newData); + Res_png_9patch* outPatch = inPatch->deserialize(newData); outPatch->fileToDevice(); // deserialization is done in place, so outPatch == newData assert(outPatch == newData); @@ -244,10 +236,9 @@ PNG_COLOR_TYPE_RGB_ALPHA) { #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define ABS(a) ((a) < 0 ? -(a) : (a)) -static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, - int grayscaleTolerance, png_colorp rgbPalette, png_bytep alphaPalette, - int* paletteEntries, bool* hasTransparency, int* colorType, - png_bytepp outRows) { +static void analyze_image(IDiagnostics* diag, const PngInfo& imageInfo, int grayscaleTolerance, + png_colorp rgbPalette, png_bytep alphaPalette, int* paletteEntries, + bool* hasTransparency, int* colorType, png_bytepp outRows) { int w = imageInfo.width; int h = imageInfo.height; int i, j, rr, gg, bb, aa, idx; @@ -284,8 +275,8 @@ static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, maxGrayDeviation = MAX(ABS(bb - rr), maxGrayDeviation); if (maxGrayDeviation > odev) { if (kDebug) { - printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n", - maxGrayDeviation, i, j, rr, gg, bb, aa); + printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n", maxGrayDeviation, i, j, + rr, gg, bb, aa); } } @@ -293,8 +284,7 @@ static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, if (isGrayscale) { if (rr != gg || rr != bb) { if (kDebug) { - printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n", i, j, - rr, gg, bb, aa); + printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n", i, j, rr, gg, bb, aa); } isGrayscale = false; } @@ -304,8 +294,7 @@ static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, if (isOpaque) { if (aa != 0xff) { if (kDebug) { - printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n", i, j, - rr, gg, bb, aa); + printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n", i, j, rr, gg, bb, aa); } isOpaque = false; } @@ -349,10 +338,9 @@ static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, printf("isGrayscale = %s\n", isGrayscale ? "true" : "false"); printf("isOpaque = %s\n", isOpaque ? "true" : "false"); printf("isPalette = %s\n", isPalette ? "true" : "false"); - printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n", paletteSize, - 2 * w * h, bpp * w * h); - printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, - grayscaleTolerance); + printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n", paletteSize, 2 * w * h, + bpp * w * h); + printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance); } // Choose the best color type for the image. @@ -381,8 +369,8 @@ static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, *colorType = PNG_COLOR_TYPE_PALETTE; } else { if (maxGrayDeviation <= grayscaleTolerance) { - diag->Note(android::DiagMessage() - << "forcing image to gray (max deviation = " << maxGrayDeviation << ")"); + diag->Note(DiagMessage() << "forcing image to gray (max deviation = " << maxGrayDeviation + << ")"); *colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA; } else { *colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA; @@ -404,8 +392,7 @@ static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, rgbPalette[idx].blue = (png_byte)((col >> 8) & 0xff); alphaPalette[idx] = (png_byte)(col & 0xff); } - } else if (*colorType == PNG_COLOR_TYPE_GRAY || - *colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { + } else if (*colorType == PNG_COLOR_TYPE_GRAY || *colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { // If the image is gray or gray + alpha, compact the pixels into outRows for (j = 0; j < h; j++) { const png_byte* row = imageInfo.rows[j]; @@ -429,10 +416,10 @@ static void analyze_image(android::IDiagnostics* diag, const PngInfo& imageInfo, } } -static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_infop infoPtr, - PngInfo* info, int grayScaleTolerance) { +static bool writePng(IDiagnostics* diag, png_structp writePtr, png_infop infoPtr, PngInfo* info, + int grayScaleTolerance) { if (setjmp(png_jmpbuf(writePtr))) { - diag->Error(android::DiagMessage() << "failed to write png"); + diag->Error(DiagMessage() << "failed to write png"); return false; } @@ -444,8 +431,7 @@ static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_info unknowns[1].data = nullptr; unknowns[2].data = nullptr; - png_bytepp outRows = - (png_bytepp)malloc((int)info->height * sizeof(png_bytep)); + png_bytepp outRows = (png_bytepp)malloc((int)info->height * sizeof(png_bytep)); if (outRows == (png_bytepp)0) { printf("Can't allocate output buffer!\n"); exit(1); @@ -461,8 +447,7 @@ static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_info png_set_compression_level(writePtr, Z_BEST_COMPRESSION); if (kDebug) { - diag->Note(android::DiagMessage() - << "writing image: w = " << info->width << ", h = " << info->height); + diag->Note(DiagMessage() << "writing image: w = " << info->width << ", h = " << info->height); } png_color rgbPalette[256]; @@ -470,48 +455,45 @@ static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_info bool hasTransparency; int paletteEntries; - analyze_image(diag, *info, grayScaleTolerance, rgbPalette, alphaPalette, - &paletteEntries, &hasTransparency, &colorType, outRows); + analyze_image(diag, *info, grayScaleTolerance, rgbPalette, alphaPalette, &paletteEntries, + &hasTransparency, &colorType, outRows); // If the image is a 9-patch, we need to preserve it as a ARGB file to make // sure the pixels will not be pre-dithered/clamped until we decide they are - if (info->is9Patch && - (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY || - colorType == PNG_COLOR_TYPE_PALETTE)) { + if (info->is9Patch && (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY || + colorType == PNG_COLOR_TYPE_PALETTE)) { colorType = PNG_COLOR_TYPE_RGB_ALPHA; } if (kDebug) { switch (colorType) { case PNG_COLOR_TYPE_PALETTE: - diag->Note(android::DiagMessage() << "has " << paletteEntries << " colors" - << (hasTransparency ? " (with alpha)" : "") - << ", using PNG_COLOR_TYPE_PALLETTE"); + diag->Note(DiagMessage() << "has " << paletteEntries << " colors" + << (hasTransparency ? " (with alpha)" : "") + << ", using PNG_COLOR_TYPE_PALLETTE"); break; case PNG_COLOR_TYPE_GRAY: - diag->Note(android::DiagMessage() << "is opaque gray, using PNG_COLOR_TYPE_GRAY"); + diag->Note(DiagMessage() << "is opaque gray, using PNG_COLOR_TYPE_GRAY"); break; case PNG_COLOR_TYPE_GRAY_ALPHA: - diag->Note(android::DiagMessage() << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA"); + diag->Note(DiagMessage() << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA"); break; case PNG_COLOR_TYPE_RGB: - diag->Note(android::DiagMessage() << "is opaque RGB, using PNG_COLOR_TYPE_RGB"); + diag->Note(DiagMessage() << "is opaque RGB, using PNG_COLOR_TYPE_RGB"); break; case PNG_COLOR_TYPE_RGB_ALPHA: - diag->Note(android::DiagMessage() << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA"); + diag->Note(DiagMessage() << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA"); break; } } - png_set_IHDR(writePtr, infoPtr, info->width, info->height, 8, colorType, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); + png_set_IHDR(writePtr, infoPtr, info->width, info->height, 8, colorType, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (colorType == PNG_COLOR_TYPE_PALETTE) { png_set_PLTE(writePtr, infoPtr, rgbPalette, paletteEntries); if (hasTransparency) { - png_set_tRNS(writePtr, infoPtr, alphaPalette, paletteEntries, - (png_color_16p)0); + png_set_tRNS(writePtr, infoPtr, alphaPalette, paletteEntries, (png_color_16p)0); } png_set_filter(writePtr, 0, PNG_NO_FILTERS); } else { @@ -526,13 +508,12 @@ static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_info // Chunks ordered thusly because older platforms depend on the base 9 patch // data being last - png_bytep chunkNames = info->haveLayoutBounds - ? (png_bytep) "npOl\0npLb\0npTc\0" - : (png_bytep) "npOl\0npTc"; + png_bytep chunkNames = + info->haveLayoutBounds ? (png_bytep) "npOl\0npLb\0npTc\0" : (png_bytep) "npOl\0npTc"; // base 9 patch data if (kDebug) { - diag->Note(android::DiagMessage() << "adding 9-patch info.."); + diag->Note(DiagMessage() << "adding 9-patch info.."); } memcpy((char*)unknowns[pIndex].name, "npTc", 5); unknowns[pIndex].data = (png_byte*)info->serialize9Patch(); @@ -563,8 +544,7 @@ static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_info for (int i = 0; i < chunkCount; i++) { unknowns[i].location = PNG_HAVE_PLTE; } - png_set_keep_unknown_chunks(writePtr, PNG_HANDLE_CHUNK_ALWAYS, chunkNames, - chunkCount); + png_set_keep_unknown_chunks(writePtr, PNG_HANDLE_CHUNK_ALWAYS, chunkNames, chunkCount); png_set_unknown_chunks(writePtr, infoPtr, unknowns, chunkCount); #if PNG_LIBPNG_VER < 10600 @@ -579,8 +559,7 @@ static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_info png_write_info(writePtr, infoPtr); png_bytepp rows; - if (colorType == PNG_COLOR_TYPE_RGB || - colorType == PNG_COLOR_TYPE_RGB_ALPHA) { + if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) { if (colorType == PNG_COLOR_TYPE_RGB) { png_set_filler(writePtr, 0, PNG_FILLER_AFTER); } @@ -605,14 +584,13 @@ static bool writePng(android::IDiagnostics* diag, png_structp writePtr, png_info free(unknowns[1].data); free(unknowns[2].data); - png_get_IHDR(writePtr, infoPtr, &width, &height, &bitDepth, &colorType, - &interlaceType, &compressionType, nullptr); + png_get_IHDR(writePtr, infoPtr, &width, &height, &bitDepth, &colorType, &interlaceType, + &compressionType, nullptr); if (kDebug) { - diag->Note(android::DiagMessage() - << "image written: w = " << width << ", h = " << height << ", d = " << bitDepth - << ", colors = " << colorType << ", inter = " << interlaceType - << ", comp = " << compressionType); + diag->Note(DiagMessage() << "image written: w = " << width << ", h = " << height + << ", d = " << bitDepth << ", colors = " << colorType + << ", inter = " << interlaceType << ", comp = " << compressionType); } return true; } @@ -673,9 +651,8 @@ static TickType tickType(png_bytep p, bool transparent, const char** outError) { enum class TickState { kStart, kInside1, kOutside1 }; -static bool getHorizontalTicks(png_bytep row, int width, bool transparent, - bool required, int32_t* outLeft, - int32_t* outRight, const char** outError, +static bool getHorizontalTicks(png_bytep row, int width, bool transparent, bool required, + int32_t* outLeft, int32_t* outRight, const char** outError, uint8_t* outDivs, bool multipleAllowed) { *outLeft = *outRight = -1; TickState state = TickState::kStart; @@ -683,8 +660,7 @@ static bool getHorizontalTicks(png_bytep row, int width, bool transparent, for (int i = 1; i < width - 1; i++) { if (tickType(row + i * 4, transparent, outError) == TickType::kTick) { - if (state == TickState::kStart || - (state == TickState::kOutside1 && multipleAllowed)) { + if (state == TickState::kStart || (state == TickState::kOutside1 && multipleAllowed)) { *outLeft = i - 1; *outRight = width - 2; found = true; @@ -719,18 +695,16 @@ static bool getHorizontalTicks(png_bytep row, int width, bool transparent, return true; } -static bool getVerticalTicks(png_bytepp rows, int offset, int height, - bool transparent, bool required, int32_t* outTop, - int32_t* outBottom, const char** outError, - uint8_t* outDivs, bool multipleAllowed) { +static bool getVerticalTicks(png_bytepp rows, int offset, int height, bool transparent, + bool required, int32_t* outTop, int32_t* outBottom, + const char** outError, uint8_t* outDivs, bool multipleAllowed) { *outTop = *outBottom = -1; TickState state = TickState::kStart; bool found = false; for (int i = 1; i < height - 1; i++) { if (tickType(rows[i] + offset, transparent, outError) == TickType::kTick) { - if (state == TickState::kStart || - (state == TickState::kOutside1 && multipleAllowed)) { + if (state == TickState::kStart || (state == TickState::kOutside1 && multipleAllowed)) { *outTop = i - 1; *outBottom = height - 2; found = true; @@ -765,10 +739,8 @@ static bool getVerticalTicks(png_bytepp rows, int offset, int height, return true; } -static bool getHorizontalLayoutBoundsTicks(png_bytep row, int width, - bool transparent, - bool /* required */, - int32_t* outLeft, int32_t* outRight, +static bool getHorizontalLayoutBoundsTicks(png_bytep row, int width, bool transparent, + bool /* required */, int32_t* outLeft, int32_t* outRight, const char** outError) { *outLeft = *outRight = 0; @@ -779,23 +751,20 @@ static bool getHorizontalLayoutBoundsTicks(png_bytep row, int width, while (i < width - 1) { (*outLeft)++; i++; - if (tickType(row + i * 4, transparent, outError) != - TickType::kLayoutBounds) { + if (tickType(row + i * 4, transparent, outError) != TickType::kLayoutBounds) { break; } } } // Look for right tick - if (tickType(row + (width - 2) * 4, transparent, outError) == - TickType::kLayoutBounds) { + if (tickType(row + (width - 2) * 4, transparent, outError) == TickType::kLayoutBounds) { // Ending with a layout padding tick int i = width - 2; while (i > 1) { (*outRight)++; i--; - if (tickType(row + i * 4, transparent, outError) != - TickType::kLayoutBounds) { + if (tickType(row + i * 4, transparent, outError) != TickType::kLayoutBounds) { break; } } @@ -803,38 +772,32 @@ static bool getHorizontalLayoutBoundsTicks(png_bytep row, int width, return true; } -static bool getVerticalLayoutBoundsTicks(png_bytepp rows, int offset, - int height, bool transparent, - bool /* required */, int32_t* outTop, - int32_t* outBottom, +static bool getVerticalLayoutBoundsTicks(png_bytepp rows, int offset, int height, bool transparent, + bool /* required */, int32_t* outTop, int32_t* outBottom, const char** outError) { *outTop = *outBottom = 0; // Look for top tick - if (tickType(rows[1] + offset, transparent, outError) == - TickType::kLayoutBounds) { + if (tickType(rows[1] + offset, transparent, outError) == TickType::kLayoutBounds) { // Starting with a layout padding tick int i = 1; while (i < height - 1) { (*outTop)++; i++; - if (tickType(rows[i] + offset, transparent, outError) != - TickType::kLayoutBounds) { + if (tickType(rows[i] + offset, transparent, outError) != TickType::kLayoutBounds) { break; } } } // Look for bottom tick - if (tickType(rows[height - 2] + offset, transparent, outError) == - TickType::kLayoutBounds) { + if (tickType(rows[height - 2] + offset, transparent, outError) == TickType::kLayoutBounds) { // Ending with a layout padding tick int i = height - 2; while (i > 1) { (*outBottom)++; i--; - if (tickType(rows[i] + offset, transparent, outError) != - TickType::kLayoutBounds) { + if (tickType(rows[i] + offset, transparent, outError) != TickType::kLayoutBounds) { break; } } @@ -842,13 +805,12 @@ static bool getVerticalLayoutBoundsTicks(png_bytepp rows, int offset, return true; } -static void findMaxOpacity(png_bytepp rows, int startX, int startY, int endX, - int endY, int dX, int dY, int* outInset) { +static void findMaxOpacity(png_bytepp rows, int startX, int startY, int endX, int endY, int dX, + int dY, int* outInset) { uint8_t maxOpacity = 0; int inset = 0; *outInset = 0; - for (int x = startX, y = startY; x != endX && y != endY; - x += dX, y += dY, inset++) { + for (int x = startX, y = startY; x != endX && y != endY; x += dX, y += dY, inset++) { png_byte* color = rows[y] + x * 4; uint8_t opacity = color[3]; if (opacity > maxOpacity) { @@ -868,8 +830,7 @@ static uint8_t maxAlphaOverRow(png_bytep row, int startX, int endX) { return maxAlpha; } -static uint8_t maxAlphaOverCol(png_bytepp rows, int offsetX, int startY, - int endY) { +static uint8_t maxAlphaOverCol(png_bytepp rows, int offsetX, int startY, int endY) { uint8_t maxAlpha = 0; for (int y = startY; y < endY; y++) { uint8_t alpha = (rows[y] + offsetX * 4)[3]; @@ -886,10 +847,8 @@ static void getOutline(PngInfo* image) { // find left and right extent of nine patch content on center row if (image->width > 4) { - findMaxOpacity(image->rows.data(), 1, midY, midX, -1, 1, 0, - &image->outlineInsetsLeft); - findMaxOpacity(image->rows.data(), endX, midY, midX, -1, -1, 0, - &image->outlineInsetsRight); + findMaxOpacity(image->rows.data(), 1, midY, midX, -1, 1, 0, &image->outlineInsetsLeft); + findMaxOpacity(image->rows.data(), endX, midY, midX, -1, -1, 0, &image->outlineInsetsRight); } else { image->outlineInsetsLeft = 0; image->outlineInsetsRight = 0; @@ -897,10 +856,8 @@ static void getOutline(PngInfo* image) { // find top and bottom extent of nine patch content on center column if (image->height > 4) { - findMaxOpacity(image->rows.data(), midX, 1, -1, midY, 0, 1, - &image->outlineInsetsTop); - findMaxOpacity(image->rows.data(), midX, endY, -1, midY, 0, -1, - &image->outlineInsetsBottom); + findMaxOpacity(image->rows.data(), midX, 1, -1, midY, 0, 1, &image->outlineInsetsTop); + findMaxOpacity(image->rows.data(), midX, endY, -1, midY, 0, -1, &image->outlineInsetsBottom); } else { image->outlineInsetsTop = 0; image->outlineInsetsBottom = 0; @@ -915,13 +872,13 @@ static void getOutline(PngInfo* image) { // assuming the image is a round rect, compute the radius by marching // diagonally from the top left corner towards the center - image->outlineAlpha = std::max( - maxAlphaOverRow(image->rows[innerMidY], innerStartX, innerEndX), - maxAlphaOverCol(image->rows.data(), innerMidX, innerStartY, innerStartY)); + image->outlineAlpha = + std::max(maxAlphaOverRow(image->rows[innerMidY], innerStartX, innerEndX), + maxAlphaOverCol(image->rows.data(), innerMidX, innerStartY, innerStartY)); int diagonalInset = 0; - findMaxOpacity(image->rows.data(), innerStartX, innerStartY, innerMidX, - innerMidY, 1, 1, &diagonalInset); + findMaxOpacity(image->rows.data(), innerStartX, innerStartY, innerMidX, innerMidY, 1, 1, + &diagonalInset); /* Determine source radius based upon inset: * sqrt(r^2 + r^2) = sqrt(i^2 + i^2) + r @@ -932,19 +889,17 @@ static void getOutline(PngInfo* image) { image->outlineRadius = 3.4142f * diagonalInset; if (kDebug) { - printf("outline insets %d %d %d %d, rad %f, alpha %x\n", - image->outlineInsetsLeft, image->outlineInsetsTop, - image->outlineInsetsRight, image->outlineInsetsBottom, + printf("outline insets %d %d %d %d, rad %f, alpha %x\n", image->outlineInsetsLeft, + image->outlineInsetsTop, image->outlineInsetsRight, image->outlineInsetsBottom, image->outlineRadius, image->outlineAlpha); } } -static uint32_t getColor(png_bytepp rows, int left, int top, int right, - int bottom) { +static uint32_t getColor(png_bytepp rows, int left, int top, int right, int bottom) { png_bytep color = rows[top] + left * 4; if (left > right || top > bottom) { - return android::Res_png_9patch::TRANSPARENT_COLOR; + return Res_png_9patch::TRANSPARENT_COLOR; } while (top <= bottom) { @@ -952,18 +907,17 @@ static uint32_t getColor(png_bytepp rows, int left, int top, int right, png_bytep p = rows[top] + i * 4; if (color[3] == 0) { if (p[3] != 0) { - return android::Res_png_9patch::NO_COLOR; + return Res_png_9patch::NO_COLOR; } - } else if (p[0] != color[0] || p[1] != color[1] || p[2] != color[2] || - p[3] != color[3]) { - return android::Res_png_9patch::NO_COLOR; + } else if (p[0] != color[0] || p[1] != color[1] || p[2] != color[2] || p[3] != color[3]) { + return Res_png_9patch::NO_COLOR; } } top++; } if (color[3] == 0) { - return android::Res_png_9patch::TRANSPARENT_COLOR; + return Res_png_9patch::TRANSPARENT_COLOR; } return (color[3] << 24) | (color[0] << 16) | (color[1] << 8) | color[2]; } @@ -1014,23 +968,22 @@ static bool do9Patch(PngInfo* image, std::string* outError) { } // Validate frame... - if (!transparent && - (p[0] != 0xFF || p[1] != 0xFF || p[2] != 0xFF || p[3] != 0xFF)) { + if (!transparent && (p[0] != 0xFF || p[1] != 0xFF || p[2] != 0xFF || p[3] != 0xFF)) { errorMsg = "Must have one-pixel frame that is either transparent or white"; goto getout; } // Find left and right of sizing areas... - if (!getHorizontalTicks(p, W, transparent, true, &xDivs[0], &xDivs[1], - &errorMsg, &numXDivs, true)) { + if (!getHorizontalTicks(p, W, transparent, true, &xDivs[0], &xDivs[1], &errorMsg, &numXDivs, + true)) { errorPixel = xDivs[0]; errorEdge = "top"; goto getout; } // Find top and bottom of sizing areas... - if (!getVerticalTicks(image->rows.data(), 0, H, transparent, true, &yDivs[0], - &yDivs[1], &errorMsg, &numYDivs, true)) { + if (!getVerticalTicks(image->rows.data(), 0, H, transparent, true, &yDivs[0], &yDivs[1], + &errorMsg, &numYDivs, true)) { errorPixel = yDivs[0]; errorEdge = "left"; goto getout; @@ -1041,10 +994,8 @@ static bool do9Patch(PngInfo* image, std::string* outError) { image->info9Patch.numYDivs = numYDivs; // Find left and right of padding area... - if (!getHorizontalTicks(image->rows[H - 1], W, transparent, false, - &image->info9Patch.paddingLeft, - &image->info9Patch.paddingRight, &errorMsg, nullptr, - false)) { + if (!getHorizontalTicks(image->rows[H - 1], W, transparent, false, &image->info9Patch.paddingLeft, + &image->info9Patch.paddingRight, &errorMsg, nullptr, false)) { errorPixel = image->info9Patch.paddingLeft; errorEdge = "bottom"; goto getout; @@ -1052,9 +1003,8 @@ static bool do9Patch(PngInfo* image, std::string* outError) { // Find top and bottom of padding area... if (!getVerticalTicks(image->rows.data(), (W - 1) * 4, H, transparent, false, - &image->info9Patch.paddingTop, - &image->info9Patch.paddingBottom, &errorMsg, nullptr, - false)) { + &image->info9Patch.paddingTop, &image->info9Patch.paddingBottom, &errorMsg, + nullptr, false)) { errorPixel = image->info9Patch.paddingTop; errorEdge = "right"; goto getout; @@ -1062,22 +1012,18 @@ static bool do9Patch(PngInfo* image, std::string* outError) { // Find left and right of layout padding... getHorizontalLayoutBoundsTicks(image->rows[H - 1], W, transparent, false, - &image->layoutBoundsLeft, - &image->layoutBoundsRight, &errorMsg); + &image->layoutBoundsLeft, &image->layoutBoundsRight, &errorMsg); - getVerticalLayoutBoundsTicks(image->rows.data(), (W - 1) * 4, H, transparent, - false, &image->layoutBoundsTop, - &image->layoutBoundsBottom, &errorMsg); + getVerticalLayoutBoundsTicks(image->rows.data(), (W - 1) * 4, H, transparent, false, + &image->layoutBoundsTop, &image->layoutBoundsBottom, &errorMsg); - image->haveLayoutBounds = - image->layoutBoundsLeft != 0 || image->layoutBoundsRight != 0 || - image->layoutBoundsTop != 0 || image->layoutBoundsBottom != 0; + image->haveLayoutBounds = image->layoutBoundsLeft != 0 || image->layoutBoundsRight != 0 || + image->layoutBoundsTop != 0 || image->layoutBoundsBottom != 0; if (image->haveLayoutBounds) { if (kDebug) { - printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, - image->layoutBoundsTop, image->layoutBoundsRight, - image->layoutBoundsBottom); + printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop, + image->layoutBoundsRight, image->layoutBoundsBottom); } } @@ -1189,7 +1135,7 @@ static bool do9Patch(PngInfo* image, std::string* outError) { c = getColor(image->rows.data(), left, top, right - 1, bottom - 1); image->colors[colorIndex++] = c; if (kDebug) { - if (c != android::Res_png_9patch::NO_COLOR) { + if (c != Res_png_9patch::NO_COLOR) { hasColor = true; } } @@ -1214,8 +1160,7 @@ getout: if (errorEdge) { err << "." << std::endl; if (errorPixel >= 0) { - err << "Found at pixel #" << errorPixel << " along " << errorEdge - << " edge"; + err << "Found at pixel #" << errorPixel << " along " << errorEdge << " edge"; } else { err << "Found along " << errorEdge << " edge"; } @@ -1226,20 +1171,19 @@ getout: return true; } -bool Png::process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer, +bool Png::process(const Source& source, std::istream* input, BigBuffer* outBuffer, const PngOptions& options) { - TRACE_CALL(); png_byte signature[kPngSignatureSize]; // Read the PNG signature first. if (!input->read(reinterpret_cast<char*>(signature), kPngSignatureSize)) { - mDiag->Error(android::DiagMessage() << strerror(errno)); + mDiag->Error(DiagMessage() << strerror(errno)); return false; } // If the PNG signature doesn't match, bail early. if (png_sig_cmp(signature, 0, kPngSignatureSize) != 0) { - mDiag->Error(android::DiagMessage() << "not a valid png file"); + mDiag->Error(DiagMessage() << "not a valid png file"); return false; } @@ -1252,18 +1196,17 @@ bool Png::process(const android::Source& source, std::istream* input, android::B readPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr); if (!readPtr) { - mDiag->Error(android::DiagMessage() << "failed to allocate read ptr"); + mDiag->Error(DiagMessage() << "failed to allocate read ptr"); goto bail; } infoPtr = png_create_info_struct(readPtr); if (!infoPtr) { - mDiag->Error(android::DiagMessage() << "failed to allocate info ptr"); + mDiag->Error(DiagMessage() << "failed to allocate info ptr"); goto bail; } - png_set_error_fn(readPtr, reinterpret_cast<png_voidp>(mDiag), nullptr, - logWarning); + png_set_error_fn(readPtr, reinterpret_cast<png_voidp>(mDiag), nullptr, logWarning); // Set the read function to read from std::istream. png_set_read_fn(readPtr, (png_voidp)input, readDataFromStream); @@ -1272,35 +1215,32 @@ bool Png::process(const android::Source& source, std::istream* input, android::B goto bail; } - if (util::EndsWith(source.path, ".9.png")) { + if (android::base::EndsWith(source.path, ".9.png")) { std::string errorMsg; if (!do9Patch(&pngInfo, &errorMsg)) { - mDiag->Error(android::DiagMessage() << errorMsg); + mDiag->Error(DiagMessage() << errorMsg); goto bail; } } - writePtr = - png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr); + writePtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr); if (!writePtr) { - mDiag->Error(android::DiagMessage() << "failed to allocate write ptr"); + mDiag->Error(DiagMessage() << "failed to allocate write ptr"); goto bail; } writeInfoPtr = png_create_info_struct(writePtr); if (!writeInfoPtr) { - mDiag->Error(android::DiagMessage() << "failed to allocate write info ptr"); + mDiag->Error(DiagMessage() << "failed to allocate write info ptr"); goto bail; } png_set_error_fn(writePtr, nullptr, nullptr, logWarning); // Set the write function to write to std::ostream. - png_set_write_fn(writePtr, (png_voidp)outBuffer, writeDataToStream, - flushDataToStream); + png_set_write_fn(writePtr, (png_voidp)outBuffer, writeDataToStream, flushDataToStream); - if (!writePng(mDiag, writePtr, writeInfoPtr, &pngInfo, - options.grayscale_tolerance)) { + if (!writePng(mDiag, writePtr, writeInfoPtr, &pngInfo, options.grayscale_tolerance)) { goto bail; } @@ -1316,4 +1256,4 @@ bail: return result; } -} // namespace aapt +} // namespace android diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/libs/androidfw/PngChunkFilter.cpp index 2e55d0c82b7b..331b94803e93 100644 --- a/tools/aapt2/compile/PngChunkFilter.cpp +++ b/libs/androidfw/PngChunkFilter.cpp @@ -14,25 +14,22 @@ * limitations under the License. */ -#include "compile/Png.h" - #include "android-base/stringprintf.h" +#include "android-base/strings.h" +#include "androidfw/Png.h" +#include "androidfw/Streams.h" #include "androidfw/StringPiece.h" -#include "io/Io.h" - -using ::android::StringPiece; using ::android::base::StringPrintf; -namespace aapt { +namespace android { static constexpr const char* kPngSignature = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"; // Useful helper function that encodes individual bytes into a uint32 // at compile time. constexpr uint32_t u32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { - return (((uint32_t)a) << 24) | (((uint32_t)b) << 16) | (((uint32_t)c) << 8) | - ((uint32_t)d); + return (((uint32_t)a) << 24) | (((uint32_t)b) << 16) | (((uint32_t)c) << 8) | ((uint32_t)d); } // Allow list of PNG chunk types that we want to keep in the resulting PNG. @@ -71,7 +68,7 @@ static bool IsPngChunkAllowed(uint32_t type) { } PngChunkFilter::PngChunkFilter(StringPiece data) : data_(data) { - if (util::StartsWith(data_, kPngSignature)) { + if (android::base::StartsWith(data_, kPngSignature)) { window_start_ = 0; window_end_ = kPngSignatureSize; } else { @@ -176,5 +173,4 @@ bool PngChunkFilter::Rewind() { window_end_ = kPngSignatureSize; return true; } - -} // namespace aapt +} // namespace android diff --git a/tools/aapt2/compile/PngCrunch.cpp b/libs/androidfw/PngCrunch.cpp index 4ef87ba3671b..cf3c0eeff402 100644 --- a/tools/aapt2/compile/PngCrunch.cpp +++ b/libs/androidfw/PngCrunch.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#include "compile/Png.h" - #include <png.h> #include <zlib.h> @@ -26,16 +24,16 @@ #include "android-base/errors.h" #include "android-base/logging.h" #include "android-base/macros.h" +#include "androidfw/Png.h" -#include "trace/TraceBuffer.h" - -namespace aapt { +namespace android { // Custom deleter that destroys libpng read and info structs. class PngReadStructDeleter { public: PngReadStructDeleter(png_structp read_ptr, png_infop info_ptr) - : read_ptr_(read_ptr), info_ptr_(info_ptr) {} + : read_ptr_(read_ptr), info_ptr_(info_ptr) { + } ~PngReadStructDeleter() { png_destroy_read_struct(&read_ptr_, &info_ptr_, nullptr); @@ -52,7 +50,8 @@ class PngReadStructDeleter { class PngWriteStructDeleter { public: PngWriteStructDeleter(png_structp write_ptr, png_infop info_ptr) - : write_ptr_(write_ptr), info_ptr_(info_ptr) {} + : write_ptr_(write_ptr), info_ptr_(info_ptr) { + } ~PngWriteStructDeleter() { png_destroy_write_struct(&write_ptr_, &info_ptr_); @@ -83,7 +82,7 @@ static void LogError(png_structp png_ptr, png_const_charp error_msg) { } static void ReadDataFromStream(png_structp png_ptr, png_bytep buffer, png_size_t len) { - io::InputStream* in = (io::InputStream*)png_get_io_ptr(png_ptr); + InputStream* in = (InputStream*)png_get_io_ptr(png_ptr); const void* in_buffer; size_t in_len; @@ -108,7 +107,7 @@ static void ReadDataFromStream(png_structp png_ptr, png_bytep buffer, png_size_t } static void WriteDataToStream(png_structp png_ptr, png_bytep buffer, png_size_t len) { - io::OutputStream* out = (io::OutputStream*)png_get_io_ptr(png_ptr); + OutputStream* out = (OutputStream*)png_get_io_ptr(png_ptr); void* out_buffer; size_t out_len; @@ -143,28 +142,22 @@ static void WriteDataToStream(png_structp png_ptr, png_bytep buffer, png_size_t } } -std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source, - io::InputStream* in) { - TRACE_CALL(); - // Create a diagnostics that has the source information encoded. - android::SourcePathDiagnostics source_diag(source, context->GetDiagnostics()); - +std::unique_ptr<Image> ReadPng(InputStream* in, IDiagnostics* diag) { // Read the first 8 bytes of the file looking for the PNG signature. // Bail early if it does not match. const png_byte* signature; size_t buffer_size; if (!in->Next((const void**)&signature, &buffer_size)) { if (in->HadError()) { - source_diag.Error(android::DiagMessage() - << "failed to read PNG signature: " << in->GetError()); + diag->Error(android::DiagMessage() << "failed to read PNG signature: " << in->GetError()); } else { - source_diag.Error(android::DiagMessage() << "not enough data for PNG signature"); + diag->Error(android::DiagMessage() << "not enough data for PNG signature"); } return {}; } if (buffer_size < kPngSignatureSize || png_sig_cmp(signature, 0, kPngSignatureSize) != 0) { - source_diag.Error(android::DiagMessage() << "file signature does not match PNG signature"); + diag->Error(android::DiagMessage() << "file signature does not match PNG signature"); return {}; } @@ -176,14 +169,14 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& sou // version of libpng. png_structp read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (read_ptr == nullptr) { - source_diag.Error(android::DiagMessage() << "failed to create libpng read png_struct"); + diag->Error(android::DiagMessage() << "failed to create libpng read png_struct"); return {}; } // Create and initialize the memory for image header and data. png_infop info_ptr = png_create_info_struct(read_ptr); if (info_ptr == nullptr) { - source_diag.Error(android::DiagMessage() << "failed to create libpng read png_info"); + diag->Error(android::DiagMessage() << "failed to create libpng read png_info"); png_destroy_read_struct(&read_ptr, nullptr, nullptr); return {}; } @@ -199,7 +192,7 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& sou } // Handle warnings ourselves via IDiagnostics. - png_set_error_fn(read_ptr, (png_voidp)&source_diag, LogError, LogWarning); + png_set_error_fn(read_ptr, (png_voidp)&diag, LogError, LogWarning); // Set up the read functions which read from our custom data sources. png_set_read_fn(read_ptr, (png_voidp)in, ReadDataFromStream); @@ -213,8 +206,8 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& sou // Extract image meta-data from the various chunk headers. uint32_t width, height; int bit_depth, color_type, interlace_method, compression_method, filter_method; - png_get_IHDR(read_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_method, &compression_method, &filter_method); + png_get_IHDR(read_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, + &compression_method, &filter_method); // When the image is read, expand it so that it is in RGBA 8888 format // so that image handling is uniform. @@ -239,8 +232,7 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& sou png_set_add_alpha(read_ptr, 0xFF, PNG_FILLER_AFTER); } - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(read_ptr); } @@ -256,12 +248,12 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& sou // something // that can always be represented by 9-patch. if (width > std::numeric_limits<int32_t>::max() || height > std::numeric_limits<int32_t>::max()) { - source_diag.Error(android::DiagMessage() - << "PNG image dimensions are too large: " << width << "x" << height); + diag->Error(android::DiagMessage() + << "PNG image dimensions are too large: " << width << "x" << height); return {}; } - std::unique_ptr<Image> output_image = util::make_unique<Image>(); + std::unique_ptr<Image> output_image = std::make_unique<Image>(); output_image->width = static_cast<int32_t>(width); output_image->height = static_cast<int32_t>(height); @@ -272,7 +264,7 @@ std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& sou output_image->data = std::unique_ptr<uint8_t[]>(new uint8_t[height * row_bytes]); // Create an array of rows that index into the data block. - output_image->rows = std::unique_ptr<uint8_t* []>(new uint8_t*[height]); + output_image->rows = std::unique_ptr<uint8_t*[]>(new uint8_t*[height]); for (uint32_t h = 0; h < height; h++) { output_image->rows[h] = output_image->data.get() + (h * row_bytes); } @@ -332,8 +324,7 @@ static int PickColorType(int32_t width, int32_t height, bool grayscale, // This grayscale has alpha and can fit within a palette. // See if it is worth fitting into a palette. const size_t palette_threshold = palette_chunk_size + alpha_chunk_size + - palette_data_chunk_size + - kPaletteOverheadConstant; + palette_data_chunk_size + kPaletteOverheadConstant; if (grayscale_alpha_data_chunk_size > palette_threshold) { return PNG_COLOR_TYPE_PALETTE; } @@ -343,16 +334,14 @@ static int PickColorType(int32_t width, int32_t height, bool grayscale, if (color_palette_size <= 256 && !has_nine_patch) { // This image can fit inside a palette. Let's see if it is worth it. - size_t total_size_with_palette = - palette_data_chunk_size + palette_chunk_size; + size_t total_size_with_palette = palette_data_chunk_size + palette_chunk_size; size_t total_size_without_palette = color_data_chunk_size; if (alpha_palette_size > 0) { total_size_with_palette += alpha_palette_size; total_size_without_palette = color_alpha_data_chunk_size; } - if (total_size_without_palette > - total_size_with_palette + kPaletteOverheadConstant) { + if (total_size_without_palette > total_size_with_palette + kPaletteOverheadConstant) { return PNG_COLOR_TYPE_PALETTE; } } @@ -482,26 +471,22 @@ static void WriteNinePatch(png_structp write_ptr, png_infop write_info_ptr, png_set_unknown_chunks(write_ptr, write_info_ptr, unknown_chunks, index); } -bool WritePng(IAaptContext* context, const Image* image, - const NinePatch* nine_patch, io::OutputStream* out, - const PngOptions& options) { - TRACE_CALL(); +bool WritePng(const Image* image, const NinePatch* nine_patch, OutputStream* out, + const PngOptions& options, IDiagnostics* diag, bool verbose) { // Create and initialize the write png_struct with the default error and // warning handlers. // The header version is also passed in to ensure that this was built against the same // version of libpng. png_structp write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (write_ptr == nullptr) { - context->GetDiagnostics()->Error(android::DiagMessage() - << "failed to create libpng write png_struct"); + diag->Error(android::DiagMessage() << "failed to create libpng write png_struct"); return false; } // Allocate memory to store image header data. png_infop write_info_ptr = png_create_info_struct(write_ptr); if (write_info_ptr == nullptr) { - context->GetDiagnostics()->Error(android::DiagMessage() - << "failed to create libpng write png_info"); + diag->Error(android::DiagMessage() << "failed to create libpng write png_info"); png_destroy_write_struct(&write_ptr, nullptr); return false; } @@ -516,7 +501,7 @@ bool WritePng(IAaptContext* context, const Image* image, } // Handle warnings with our IDiagnostics. - png_set_error_fn(write_ptr, (png_voidp)context->GetDiagnostics(), LogError, LogWarning); + png_set_error_fn(write_ptr, (png_voidp)&diag, LogError, LogWarning); // Set up the write functions which write to our custom data sources. png_set_write_fn(write_ptr, (png_voidp)out, WriteDataToStream, nullptr); @@ -578,22 +563,21 @@ bool WritePng(IAaptContext* context, const Image* image, } } - if (context->IsVerbose()) { + if (verbose) { android::DiagMessage msg; - msg << " paletteSize=" << color_palette.size() - << " alphaPaletteSize=" << alpha_palette.size() + msg << " paletteSize=" << color_palette.size() << " alphaPaletteSize=" << alpha_palette.size() << " maxGrayDeviation=" << max_gray_deviation << " grayScale=" << (grayscale ? "true" : "false"); - context->GetDiagnostics()->Note(msg); + diag->Note(msg); } const bool convertible_to_grayscale = max_gray_deviation <= options.grayscale_tolerance; - const int new_color_type = PickColorType( - image->width, image->height, grayscale, convertible_to_grayscale, - nine_patch != nullptr, color_palette.size(), alpha_palette.size()); + const int new_color_type = + PickColorType(image->width, image->height, grayscale, convertible_to_grayscale, + nine_patch != nullptr, color_palette.size(), alpha_palette.size()); - if (context->IsVerbose()) { + if (verbose) { android::DiagMessage msg; msg << "encoding PNG "; if (nine_patch) { @@ -619,12 +603,11 @@ bool WritePng(IAaptContext* context, const Image* image, msg << "unknown type " << new_color_type; break; } - context->GetDiagnostics()->Note(msg); + diag->Note(msg); } - png_set_IHDR(write_ptr, write_info_ptr, image->width, image->height, 8, - new_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); + png_set_IHDR(write_ptr, write_info_ptr, image->width, image->height, 8, new_color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (new_color_type & PNG_COLOR_MASK_PALETTE) { // Assigns indices to the palette, and writes the encoded palette to the @@ -666,11 +649,9 @@ bool WritePng(IAaptContext* context, const Image* image, } png_write_row(write_ptr, out_row.get()); } - } else if (new_color_type == PNG_COLOR_TYPE_GRAY || - new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + } else if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { const size_t bpp = new_color_type == PNG_COLOR_TYPE_GRAY ? 1 : 2; - auto out_row = - std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]); + auto out_row = std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]); for (int32_t y = 0; y < image->height; y++) { png_const_bytep in_row = image->rows[y]; @@ -691,8 +672,7 @@ bool WritePng(IAaptContext* context, const Image* image, // The image is convertible to grayscale, use linear-luminance of // sRGB colorspace: // https://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale - out_row[x * bpp] = - (png_byte)(rr * 0.2126f + gg * 0.7152f + bb * 0.0722f); + out_row[x * bpp] = (png_byte)(rr * 0.2126f + gg * 0.7152f + bb * 0.0722f); } if (bpp == 2) { @@ -747,4 +727,4 @@ bool WritePng(IAaptContext* context, const Image* image, return true; } -} // namespace aapt +} // namespace android diff --git a/tools/aapt2/io/BigBufferStream.h b/libs/androidfw/include/androidfw/BigBufferStream.h index 63a5e5756ed4..e55fe0d653cc 100644 --- a/tools/aapt2/io/BigBufferStream.h +++ b/libs/androidfw/include/androidfw/BigBufferStream.h @@ -14,18 +14,16 @@ * limitations under the License. */ -#ifndef AAPT_IO_BIGBUFFERSTREAM_H -#define AAPT_IO_BIGBUFFERSTREAM_H +#pragma once -#include "androidfw/BigBuffer.h" -#include "io/Io.h" +#include "BigBuffer.h" +#include "Streams.h" -namespace aapt { -namespace io { +namespace android { class BigBufferInputStream : public KnownSizeInputStream { public: - inline explicit BigBufferInputStream(const android::BigBuffer* buffer) + inline explicit BigBufferInputStream(const BigBuffer* buffer) : buffer_(buffer), iter_(buffer->begin()) { } virtual ~BigBufferInputStream() = default; @@ -44,18 +42,20 @@ class BigBufferInputStream : public KnownSizeInputStream { size_t TotalSize() const override; + bool ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) override; + private: DISALLOW_COPY_AND_ASSIGN(BigBufferInputStream); - const android::BigBuffer* buffer_; - android::BigBuffer::const_iterator iter_; + const BigBuffer* buffer_; + BigBuffer::const_iterator iter_; size_t offset_ = 0; size_t bytes_read_ = 0; }; class BigBufferOutputStream : public OutputStream { public: - inline explicit BigBufferOutputStream(android::BigBuffer* buffer) : buffer_(buffer) { + inline explicit BigBufferOutputStream(BigBuffer* buffer) : buffer_(buffer) { } virtual ~BigBufferOutputStream() = default; @@ -70,10 +70,7 @@ class BigBufferOutputStream : public OutputStream { private: DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream); - android::BigBuffer* buffer_; + BigBuffer* buffer_; }; -} // namespace io -} // namespace aapt - -#endif // AAPT_IO_BIGBUFFERSTREAM_H +} // namespace android
\ No newline at end of file diff --git a/tools/aapt2/io/FileStream.h b/libs/androidfw/include/androidfw/FileStream.h index 62d910f0b06a..fb84a91a00de 100644 --- a/tools/aapt2/io/FileStream.h +++ b/libs/androidfw/include/androidfw/FileStream.h @@ -14,19 +14,16 @@ * limitations under the License. */ -#ifndef AAPT_IO_FILESTREAM_H -#define AAPT_IO_FILESTREAM_H - -#include "io/Io.h" +#pragma once #include <memory> #include <string> +#include "Streams.h" #include "android-base/macros.h" #include "android-base/unique_fd.h" -namespace aapt { -namespace io { +namespace android { constexpr size_t kDefaultBufferCapacity = 4096u; @@ -48,6 +45,8 @@ class FileInputStream : public InputStream { std::string GetError() const override; + bool ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) override; + private: DISALLOW_COPY_AND_ASSIGN(FileInputStream); @@ -101,7 +100,4 @@ class FileOutputStream : public OutputStream { size_t total_byte_count_ = 0u; }; -} // namespace io -} // namespace aapt - -#endif // AAPT_IO_FILESTREAM_H +} // namespace android
\ No newline at end of file diff --git a/tools/aapt2/compile/Image.h b/libs/androidfw/include/androidfw/Image.h index db0b945e1f18..c18c34c25bf9 100644 --- a/tools/aapt2/compile/Image.h +++ b/libs/androidfw/include/androidfw/Image.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef AAPT_COMPILE_IMAGE_H -#define AAPT_COMPILE_IMAGE_H +#pragma once #include <cstdint> #include <memory> @@ -24,7 +23,7 @@ #include "android-base/macros.h" -namespace aapt { +namespace android { /** * An in-memory image, loaded from disk, with pixels in RGBA_8888 format. @@ -37,7 +36,7 @@ class Image { * A `height` sized array of pointers, where each element points to a * `width` sized row of RGBA_8888 pixels. */ - std::unique_ptr<uint8_t* []> rows; + std::unique_ptr<uint8_t*[]> rows; /** * The width of the image in RGBA_8888 pixels. This is int32_t because of @@ -72,7 +71,8 @@ struct Range { int32_t end = 0; explicit Range() = default; - inline explicit Range(int32_t s, int32_t e) : start(s), end(e) {} + inline explicit Range(int32_t s, int32_t e) : start(s), end(e) { + } }; inline bool operator==(const Range& left, const Range& right) { @@ -93,7 +93,8 @@ struct Bounds { explicit Bounds() = default; inline explicit Bounds(int32_t l, int32_t t, int32_t r, int32_t b) - : left(l), top(t), right(r), bottom(b) {} + : left(l), top(t), right(r), bottom(b) { + } bool nonZero() const; }; @@ -103,8 +104,8 @@ inline bool Bounds::nonZero() const { } inline bool operator==(const Bounds& left, const Bounds& right) { - return left.left == right.left && left.top == right.top && - left.right == right.right && left.bottom == right.bottom; + return left.left == right.left && left.top == right.top && left.right == right.right && + left.bottom == right.bottom; } /** @@ -115,8 +116,7 @@ inline bool operator==(const Bounds& left, const Bounds& right) { class NinePatch { public: static std::unique_ptr<NinePatch> Create(uint8_t** rows, const int32_t width, - const int32_t height, - std::string* err_out); + const int32_t height, std::string* err_out); /** * Packs the RGBA_8888 data pointed to by pixel into a uint32_t @@ -204,6 +204,4 @@ class NinePatch { ::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds); ::std::ostream& operator<<(::std::ostream& out, const NinePatch& nine_patch); -} // namespace aapt - -#endif /* AAPT_COMPILE_IMAGE_H */ +} // namespace android
\ No newline at end of file diff --git a/tools/aapt2/compile/Png.h b/libs/androidfw/include/androidfw/Png.h index a8b7dd18f12f..2ece43e08110 100644 --- a/tools/aapt2/compile/Png.h +++ b/libs/androidfw/include/androidfw/Png.h @@ -14,22 +14,18 @@ * limitations under the License. */ -#ifndef AAPT_PNG_H -#define AAPT_PNG_H +#pragma once -#include <iostream> #include <string> +#include "BigBuffer.h" +#include "IDiagnostics.h" +#include "Image.h" +#include "Source.h" +#include "Streams.h" #include "android-base/macros.h" -#include "androidfw/BigBuffer.h" -#include "androidfw/IDiagnostics.h" -#include "androidfw/Source.h" -#include "compile/Image.h" -#include "io/Io.h" -#include "process/IResourceTableConsumer.h" - -namespace aapt { +namespace android { // Size in bytes of the PNG signature. constexpr size_t kPngSignatureSize = 8u; @@ -42,32 +38,36 @@ struct PngOptions { */ class Png { public: - explicit Png(android::IDiagnostics* diag) : mDiag(diag) { + explicit Png(IDiagnostics* diag) : mDiag(diag) { } - bool process(const android::Source& source, std::istream* input, android::BigBuffer* outBuffer, + bool process(const Source& source, std::istream* input, BigBuffer* outBuffer, const PngOptions& options); private: DISALLOW_COPY_AND_ASSIGN(Png); - android::IDiagnostics* mDiag; + IDiagnostics* mDiag; }; /** * An InputStream that filters out unimportant PNG chunks. */ -class PngChunkFilter : public io::InputStream { +class PngChunkFilter : public InputStream { public: - explicit PngChunkFilter(android::StringPiece data); + explicit PngChunkFilter(StringPiece data); virtual ~PngChunkFilter() = default; bool Next(const void** buffer, size_t* len) override; void BackUp(size_t count) override; - bool CanRewind() const override { return true; } + bool CanRewind() const override { + return true; + } bool Rewind() override; - size_t ByteCount() const override { return window_start_; } + size_t ByteCount() const override { + return window_start_; + } bool HadError() const override { return !error_msg_.empty(); @@ -81,26 +81,20 @@ class PngChunkFilter : public io::InputStream { bool ConsumeWindow(const void** buffer, size_t* len); - android::StringPiece data_; + StringPiece data_; size_t window_start_ = 0; size_t window_end_ = 0; std::string error_msg_; }; - /** * Reads a PNG from the InputStream into memory as an RGBA Image. */ -std::unique_ptr<Image> ReadPng(IAaptContext* context, const android::Source& source, - io::InputStream* in); +std::unique_ptr<Image> ReadPng(InputStream* in, IDiagnostics* diag); /** * Writes the RGBA Image, with optional 9-patch meta-data, into the OutputStream * as a PNG. */ -bool WritePng(IAaptContext* context, const Image* image, - const NinePatch* nine_patch, io::OutputStream* out, - const PngOptions& options); - -} // namespace aapt - -#endif // AAPT_PNG_H +bool WritePng(const Image* image, const NinePatch* nine_patch, OutputStream* out, + const PngOptions& options, IDiagnostics* diag, bool verbose); +} // namespace android
\ No newline at end of file diff --git a/tools/aapt2/io/Io.h b/libs/androidfw/include/androidfw/Streams.h index e1df23a698f5..2daf0e2fb06d 100644 --- a/tools/aapt2/io/Io.h +++ b/libs/androidfw/include/androidfw/Streams.h @@ -14,13 +14,12 @@ * limitations under the License. */ -#ifndef AAPT_IO_IO_H -#define AAPT_IO_IO_H +#pragma once #include <string> +#include "android-base/off64_t.h" -namespace aapt { -namespace io { +namespace android { // InputStream interface that mimics protobuf's ZeroCopyInputStream, // with added error handling methods to better report issues. @@ -41,21 +40,34 @@ class InputStream { virtual void BackUp(size_t count) = 0; // Returns true if this InputStream can rewind. If so, Rewind() can be called. - virtual bool CanRewind() const { return false; }; + virtual bool CanRewind() const { + return false; + }; // Rewinds the stream to the beginning so it can be read again. // Returns true if the rewind succeeded. // This does nothing if CanRewind() returns false. - virtual bool Rewind() { return false; } + virtual bool Rewind() { + return false; + } // Returns the number of bytes that have been read from the stream. virtual size_t ByteCount() const = 0; // Returns an error message if HadError() returned true. - virtual std::string GetError() const { return {}; } + virtual std::string GetError() const { + return {}; + } // Returns true if an error occurred. Errors are permanent. virtual bool HadError() const = 0; + + virtual bool ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) { + (void)data; + (void)byte_count; + (void)offset; + return false; + } }; // A sub-InputStream interface that knows the total size of its stream. @@ -87,13 +99,12 @@ class OutputStream { virtual size_t ByteCount() const = 0; // Returns an error message if HadError() returned true. - virtual std::string GetError() const { return {}; } + virtual std::string GetError() const { + return {}; + } // Returns true if an error occurred. Errors are permanent. virtual bool HadError() const = 0; }; -} // namespace io -} // namespace aapt - -#endif /* AAPT_IO_IO_H */ +} // namespace android
\ No newline at end of file diff --git a/tools/aapt2/io/FileStream_test.cpp b/libs/androidfw/tests/FileStream_test.cpp index cc9cd2808a0c..978597507a6d 100644 --- a/tools/aapt2/io/FileStream_test.cpp +++ b/libs/androidfw/tests/FileStream_test.cpp @@ -14,20 +14,21 @@ * limitations under the License. */ -#include "io/FileStream.h" +#include "androidfw/FileStream.h" +#include "androidfw/StringPiece.h" #include "android-base/file.h" #include "android-base/macros.h" -#include "test/Test.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" using ::android::StringPiece; using ::testing::Eq; using ::testing::NotNull; using ::testing::StrEq; -namespace aapt { -namespace io { +namespace android { TEST(FileInputStreamTest, NextAndBackup) { std::string input = "this is a cool string"; @@ -123,5 +124,4 @@ TEST(FileOutputStreamTest, NextAndBackup) { EXPECT_THAT(actual, StrEq(input)); } -} // namespace io -} // namespace aapt +} // namespace android diff --git a/tools/aapt2/compile/NinePatch_test.cpp b/libs/androidfw/tests/NinePatch_test.cpp index f54bb2e62842..7ee8e9ebd624 100644 --- a/tools/aapt2/compile/NinePatch_test.cpp +++ b/libs/androidfw/tests/NinePatch_test.cpp @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "compile/Image.h" +#include "androidfw/Image.h" +#include "androidfw/ResourceTypes.h" +#include "gtest/gtest.h" -#include "test/Test.h" - -namespace aapt { +namespace android { // Pixels are in RGBA_8888 packing. @@ -33,16 +33,19 @@ namespace aapt { #define TRANS "\x00\x00\x00\x00" static uint8_t* k2x2[] = { - (uint8_t*)WHITE WHITE, (uint8_t*)WHITE WHITE, + (uint8_t*)WHITE WHITE, + (uint8_t*)WHITE WHITE, }; static uint8_t* kMixedNeutralColor3x3[] = { - (uint8_t*)WHITE BLACK TRANS, (uint8_t*)TRANS RED TRANS, + (uint8_t*)WHITE BLACK TRANS, + (uint8_t*)TRANS RED TRANS, (uint8_t*)WHITE WHITE WHITE, }; static uint8_t* kTransparentNeutralColor3x3[] = { - (uint8_t*)TRANS BLACK TRANS, (uint8_t*)BLACK RED BLACK, + (uint8_t*)TRANS BLACK TRANS, + (uint8_t*)BLACK RED BLACK, (uint8_t*)TRANS BLACK TRANS, }; @@ -66,55 +69,44 @@ static uint8_t* kMultipleStretch10x7[] = { }; static uint8_t* kPadding6x5[] = { - (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE BLACK, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE BLACK, (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE BLACK BLACK WHITE WHITE, }; static uint8_t* kLayoutBoundsWrongEdge3x3[] = { - (uint8_t*)WHITE RED WHITE, (uint8_t*)RED WHITE WHITE, + (uint8_t*)WHITE RED WHITE, + (uint8_t*)RED WHITE WHITE, (uint8_t*)WHITE WHITE WHITE, }; static uint8_t* kLayoutBoundsNotEdgeAligned5x5[] = { - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE RED, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE WHITE WHITE WHITE, + (uint8_t*)WHITE WHITE WHITE WHITE RED, (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE RED WHITE WHITE, }; static uint8_t* kLayoutBounds5x5[] = { - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE RED, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE RED, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE WHITE WHITE RED, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE WHITE WHITE RED, (uint8_t*)WHITE RED WHITE RED WHITE, }; static uint8_t* kAsymmetricLayoutBounds5x5[] = { - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE RED, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE WHITE WHITE RED, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE RED WHITE WHITE WHITE, }; static uint8_t* kPaddingAndLayoutBounds5x5[] = { - (uint8_t*)WHITE WHITE WHITE WHITE WHITE, - (uint8_t*)WHITE WHITE WHITE WHITE RED, - (uint8_t*)WHITE WHITE WHITE WHITE BLACK, - (uint8_t*)WHITE WHITE WHITE WHITE RED, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE, (uint8_t*)WHITE WHITE WHITE WHITE RED, + (uint8_t*)WHITE WHITE WHITE WHITE BLACK, (uint8_t*)WHITE WHITE WHITE WHITE RED, (uint8_t*)WHITE RED BLACK RED WHITE, }; static uint8_t* kColorfulImage5x5[] = { - (uint8_t*)WHITE BLACK WHITE BLACK WHITE, - (uint8_t*)BLACK RED BLUE GREEN WHITE, - (uint8_t*)BLACK RED GREEN GREEN WHITE, - (uint8_t*)WHITE TRANS BLUE GREEN WHITE, + (uint8_t*)WHITE BLACK WHITE BLACK WHITE, (uint8_t*)BLACK RED BLUE GREEN WHITE, + (uint8_t*)BLACK RED GREEN GREEN WHITE, (uint8_t*)WHITE TRANS BLUE GREEN WHITE, (uint8_t*)WHITE WHITE WHITE WHITE WHITE, }; @@ -145,33 +137,21 @@ static uint8_t* kOutlineTranslucent10x10[] = { }; static uint8_t* kOutlineOffsetTranslucent12x10[] = { - (uint8_t*) - WHITE WHITE WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE, - (uint8_t*) - WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE, - (uint8_t*) - WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE, + (uint8_t*)WHITE WHITE WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE, + (uint8_t*)WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE, + (uint8_t*)WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE, }; static uint8_t* kOutlineRadius5x5[] = { - (uint8_t*)WHITE BLACK BLACK BLACK WHITE, - (uint8_t*)BLACK TRANS GREEN TRANS WHITE, - (uint8_t*)BLACK GREEN GREEN GREEN WHITE, - (uint8_t*)BLACK TRANS GREEN TRANS WHITE, + (uint8_t*)WHITE BLACK BLACK BLACK WHITE, (uint8_t*)BLACK TRANS GREEN TRANS WHITE, + (uint8_t*)BLACK GREEN GREEN GREEN WHITE, (uint8_t*)BLACK TRANS GREEN TRANS WHITE, (uint8_t*)WHITE WHITE WHITE WHITE WHITE, }; @@ -195,14 +175,12 @@ TEST(NinePatchTest, MixedNeutralColors) { TEST(NinePatchTest, TransparentNeutralColor) { std::string err; - EXPECT_NE(nullptr, - NinePatch::Create(kTransparentNeutralColor3x3, 3, 3, &err)); + EXPECT_NE(nullptr, NinePatch::Create(kTransparentNeutralColor3x3, 3, 3, &err)); } TEST(NinePatchTest, SingleStretchRegion) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kSingleStretch7x6, 7, 6, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kSingleStretch7x6, 7, 6, &err); ASSERT_NE(nullptr, nine_patch); ASSERT_EQ(1u, nine_patch->horizontal_stretch_regions.size()); @@ -214,8 +192,7 @@ TEST(NinePatchTest, SingleStretchRegion) { TEST(NinePatchTest, MultipleStretchRegions) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kMultipleStretch10x7, 10, 7, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kMultipleStretch10x7, 10, 7, &err); ASSERT_NE(nullptr, nine_patch); ASSERT_EQ(3u, nine_patch->horizontal_stretch_regions.size()); @@ -231,16 +208,14 @@ TEST(NinePatchTest, MultipleStretchRegions) { TEST(NinePatchTest, InferPaddingFromStretchRegions) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kMultipleStretch10x7, 10, 7, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kMultipleStretch10x7, 10, 7, &err); ASSERT_NE(nullptr, nine_patch); EXPECT_EQ(Bounds(1, 0, 1, 0), nine_patch->padding); } TEST(NinePatchTest, Padding) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kPadding6x5, 6, 5, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kPadding6x5, 6, 5, &err); ASSERT_NE(nullptr, nine_patch); EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->padding); } @@ -253,15 +228,13 @@ TEST(NinePatchTest, LayoutBoundsAreOnWrongEdge) { TEST(NinePatchTest, LayoutBoundsMustTouchEdges) { std::string err; - EXPECT_EQ(nullptr, - NinePatch::Create(kLayoutBoundsNotEdgeAligned5x5, 5, 5, &err)); + EXPECT_EQ(nullptr, NinePatch::Create(kLayoutBoundsNotEdgeAligned5x5, 5, 5, &err)); EXPECT_FALSE(err.empty()); } TEST(NinePatchTest, LayoutBounds) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kLayoutBounds5x5, 5, 5, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kLayoutBounds5x5, 5, 5, &err); ASSERT_NE(nullptr, nine_patch); EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->layout_bounds); @@ -272,8 +245,7 @@ TEST(NinePatchTest, LayoutBounds) { TEST(NinePatchTest, PaddingAndLayoutBounds) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kPaddingAndLayoutBounds5x5, 5, 5, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kPaddingAndLayoutBounds5x5, 5, 5, &err); ASSERT_NE(nullptr, nine_patch); EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->padding); EXPECT_EQ(Bounds(1, 1, 1, 1), nine_patch->layout_bounds); @@ -281,25 +253,20 @@ TEST(NinePatchTest, PaddingAndLayoutBounds) { TEST(NinePatchTest, RegionColorsAreCorrect) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kColorfulImage5x5, 5, 5, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kColorfulImage5x5, 5, 5, &err); ASSERT_NE(nullptr, nine_patch); std::vector<uint32_t> expected_colors = { - NinePatch::PackRGBA((uint8_t*)RED), - (uint32_t)android::Res_png_9patch::NO_COLOR, - NinePatch::PackRGBA((uint8_t*)GREEN), - (uint32_t)android::Res_png_9patch::TRANSPARENT_COLOR, - NinePatch::PackRGBA((uint8_t*)BLUE), - NinePatch::PackRGBA((uint8_t*)GREEN), + NinePatch::PackRGBA((uint8_t*)RED), (uint32_t)android::Res_png_9patch::NO_COLOR, + NinePatch::PackRGBA((uint8_t*)GREEN), (uint32_t)android::Res_png_9patch::TRANSPARENT_COLOR, + NinePatch::PackRGBA((uint8_t*)BLUE), NinePatch::PackRGBA((uint8_t*)GREEN), }; EXPECT_EQ(expected_colors, nine_patch->region_colors); } TEST(NinePatchTest, OutlineFromOpaqueImage) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kOutlineOpaque10x10, 10, 10, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kOutlineOpaque10x10, 10, 10, &err); ASSERT_NE(nullptr, nine_patch); EXPECT_EQ(Bounds(2, 2, 2, 2), nine_patch->outline); EXPECT_EQ(0x000000ffu, nine_patch->outline_alpha); @@ -308,8 +275,7 @@ TEST(NinePatchTest, OutlineFromOpaqueImage) { TEST(NinePatchTest, OutlineFromTranslucentImage) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kOutlineTranslucent10x10, 10, 10, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kOutlineTranslucent10x10, 10, 10, &err); ASSERT_NE(nullptr, nine_patch); EXPECT_EQ(Bounds(3, 3, 3, 3), nine_patch->outline); EXPECT_EQ(0x000000b3u, nine_patch->outline_alpha); @@ -337,8 +303,7 @@ TEST(NinePatchTest, OutlineFromOffCenterImage) { TEST(NinePatchTest, OutlineRadius) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kOutlineRadius5x5, 5, 5, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kOutlineRadius5x5, 5, 5, &err); ASSERT_NE(nullptr, nine_patch); EXPECT_EQ(Bounds(0, 0, 0, 0), nine_patch->outline); EXPECT_EQ(3.4142f, nine_patch->outline_radius); @@ -353,8 +318,7 @@ TEST(NinePatchTest, OutlineRadius) { TEST(NinePatchTest, SerializePngEndianness) { std::string err; - std::unique_ptr<NinePatch> nine_patch = - NinePatch::Create(kStretchAndPadding5x5, 5, 5, &err); + std::unique_ptr<NinePatch> nine_patch = NinePatch::Create(kStretchAndPadding5x5, 5, 5, &err); ASSERT_NE(nullptr, nine_patch); size_t len; @@ -374,4 +338,4 @@ TEST(NinePatchTest, SerializePngEndianness) { EXPECT_TRUE(BigEndianOne(cursor + 12)); } -} // namespace aapt +} // namespace android diff --git a/libs/hwui/Mesh.cpp b/libs/hwui/Mesh.cpp index e59bc9565a59..37a7d74330e9 100644 --- a/libs/hwui/Mesh.cpp +++ b/libs/hwui/Mesh.cpp @@ -90,8 +90,8 @@ std::tuple<bool, SkString> Mesh::validate() { FAIL_MESH_VALIDATE("%s mode requires at least %zu vertices but vertex count is %zu.", modeToStr(meshMode), min_vcount_for_mode(meshMode), mVertexCount); } - SkASSERT(!fICount); - SkASSERT(!fIOffset); + LOG_ALWAYS_FATAL_IF(mIndexCount != 0); + LOG_ALWAYS_FATAL_IF(mIndexOffset != 0); } if (!sm.ok()) { diff --git a/libs/hwui/jni/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp index c55066af3612..0275e4f13b3b 100644 --- a/libs/hwui/jni/YuvToJpegEncoder.cpp +++ b/libs/hwui/jni/YuvToJpegEncoder.cpp @@ -2,6 +2,7 @@ #include "SkStream.h" #include "YuvToJpegEncoder.h" #include <ui/PixelFormat.h> +#include <utils/Errors.h> #include <hardware/hardware.h> #include "graphics_jni_helpers.h" @@ -295,7 +296,7 @@ void Yuv422IToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) { } /////////////////////////////////////////////////////////////////////////////// -using namespace android::ultrahdr; +using namespace ultrahdr; ultrahdr_color_gamut P010Yuv420ToJpegREncoder::findColorGamut(JNIEnv* env, int aDataSpace) { switch (aDataSpace & ADataSpace::STANDARD_MASK) { diff --git a/libs/hwui/jni/YuvToJpegEncoder.h b/libs/hwui/jni/YuvToJpegEncoder.h index a3a322453be7..629f1e64726b 100644 --- a/libs/hwui/jni/YuvToJpegEncoder.h +++ b/libs/hwui/jni/YuvToJpegEncoder.h @@ -108,7 +108,7 @@ public: * @param aDataSpace data space defined in data_space.h. * @return color gamut for JPEG/R. */ - static android::ultrahdr::ultrahdr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace); + static ultrahdr::ultrahdr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace); /** Map data space (defined in DataSpace.java and data_space.h) to the transfer function * used in JPEG/R @@ -117,8 +117,8 @@ public: * @param aDataSpace data space defined in data_space.h. * @return color gamut for JPEG/R. */ - static android::ultrahdr::ultrahdr_transfer_function findHdrTransferFunction( - JNIEnv* env, int aDataSpace); + static ultrahdr::ultrahdr_transfer_function findHdrTransferFunction(JNIEnv* env, + int aDataSpace); }; #endif // _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_ diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index bf9419fe6603..4be282b5de87 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -29,6 +29,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import android.util.IntArray; import android.util.Log; import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; @@ -330,7 +331,7 @@ public final class AudioAttributes implements Parcelable { * @hide * Array of all usage types exposed in the SDK that applications can use. */ - public final static int[] SDK_USAGES = { + public static final IntArray SDK_USAGES = IntArray.wrap(new int[] { USAGE_UNKNOWN, USAGE_MEDIA, USAGE_VOICE_COMMUNICATION, @@ -347,14 +348,14 @@ public final class AudioAttributes implements Parcelable { USAGE_ASSISTANCE_SONIFICATION, USAGE_GAME, USAGE_ASSISTANT, - }; + }); /** * @hide */ @TestApi public static int[] getSdkUsages() { - return SDK_USAGES; + return SDK_USAGES.toArray(); } /** @@ -567,6 +568,15 @@ public final class AudioAttributes implements Parcelable { private String mFormattedTags; private Bundle mBundle; // lazy-initialized, may be null + /** Array of all content types exposed in the SDK that applications can use */ + private static final IntArray CONTENT_TYPES = IntArray.wrap(new int[]{ + CONTENT_TYPE_UNKNOWN, + CONTENT_TYPE_SPEECH, + CONTENT_TYPE_MUSIC, + CONTENT_TYPE_MOVIE, + CONTENT_TYPE_SONIFICATION, + }); + private AudioAttributes() { } @@ -1669,6 +1679,27 @@ public final class AudioAttributes implements Parcelable { } /** + * Query if the usage is a valid sdk usage + * + * @param usage one of {@link AttributeSdkUsage} + * @return {@code true} if the usage is valid for sdk or {@code false} otherwise + * @hide + */ + public static boolean isSdkUsage(@AttributeSdkUsage int usage) { + return SDK_USAGES.contains(usage); + } + + /** + * Query if the content type is a valid sdk content type + * @param contentType one of {@link AttributeContentType} + * @return {@code true} if the content type is valid for sdk or {@code false} otherwise + * @hide + */ + public static boolean isSdkContentType(@AttributeContentType int contentType) { + return CONTENT_TYPES.contains(contentType); + } + + /** * Returns the stream type matching this {@code AudioAttributes} instance for volume control. * Use this method to derive the stream type needed to configure the volume * control slider in an {@link android.app.Activity} with diff --git a/media/java/android/media/AudioHalVersionInfo.java b/media/java/android/media/AudioHalVersionInfo.java index 0f48abeb6882..c881a03c6732 100644 --- a/media/java/android/media/AudioHalVersionInfo.java +++ b/media/java/android/media/AudioHalVersionInfo.java @@ -80,9 +80,8 @@ public final class AudioHalVersionInfo implements Parcelable, Comparable<AudioHa * List of all valid Audio HAL versions. This list need to be in sync with sAudioHALVersions * defined in frameworks/av/media/libaudiohal/FactoryHalHidl.cpp. */ - // TODO: add AIDL_1_0 with sAudioHALVersions. public static final @NonNull List<AudioHalVersionInfo> VERSIONS = - List.of(HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0, HIDL_4_0); + List.of(AIDL_1_0, HIDL_7_1, HIDL_7_0, HIDL_6_0, HIDL_5_0, HIDL_4_0); private static final String TAG = "AudioHalVersionInfo"; private AudioHalVersion mHalVersion = new AudioHalVersion(); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 367b38a152fc..9ffd644493db 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -318,11 +318,12 @@ public class AudioSystem /** * @hide - * Convert a Bluetooth codec to an audio format enum + * Convert an A2DP Bluetooth codec to an audio format enum * @param btCodec the codec to convert. * @return the audio format, or {@link #AUDIO_FORMAT_DEFAULT} if unknown */ - public static @AudioFormatNativeEnumForBtCodec int bluetoothCodecToAudioFormat(int btCodec) { + public static @AudioFormatNativeEnumForBtCodec int bluetoothA2dpCodecToAudioFormat( + int btCodec) { switch (btCodec) { case BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC: return AudioSystem.AUDIO_FORMAT_SBC; @@ -339,7 +340,25 @@ public class AudioSystem case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS: return AudioSystem.AUDIO_FORMAT_OPUS; default: - Log.e(TAG, "Unknown BT codec 0x" + Integer.toHexString(btCodec) + Log.e(TAG, "Unknown A2DP BT codec 0x" + Integer.toHexString(btCodec) + + " for conversion to audio format"); + // TODO returning DEFAULT is the current behavior, should this return INVALID? + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + } + + /** + * @hide + * Convert a LE Audio Bluetooth codec to an audio format enum + * @param btCodec the codec to convert. + * @return the audio format, or {@link #AUDIO_FORMAT_DEFAULT} if unknown + */ + public static @AudioFormatNativeEnumForBtCodec int bluetoothLeCodecToAudioFormat(int btCodec) { + switch (btCodec) { + case BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3: + return AudioSystem.AUDIO_FORMAT_LC3; + default: + Log.e(TAG, "Unknown LE Audio BT codec 0x" + Integer.toHexString(btCodec) + " for conversion to audio format"); // TODO returning DEFAULT is the current behavior, should this return INVALID? return AudioSystem.AUDIO_FORMAT_DEFAULT; diff --git a/media/java/android/media/FadeManagerConfiguration.aidl b/media/java/android/media/FadeManagerConfiguration.aidl new file mode 100644 index 000000000000..ceb4ded76dcf --- /dev/null +++ b/media/java/android/media/FadeManagerConfiguration.aidl @@ -0,0 +1,23 @@ +/* + * 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 android.media; + +/** + * Class to encapsulate fade configurations. + * @hide + */ +parcelable FadeManagerConfiguration; diff --git a/media/java/android/media/FadeManagerConfiguration.java b/media/java/android/media/FadeManagerConfiguration.java new file mode 100644 index 000000000000..337d4b0a916c --- /dev/null +++ b/media/java/android/media/FadeManagerConfiguration.java @@ -0,0 +1,1684 @@ +/* + * 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 android.media; + +import static com.android.media.flags.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArrayMap; +import android.util.IntArray; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +/** + * Class to encapsulate fade configurations. + * + * <p>Configurations are provided through: + * <ul> + * <li>Fadeable list: a positive list of fadeable type - usage</li> + * <li>Unfadeable lists: negative list of unfadeable types - content type, uid, audio attributes + * </li> + * <li>Volume shaper configs: fade in and fade out configs per usage or audio attributes + * </li> + * </ul> + * + * <p>Fade manager configuration can be created in one of the following ways: + * <ul> + * <li>Disabled fades: + * <pre class="prettyprint"> + * new FadeManagerConfiguration.Builder() + * .setFadeState(FADE_STATE_DISABLED).build() + * </pre> + * Can be used to disable fading</li> + * <li>Default configurations including default fade duration: + * <pre class="prettyprint"> + * new FadeManagerConfiguration.Builder() + * .setFadeState(FADE_STATE_ENABLED_DEFAULT).build() + * </pre> + * Can be used to enable default fading configurations</li> + * <li>Default configurations with custom fade duration: + * <pre class="prettyprint"> + * new FadeManagerConfiguration.Builder(fade out duration, fade in duration) + * .setFadeState(FADE_STATE_ENABLED_DEFAULT).build() + * </pre> + * Can be used to enable default fadeability lists with configurable fade in and out duration + * </li> + * <li>Custom configurations and fade volume shapers: + * <pre class="prettyprint"> + * new FadeManagerConfiguration.Builder(fade out duration, fade in duration) + * .setFadeState(FADE_STATE_ENABLED_DEFAULT) + * .setFadeableUsages(list of usages) + * .setUnfadeableContentTypes(list of content types) + * .setUnfadeableUids(list of uids) + * .setUnfadeableAudioAttributes(list of audio attributes) + * .setFadeOutVolumeShaperConfigForAudioAttributes(attributes, volume shaper config) + * .setFadeInDurationForUsaeg(usage, duration) + * .... + * .build() </pre> + * Achieves full customization of fadeability lists and configurations</li> + * <li>Also provides a copy constructor from another instance of fade manager configuration + * <pre class="prettyprint"> + * new FadeManagerConfiguration.Builder(fadeManagerConfiguration) + * .addFadeableUsage(new usage) + * .... + * .build()</pre> + * Helps with recreating a new instance from another to simply change/add on top of the + * existing ones</li> + * </ul> + * TODO(b/304835727): Convert into system API so that it can be set through AudioPolicy + * + * @hide + */ + +@FlaggedApi(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION) +public final class FadeManagerConfiguration implements Parcelable { + + public static final String TAG = "FadeManagerConfiguration"; + + /** + * Defines the disabled fade state. No player will be faded in this state. + */ + public static final int FADE_STATE_DISABLED = 0; + + /** + * Defines the enabled fade state with default configurations + */ + public static final int FADE_STATE_ENABLED_DEFAULT = 1; + + /** + * Defines the enabled state with Automotive specific configurations + */ + public static final int FADE_STATE_ENABLED_AUTO = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = false, prefix = "FADE_STATE", value = { + FADE_STATE_DISABLED, + FADE_STATE_ENABLED_DEFAULT, + FADE_STATE_ENABLED_AUTO, + }) + public @interface FadeStateEnum {} + + /** + * Defines ID to be used in volume shaper for fading + */ + public static final int VOLUME_SHAPER_SYSTEM_FADE_ID = 2; + + /** + * Used to reset duration or return duration when not set + * + * @see Builder#setFadeOutDurationForUsage(int, long) + * @see Builder#setFadeInDurationForUsage(int, long) + * @see Builder#setFadeOutDurationForAudioAttributes(AudioAttributes, long) + * @see Builder#setFadeInDurationForAudioAttributes(AudioAttributes, long) + * @see #getFadeOutDurationForUsage(int) + * @see #getFadeInDurationForUsage(int) + * @see #getFadeOutDurationForAudioAttributes(AudioAttributes) + * @see #getFadeInDurationForAudioAttributes(AudioAttributes) + */ + public static final long DURATION_NOT_SET = 0; + /** Map of Usage to Fade volume shaper configs wrapper */ + private final SparseArray<FadeVolumeShaperConfigsWrapper> mUsageToFadeWrapperMap; + /** Map of AudioAttributes to Fade volume shaper configs wrapper */ + private final ArrayMap<AudioAttributes, FadeVolumeShaperConfigsWrapper> mAttrToFadeWrapperMap; + /** list of fadeable usages */ + private final @NonNull IntArray mFadeableUsages; + /** list of unfadeable content types */ + private final @NonNull IntArray mUnfadeableContentTypes; + /** list of unfadeable player types */ + private final @NonNull IntArray mUnfadeablePlayerTypes; + /** list of unfadeable uid(s) */ + private final @NonNull IntArray mUnfadeableUids; + /** list of unfadeable AudioAttributes */ + private final @NonNull List<AudioAttributes> mUnfadeableAudioAttributes; + /** fade state */ + private final @FadeStateEnum int mFadeState; + /** fade out duration from builder - used for creating default fade out volume shaper */ + private final long mFadeOutDurationMillis; + /** fade in duration from builder - used for creating default fade in volume shaper */ + private final long mFadeInDurationMillis; + /** delay after which the offending players are faded back in */ + private final long mFadeInDelayForOffendersMillis; + + private FadeManagerConfiguration(int fadeState, long fadeOutDurationMillis, + long fadeInDurationMillis, long offendersFadeInDelayMillis, + @NonNull SparseArray<FadeVolumeShaperConfigsWrapper> usageToFadeWrapperMap, + @NonNull ArrayMap<AudioAttributes, FadeVolumeShaperConfigsWrapper> attrToFadeWrapperMap, + @NonNull IntArray fadeableUsages, @NonNull IntArray unfadeableContentTypes, + @NonNull IntArray unfadeablePlayerTypes, @NonNull IntArray unfadeableUids, + @NonNull List<AudioAttributes> unfadeableAudioAttributes) { + mFadeState = fadeState; + mFadeOutDurationMillis = fadeOutDurationMillis; + mFadeInDurationMillis = fadeInDurationMillis; + mFadeInDelayForOffendersMillis = offendersFadeInDelayMillis; + mUsageToFadeWrapperMap = Objects.requireNonNull(usageToFadeWrapperMap, + "Usage to fade wrapper map cannot be null"); + mAttrToFadeWrapperMap = Objects.requireNonNull(attrToFadeWrapperMap, + "Attribute to fade wrapper map cannot be null"); + mFadeableUsages = Objects.requireNonNull(fadeableUsages, + "List of fadeable usages cannot be null"); + mUnfadeableContentTypes = Objects.requireNonNull(unfadeableContentTypes, + "List of unfadeable content types cannot be null"); + mUnfadeablePlayerTypes = Objects.requireNonNull(unfadeablePlayerTypes, + "List of unfadeable player types cannot be null"); + mUnfadeableUids = Objects.requireNonNull(unfadeableUids, + "List of unfadeable uids cannot be null"); + mUnfadeableAudioAttributes = Objects.requireNonNull(unfadeableAudioAttributes, + "List of unfadeable audio attributes cannot be null"); + } + + /** + * Get the fade state + * + * @return one of the {@link FadeStateEnum} state + */ + @FadeStateEnum + public int getFadeState() { + return mFadeState; + } + + /** + * Get the list of usages that can be faded + * + * @return list of {@link android.media.AudioAttributes.AttributeUsage} that shall be faded + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @NonNull + public List<Integer> getFadeableUsages() { + ensureFadingIsEnabled(); + return convertIntArrayToIntegerList(mFadeableUsages); + } + + /** + * Get the list of {@link android.media.AudioPlaybackConfiguration.PlayerType player types} + * that cannot be faded + * + * @return list of {@link android.media.AudioPlaybackConfiguration.PlayerType} + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @NonNull + public List<Integer> getUnfadeablePlayerTypes() { + ensureFadingIsEnabled(); + return convertIntArrayToIntegerList(mUnfadeablePlayerTypes); + } + + /** + * Get the list of {@link android.media.AudioAttributes.AttributeContentType content types} + * that cannot be faded + * + * @return list of {@link android.media.AudioAttributes.AttributeContentType} + * @throws IllegalStateExceptionif if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @NonNull + public List<Integer> getUnfadeableContentTypes() { + ensureFadingIsEnabled(); + return convertIntArrayToIntegerList(mUnfadeableContentTypes); + } + + /** + * Get the list of uids that cannot be faded + * + * @return list of uids that shall not be faded + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @NonNull + public List<Integer> getUnfadeableUids() { + ensureFadingIsEnabled(); + return convertIntArrayToIntegerList(mUnfadeableUids); + } + + /** + * Get the list of {@link android.media.AudioAttributes} that cannot be faded + * + * @return list of {@link android.media.AudioAttributes} that shall not be faded + * @throws IllegalStateException if fade state is set to {@link #FADE_STATE_DISABLED} + */ + @NonNull + public List<AudioAttributes> getUnfadeableAudioAttributes() { + ensureFadingIsEnabled(); + return mUnfadeableAudioAttributes; + } + + /** + * Get the duration used to fade out players with + * {@link android.media.AudioAttributes.AttributeUsage} + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} + * @return duration in milliseconds if set for the usage or {@link #DURATION_NOT_SET} otherwise + * @throws IllegalArgumentException if the usage is invalid + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + public long getFadeOutDurationForUsage(int usage) { + ensureFadingIsEnabled(); + validateUsage(usage); + return getDurationForVolumeShaperConfig(getVolumeShaperConfigFromWrapper( + mUsageToFadeWrapperMap.get(usage), /* isFadeIn= */ false)); + } + + /** + * Get the duration used to fade in players with + * {@link android.media.AudioAttributes.AttributeUsage} + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} + * @return duration in milliseconds if set for the usage or {@link #DURATION_NOT_SET} otherwise + * @throws IllegalArgumentException if the usage is invalid + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + public long getFadeInDurationForUsage(int usage) { + ensureFadingIsEnabled(); + validateUsage(usage); + return getDurationForVolumeShaperConfig(getVolumeShaperConfigFromWrapper( + mUsageToFadeWrapperMap.get(usage), /* isFadeIn= */ true)); + } + + /** + * Get the {@link android.media.VolumeShaper.Configuration} used to fade out players with + * {@link android.media.AudioAttributes.AttributeUsage} + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} + * @return {@link android.media.VolumeShaper.Configuration} if set for the usage or + * {@code null} otherwise + * @throws IllegalArgumentException if the usage is invalid + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @Nullable + public VolumeShaper.Configuration getFadeOutVolumeShaperConfigForUsage(int usage) { + ensureFadingIsEnabled(); + validateUsage(usage); + return getVolumeShaperConfigFromWrapper(mUsageToFadeWrapperMap.get(usage), + /* isFadeIn= */ false); + } + + /** + * Get the {@link android.media.VolumeShaper.Configuration} used to fade in players with + * {@link android.media.AudioAttributes.AttributeUsage} + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} of player + * @return {@link android.media.VolumeShaper.Configuration} if set for the usage or + * {@code null} otherwise + * @throws IllegalArgumentException if the usage is invalid + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @Nullable + public VolumeShaper.Configuration getFadeInVolumeShaperConfigForUsage(int usage) { + ensureFadingIsEnabled(); + validateUsage(usage); + return getVolumeShaperConfigFromWrapper(mUsageToFadeWrapperMap.get(usage), + /* isFadeIn= */ true); + } + + /** + * Get the duration used to fade out players with {@link android.media.AudioAttributes} + * + * @param audioAttributes {@link android.media.AudioAttributes} + * @return duration in milliseconds if set for the audio attributes or + * {@link #DURATION_NOT_SET} otherwise + * @throws NullPointerException if the audio attributes is {@code null} + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + public long getFadeOutDurationForAudioAttributes(@NonNull AudioAttributes audioAttributes) { + ensureFadingIsEnabled(); + return getDurationForVolumeShaperConfig(getVolumeShaperConfigFromWrapper( + mAttrToFadeWrapperMap.get(audioAttributes), /* isFadeIn= */ false)); + } + + /** + * Get the duration used to fade-in players with {@link android.media.AudioAttributes} + * + * @param audioAttributes {@link android.media.AudioAttributes} + * @return duration in milliseconds if set for the audio attributes or + * {@link #DURATION_NOT_SET} otherwise + * @throws NullPointerException if the audio attributes is {@code null} + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + public long getFadeInDurationForAudioAttributes(@NonNull AudioAttributes audioAttributes) { + ensureFadingIsEnabled(); + return getDurationForVolumeShaperConfig(getVolumeShaperConfigFromWrapper( + mAttrToFadeWrapperMap.get(audioAttributes), /* isFadeIn= */ true)); + } + + /** + * Get the {@link android.media.VolumeShaper.Configuration} used to fade out players with + * {@link android.media.AudioAttributes} + * + * @param audioAttributes {@link android.media.AudioAttributes} + * @return {@link android.media.VolumeShaper.Configuration} if set for the audio attribute or + * {@code null} otherwise + * @throws NullPointerException if the audio attributes is {@code null} + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @Nullable + public VolumeShaper.Configuration getFadeOutVolumeShaperConfigForAudioAttributes( + @NonNull AudioAttributes audioAttributes) { + Objects.requireNonNull(audioAttributes, "Audio attributes cannot be null"); + ensureFadingIsEnabled(); + return getVolumeShaperConfigFromWrapper(mAttrToFadeWrapperMap.get(audioAttributes), + /* isFadeIn= */ false); + } + + /** + * Get the {@link android.media.VolumeShaper.Configuration} used to fade out players with + * {@link android.media.AudioAttributes} + * + * @param audioAttributes {@link android.media.AudioAttributes} + * @return {@link android.media.VolumeShaper.Configuration} used for fading in if set for the + * audio attribute or {@code null} otherwise + * @throws NullPointerException if the audio attributes is {@code null} + * @throws IllegalStateException if the fade state is set to {@link #FADE_STATE_DISABLED} + */ + @Nullable + public VolumeShaper.Configuration getFadeInVolumeShaperConfigForAudioAttributes( + @NonNull AudioAttributes audioAttributes) { + Objects.requireNonNull(audioAttributes, "Audio attributes cannot be null"); + ensureFadingIsEnabled(); + return getVolumeShaperConfigFromWrapper(mAttrToFadeWrapperMap.get(audioAttributes), + /* isFadeIn= */ true); + } + + /** + * Get the list of {@link android.media.AudioAttributes} for whome the volume shaper + * configurations are defined + * + * @return list of {@link android.media.AudioAttributes} with valid volume shaper configs or + * empty list if none set. + */ + @NonNull + public List<AudioAttributes> getAudioAttributesWithVolumeShaperConfigs() { + return getAudioAttributesInternal(); + } + + /** + * Get the delay after which the offending players are faded back in + * + * @return delay in milliseconds + */ + public long getFadeInDelayForOffenders() { + return mFadeInDelayForOffendersMillis; + } + + /** + * Query if fade is enabled + * + * @return {@code true} if fading is enabled, {@code false} otherwise + */ + public boolean isFadeEnabled() { + return mFadeState != FADE_STATE_DISABLED; + } + + /** + * Query if the usage is fadeable + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} + * @return {@code true} if usage is fadeable, {@code false} otherwise + */ + public boolean isUsageFadeable(@AudioAttributes.AttributeUsage int usage) { + if (!isFadeEnabled()) { + return false; + } + return mFadeableUsages.contains(usage); + } + + /** + * Query if the content type is unfadeable + * + * @param contentType the {@link android.media.AudioAttributes.AttributeContentType} + * @return {@code true} if content type is unfadeable or if fade state is set to + * {@link #FADE_STATE_DISABLED}, {@code false} otherwise + */ + public boolean isContentTypeUnfadeable(@AudioAttributes.AttributeContentType int contentType) { + if (!isFadeEnabled()) { + return true; + } + return mUnfadeableContentTypes.contains(contentType); + } + + /** + * Query if the player type is unfadeable + * + * @param playerType the {@link android.media.AudioPlaybackConfiguration} player type + * @return {@code true} if player type is unfadeable or if fade state is set to + * {@link #FADE_STATE_DISABLED}, {@code false} otherwise + */ + public boolean isPlayerTypeUnfadeable(int playerType) { + if (!isFadeEnabled()) { + return true; + } + return mUnfadeablePlayerTypes.contains(playerType); + } + + /** + * Query if the audio attributes is unfadeable + * + * @param audioAttributes the {@link android.media.AudioAttributes} + * @return {@code true} if audio attributes is unfadeable or if fade state is set to + * {@link #FADE_STATE_DISABLED}, {@code false} otherwise + * @throws NullPointerException if the audio attributes is {@code null} + */ + public boolean isAudioAttributesUnfadeable(@NonNull AudioAttributes audioAttributes) { + Objects.requireNonNull(audioAttributes, "Audio attributes cannot be null"); + if (!isFadeEnabled()) { + return true; + } + return mUnfadeableAudioAttributes.contains(audioAttributes); + } + + /** + * Query if the uid is unfadeable + * + * @param uid the uid of application + * @return {@code true} if uid is unfadeable or if fade state is set to + * {@link #FADE_STATE_DISABLED}, {@code false} otherwise + */ + public boolean isUidUnfadeable(int uid) { + if (!isFadeEnabled()) { + return true; + } + return mUnfadeableUids.contains(uid); + } + + @Override + public String toString() { + return "FadeManagerConfiguration { fade state = " + fadeStateToString(mFadeState) + + ", fade out duration = " + mFadeOutDurationMillis + + ", fade in duration = " + mFadeInDurationMillis + + ", offenders fade in delay = " + mFadeInDelayForOffendersMillis + + ", fade volume shapers for audio attributes = " + mAttrToFadeWrapperMap + + ", fadeable usages = " + mFadeableUsages.toString() + + ", unfadeable content types = " + mUnfadeableContentTypes.toString() + + ", unfadeable player types = " + mUnfadeablePlayerTypes.toString() + + ", unfadeable uids = " + mUnfadeableUids.toString() + + ", unfadeable audio attributes = " + mUnfadeableAudioAttributes + "}"; + } + + /** + * Convert fade state into a human-readable string + * + * @param fadeState one of the fade state in {@link FadeStateEnum} + * @return human-readable string + */ + @NonNull + public static String fadeStateToString(@FadeStateEnum int fadeState) { + switch (fadeState) { + case FADE_STATE_DISABLED: + return "FADE_STATE_DISABLED"; + case FADE_STATE_ENABLED_DEFAULT: + return "FADE_STATE_ENABLED_DEFAULT"; + case FADE_STATE_ENABLED_AUTO: + return "FADE_STATE_ENABLED_AUTO"; + default: + return "unknown fade state: " + fadeState; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof FadeManagerConfiguration)) { + return false; + } + + FadeManagerConfiguration rhs = (FadeManagerConfiguration) o; + + return mUsageToFadeWrapperMap.contentEquals(rhs.mUsageToFadeWrapperMap) + && mAttrToFadeWrapperMap.equals(rhs.mAttrToFadeWrapperMap) + && Arrays.equals(mFadeableUsages.toArray(), rhs.mFadeableUsages.toArray()) + && Arrays.equals(mUnfadeableContentTypes.toArray(), + rhs.mUnfadeableContentTypes.toArray()) + && Arrays.equals(mUnfadeablePlayerTypes.toArray(), + rhs.mUnfadeablePlayerTypes.toArray()) + && Arrays.equals(mUnfadeableUids.toArray(), rhs.mUnfadeableUids.toArray()) + && mUnfadeableAudioAttributes.equals(rhs.mUnfadeableAudioAttributes) + && mFadeState == rhs.mFadeState + && mFadeOutDurationMillis == rhs.mFadeOutDurationMillis + && mFadeInDurationMillis == rhs.mFadeInDurationMillis + && mFadeInDelayForOffendersMillis == rhs.mFadeInDelayForOffendersMillis; + } + + @Override + public int hashCode() { + return Objects.hash(mUsageToFadeWrapperMap, mAttrToFadeWrapperMap, mFadeableUsages, + mUnfadeableContentTypes, mUnfadeablePlayerTypes, mUnfadeableAudioAttributes, + mUnfadeableUids, mFadeState, mFadeOutDurationMillis, mFadeInDurationMillis, + mFadeInDelayForOffendersMillis); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mFadeState); + dest.writeLong(mFadeOutDurationMillis); + dest.writeLong(mFadeInDurationMillis); + dest.writeLong(mFadeInDelayForOffendersMillis); + dest.writeTypedSparseArray(mUsageToFadeWrapperMap, flags); + dest.writeMap(mAttrToFadeWrapperMap); + dest.writeIntArray(mFadeableUsages.toArray()); + dest.writeIntArray(mUnfadeableContentTypes.toArray()); + dest.writeIntArray(mUnfadeablePlayerTypes.toArray()); + dest.writeIntArray(mUnfadeableUids.toArray()); + dest.writeTypedList(mUnfadeableAudioAttributes, flags); + } + + /** + * Creates fade manage configuration from parcel + * + * @hide + */ + @VisibleForTesting() + FadeManagerConfiguration(Parcel in) { + int fadeState = in.readInt(); + long fadeOutDurationMillis = in.readLong(); + long fadeInDurationMillis = in.readLong(); + long fadeInDelayForOffenders = in.readLong(); + SparseArray<FadeVolumeShaperConfigsWrapper> usageToWrapperMap = + in.createTypedSparseArray(FadeVolumeShaperConfigsWrapper.CREATOR); + ArrayMap<AudioAttributes, FadeVolumeShaperConfigsWrapper> attrToFadeWrapperMap = + new ArrayMap<>(); + in.readMap(attrToFadeWrapperMap, getClass().getClassLoader(), AudioAttributes.class, + FadeVolumeShaperConfigsWrapper.class); + int[] fadeableUsages = in.createIntArray(); + int[] unfadeableContentTypes = in.createIntArray(); + int[] unfadeablePlayerTypes = in.createIntArray(); + int[] unfadeableUids = in.createIntArray(); + List<AudioAttributes> unfadeableAudioAttributes = new ArrayList<>(); + in.readTypedList(unfadeableAudioAttributes, AudioAttributes.CREATOR); + + this.mFadeState = fadeState; + this.mFadeOutDurationMillis = fadeOutDurationMillis; + this.mFadeInDurationMillis = fadeInDurationMillis; + this.mFadeInDelayForOffendersMillis = fadeInDelayForOffenders; + this.mUsageToFadeWrapperMap = usageToWrapperMap; + this.mAttrToFadeWrapperMap = attrToFadeWrapperMap; + this.mFadeableUsages = IntArray.wrap(fadeableUsages); + this.mUnfadeableContentTypes = IntArray.wrap(unfadeableContentTypes); + this.mUnfadeablePlayerTypes = IntArray.wrap(unfadeablePlayerTypes); + this.mUnfadeableUids = IntArray.wrap(unfadeableUids); + this.mUnfadeableAudioAttributes = unfadeableAudioAttributes; + } + + @NonNull + public static final Creator<FadeManagerConfiguration> CREATOR = new Creator<>() { + @Override + @NonNull + public FadeManagerConfiguration createFromParcel(@NonNull Parcel in) { + return new FadeManagerConfiguration(in); + } + + @Override + @NonNull + public FadeManagerConfiguration[] newArray(int size) { + return new FadeManagerConfiguration[size]; + } + }; + + private long getDurationForVolumeShaperConfig(VolumeShaper.Configuration config) { + return config != null ? config.getDuration() : DURATION_NOT_SET; + } + + private VolumeShaper.Configuration getVolumeShaperConfigFromWrapper( + FadeVolumeShaperConfigsWrapper wrapper, boolean isFadeIn) { + // if no volume shaper config is available, return null + if (wrapper == null) { + return null; + } + if (isFadeIn) { + return wrapper.getFadeInVolShaperConfig(); + } + return wrapper.getFadeOutVolShaperConfig(); + } + + private List<AudioAttributes> getAudioAttributesInternal() { + List<AudioAttributes> attrs = new ArrayList<>(mAttrToFadeWrapperMap.size()); + for (int index = 0; index < mAttrToFadeWrapperMap.size(); index++) { + attrs.add(mAttrToFadeWrapperMap.keyAt(index)); + } + return attrs; + } + + private static boolean isUsageValid(int usage) { + return AudioAttributes.isSdkUsage(usage) || AudioAttributes.isSystemUsage(usage); + } + + private void ensureFadingIsEnabled() { + if (!isFadeEnabled()) { + throw new IllegalStateException("Method call not allowed when fade is disabled"); + } + } + + private static void validateUsage(int usage) { + Preconditions.checkArgument(isUsageValid(usage), "Invalid usage: %s", usage); + } + + private static IntArray convertIntegerListToIntArray(List<Integer> integerList) { + if (integerList == null) { + return new IntArray(); + } + + IntArray intArray = new IntArray(integerList.size()); + for (int index = 0; index < integerList.size(); index++) { + intArray.add(integerList.get(index)); + } + return intArray; + } + + private static List<Integer> convertIntArrayToIntegerList(IntArray intArray) { + if (intArray == null) { + return new ArrayList<>(); + } + + ArrayList<Integer> integerArrayList = new ArrayList<>(intArray.size()); + for (int index = 0; index < intArray.size(); index++) { + integerArrayList.add(intArray.get(index)); + } + return integerArrayList; + } + + /** + * Builder class for {@link FadeManagerConfiguration} objects. + * + * <p><b>Notes:</b> + * <ul> + * <li>When fade state is set to enabled, the builder expects at least one valid usage to be + * set/added. Failure to do so will result in an exception during {@link #build()}</li> + * <li>Every usage added to the fadeable list should have corresponding volume shaper + * configs defined. This can be achieved by setting either the duration or volume shaper + * config through {@link #setFadeOutDurationForUsage(int, long)} or + * {@link #setFadeOutVolumeShaperConfigForUsage(int, VolumeShaper.Configuration)}</li> + * <li> It is recommended to set volume shaper configurations individually for fade out and + * fade in</li> + * <li>For any incomplete volume shaper configs a volume shaper configuration will be + * created using either the default fade durations or the ones provided as part of the + * {@link #Builder(long, long)}</li> + * <li>Additional volume shaper configs can also configured for a given usage + * with additional attributes like content-type in order to achieve finer fade controls. + * See: + * {@link #setFadeOutVolumeShaperConfigForAudioAttributes(AudioAttributes, + * VolumeShaper.Configuration)} and + * {@link #setFadeInVolumeShaperConfigForAudioAttributes(AudioAttributes, + * VolumeShaper.Configuration)} </li> + * </ul> + * + */ + @SuppressWarnings("WeakerAccess") + public static final class Builder { + private static final int INVALID_INDEX = -1; + private static final long IS_BUILDER_USED_FIELD_SET = 1 << 0; + private static final long IS_FADEABLE_USAGES_FIELD_SET = 1 << 1; + private static final long IS_UNFADEABLE_CONTENT_TYPE_FIELD_SET = 1 << 2; + + /** duration of the fade out curve */ + private static final long DEFAULT_FADE_OUT_DURATION_MS = 2_000; + /** duration of the fade in curve */ + private static final long DEFAULT_FADE_IN_DURATION_MS = 1_000; + + /** + * delay after which a faded out player will be faded back in. This will be heard by the + * user only in the case of unmuting players that didn't respect audio focus and didn't + * stop/pause when their app lost focus. + * This is the amount of time between the app being notified of the focus loss + * (when its muted by the fade out), and the time fade in (to unmute) starts + */ + private static final long DEFAULT_DELAY_FADE_IN_OFFENDERS_MS = 2_000; + + + private static final IntArray DEFAULT_UNFADEABLE_PLAYER_TYPES = IntArray.wrap(new int[]{ + AudioPlaybackConfiguration.PLAYER_TYPE_AAUDIO, + AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL + }); + + private static final IntArray DEFAULT_UNFADEABLE_CONTENT_TYPES = IntArray.wrap(new int[]{ + AudioAttributes.CONTENT_TYPE_SPEECH + }); + + private static final IntArray DEFAULT_FADEABLE_USAGES = IntArray.wrap(new int[]{ + AudioAttributes.USAGE_GAME, + AudioAttributes.USAGE_MEDIA + }); + + private int mFadeState = FADE_STATE_ENABLED_DEFAULT; + private long mFadeInDelayForOffendersMillis = DEFAULT_DELAY_FADE_IN_OFFENDERS_MS; + private long mFadeOutDurationMillis; + private long mFadeInDurationMillis; + private long mBuilderFieldsSet; + private SparseArray<FadeVolumeShaperConfigsWrapper> mUsageToFadeWrapperMap = + new SparseArray<>(); + private ArrayMap<AudioAttributes, FadeVolumeShaperConfigsWrapper> mAttrToFadeWrapperMap = + new ArrayMap<>(); + private IntArray mFadeableUsages = new IntArray(); + private IntArray mUnfadeableContentTypes = new IntArray(); + // Player types are not yet configurable + private IntArray mUnfadeablePlayerTypes = DEFAULT_UNFADEABLE_PLAYER_TYPES; + private IntArray mUnfadeableUids = new IntArray(); + private List<AudioAttributes> mUnfadeableAudioAttributes = new ArrayList<>(); + + /** + * Constructs a new Builder with default fade out and fade in durations + */ + public Builder() { + mFadeOutDurationMillis = DEFAULT_FADE_OUT_DURATION_MS; + mFadeInDurationMillis = DEFAULT_FADE_IN_DURATION_MS; + } + + /** + * Constructs a new Builder with the provided fade out and fade in durations + * + * @param fadeOutDurationMillis duration in milliseconds used for fading out + * @param fadeInDurationMills duration in milliseconds used for fading in + */ + public Builder(long fadeOutDurationMillis, long fadeInDurationMills) { + mFadeOutDurationMillis = fadeOutDurationMillis; + mFadeInDurationMillis = fadeInDurationMills; + } + + /** + * Constructs a new Builder from the given {@link FadeManagerConfiguration} + * + * @param fmc the {@link FadeManagerConfiguration} object whose data will be reused in the + * new builder + */ + public Builder(@NonNull FadeManagerConfiguration fmc) { + mFadeState = fmc.mFadeState; + mUsageToFadeWrapperMap = fmc.mUsageToFadeWrapperMap.clone(); + mAttrToFadeWrapperMap = new ArrayMap<AudioAttributes, FadeVolumeShaperConfigsWrapper>( + fmc.mAttrToFadeWrapperMap); + mFadeableUsages = fmc.mFadeableUsages.clone(); + setFlag(IS_FADEABLE_USAGES_FIELD_SET); + mUnfadeableContentTypes = fmc.mUnfadeableContentTypes.clone(); + setFlag(IS_UNFADEABLE_CONTENT_TYPE_FIELD_SET); + mUnfadeablePlayerTypes = fmc.mUnfadeablePlayerTypes.clone(); + mUnfadeableUids = fmc.mUnfadeableUids.clone(); + mUnfadeableAudioAttributes = new ArrayList<>(fmc.mUnfadeableAudioAttributes); + mFadeOutDurationMillis = fmc.mFadeOutDurationMillis; + mFadeInDurationMillis = fmc.mFadeInDurationMillis; + } + + /** + * Set the overall fade state + * + * @param state one of the {@link FadeStateEnum} states + * @return the same Builder instance + * @throws IllegalArgumentException if the fade state is invalid + * @see #getFadeState() + */ + @NonNull + public Builder setFadeState(@FadeStateEnum int state) { + validateFadeState(state); + mFadeState = state; + return this; + } + + /** + * Set the {@link android.media.VolumeShaper.Configuration} used to fade out players with + * {@link android.media.AudioAttributes.AttributeUsage} + * <p> + * This method accepts {@code null} for volume shaper config to clear a previously set + * configuration (example, if set through + * {@link #Builder(android.media.FadeManagerConfiguration)}) + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} of target player + * @param fadeOutVShaperConfig the {@link android.media.VolumeShaper.Configuration} used + * to fade out players with usage + * @return the same Builder instance + * @throws IllegalArgumentException if the usage is invalid + * @see #getFadeOutVolumeShaperConfigForUsage(int) + */ + @NonNull + public Builder setFadeOutVolumeShaperConfigForUsage(int usage, + @Nullable VolumeShaper.Configuration fadeOutVShaperConfig) { + validateUsage(usage); + getFadeVolShaperConfigWrapperForUsage(usage) + .setFadeOutVolShaperConfig(fadeOutVShaperConfig); + cleanupInactiveWrapperEntries(usage); + return this; + } + + /** + * Set the {@link android.media.VolumeShaper.Configuration} used to fade in players with + * {@link android.media.AudioAttributes.AttributeUsage} + * <p> + * This method accepts {@code null} for volume shaper config to clear a previously set + * configuration (example, if set through + * {@link #Builder(android.media.FadeManagerConfiguration)}) + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} + * @param fadeInVShaperConfig the {@link android.media.VolumeShaper.Configuration} used + * to fade in players with usage + * @return the same Builder instance + * @throws IllegalArgumentException if the usage is invalid + * @see #getFadeInVolumeShaperConfigForUsage(int) + */ + @NonNull + public Builder setFadeInVolumeShaperConfigForUsage(int usage, + @Nullable VolumeShaper.Configuration fadeInVShaperConfig) { + validateUsage(usage); + getFadeVolShaperConfigWrapperForUsage(usage) + .setFadeInVolShaperConfig(fadeInVShaperConfig); + cleanupInactiveWrapperEntries(usage); + return this; + } + + /** + * Set the duration used for fading out players with + * {@link android.media.AudioAttributes.AttributeUsage} + * <p> + * A Volume shaper configuration is generated with the provided duration and default + * volume curve definitions. This config is then used to fade out players with given usage. + * <p> + * In order to clear previously set duration (example, if set through + * {@link #Builder(android.media.FadeManagerConfiguration)}), this method accepts + * {@link #DURATION_NOT_SET} and sets the corresponding fade out volume shaper config to + * {@code null} + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} of target player + * @param fadeOutDurationMillis positive duration in milliseconds or + * {@link #DURATION_NOT_SET} + * @return the same Builder instance + * @throws IllegalArgumentException if the fade out duration is non-positive with the + * exception of {@link #DURATION_NOT_SET} + * @see #setFadeOutVolumeShaperConfigForUsage(int, VolumeShaper.Configuration) + * @see #getFadeOutDurationForUsage(int) + */ + @NonNull + public Builder setFadeOutDurationForUsage(int usage, long fadeOutDurationMillis) { + validateUsage(usage); + VolumeShaper.Configuration fadeOutVShaperConfig = + createVolShaperConfigForDuration(fadeOutDurationMillis, /* isFadeIn= */ false); + setFadeOutVolumeShaperConfigForUsage(usage, fadeOutVShaperConfig); + return this; + } + + /** + * Set the duration used for fading in players with + * {@link android.media.AudioAttributes.AttributeUsage} + * <p> + * A Volume shaper configuration is generated with the provided duration and default + * volume curve definitions. This config is then used to fade in players with given usage. + * <p> + * <b>Note: </b>In order to clear previously set duration (example, if set through + * {@link #Builder(android.media.FadeManagerConfiguration)}), this method accepts + * {@link #DURATION_NOT_SET} and sets the corresponding fade in volume shaper config to + * {@code null} + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} of target player + * @param fadeInDurationMillis positive duration in milliseconds or + * {@link #DURATION_NOT_SET} + * @return the same Builder instance + * @throws IllegalArgumentException if the fade in duration is non-positive with the + * exception of {@link #DURATION_NOT_SET} + * @see #setFadeInVolumeShaperConfigForUsage(int, VolumeShaper.Configuration) + * @see #getFadeInDurationForUsage(int) + */ + @NonNull + public Builder setFadeInDurationForUsage(int usage, long fadeInDurationMillis) { + validateUsage(usage); + VolumeShaper.Configuration fadeInVShaperConfig = + createVolShaperConfigForDuration(fadeInDurationMillis, /* isFadeIn= */ true); + setFadeInVolumeShaperConfigForUsage(usage, fadeInVShaperConfig); + return this; + } + + /** + * Set the {@link android.media.VolumeShaper.Configuration} used to fade out players with + * {@link android.media.AudioAttributes} + * <p> + * This method accepts {@code null} for volume shaper config to clear a previously set + * configuration (example, set through + * {@link #Builder(android.media.FadeManagerConfiguration)}) + * + * @param audioAttributes the {@link android.media.AudioAttributes} + * @param fadeOutVShaperConfig the {@link android.media.VolumeShaper.Configuration} used to + * fade out players with audio attribute + * @return the same Builder instance + * @throws NullPointerException if the audio attributes is {@code null} + * @see #getFadeOutVolumeShaperConfigForAudioAttributes(AudioAttributes) + */ + @NonNull + public Builder setFadeOutVolumeShaperConfigForAudioAttributes( + @NonNull AudioAttributes audioAttributes, + @Nullable VolumeShaper.Configuration fadeOutVShaperConfig) { + Objects.requireNonNull(audioAttributes, "Audio attribute cannot be null"); + getFadeVolShaperConfigWrapperForAttr(audioAttributes) + .setFadeOutVolShaperConfig(fadeOutVShaperConfig); + cleanupInactiveWrapperEntries(audioAttributes); + return this; + } + + /** + * Set the {@link android.media.VolumeShaper.Configuration} used to fade in players with + * {@link android.media.AudioAttributes} + * + * <p>This method accepts {@code null} for volume shaper config to clear a previously set + * configuration (example, set through + * {@link #Builder(android.media.FadeManagerConfiguration)}) + * + * @param audioAttributes the {@link android.media.AudioAttributes} + * @param fadeInVShaperConfig the {@link android.media.VolumeShaper.Configuration} used to + * fade in players with audio attribute + * @return the same Builder instance + * @throws NullPointerException if the audio attributes is {@code null} + * @see #getFadeInVolumeShaperConfigForAudioAttributes(AudioAttributes) + */ + @NonNull + public Builder setFadeInVolumeShaperConfigForAudioAttributes( + @NonNull AudioAttributes audioAttributes, + @Nullable VolumeShaper.Configuration fadeInVShaperConfig) { + Objects.requireNonNull(audioAttributes, "Audio attribute cannot be null"); + getFadeVolShaperConfigWrapperForAttr(audioAttributes) + .setFadeInVolShaperConfig(fadeInVShaperConfig); + cleanupInactiveWrapperEntries(audioAttributes); + return this; + } + + /** + * Set the duration used for fading out players of type + * {@link android.media.AudioAttributes}. + * <p> + * A Volume shaper configuration is generated with the provided duration and default + * volume curve definitions. This config is then used to fade out players with given usage. + * <p> + * <b>Note: </b>In order to clear previously set duration (example, if set through + * {@link #Builder(android.media.FadeManagerConfiguration)}), this method accepts + * {@link #DURATION_NOT_SET} and sets the corresponding fade out volume shaper config to + * {@code null} + * + * @param audioAttributes the {@link android.media.AudioAttributes} for which the fade out + * duration will be set/updated/reset + * @param fadeOutDurationMillis positive duration in milliseconds or + * {@link #DURATION_NOT_SET} + * @return the same Builder instance + * @throws IllegalArgumentException if the fade out duration is non-positive with the + * exception of {@link #DURATION_NOT_SET} + * @see #getFadeOutDurationForAudioAttributes(AudioAttributes) + * @see #setFadeOutVolumeShaperConfigForAudioAttributes(AudioAttributes, + * VolumeShaper.Configuration) + */ + @NonNull + public Builder setFadeOutDurationForAudioAttributes( + @NonNull AudioAttributes audioAttributes, + long fadeOutDurationMillis) { + Objects.requireNonNull(audioAttributes, "Audio attribute cannot be null"); + VolumeShaper.Configuration fadeOutVShaperConfig = + createVolShaperConfigForDuration(fadeOutDurationMillis, /* isFadeIn= */ false); + setFadeOutVolumeShaperConfigForAudioAttributes(audioAttributes, fadeOutVShaperConfig); + return this; + } + + /** + * Set the duration used for fading in players of type + * {@link android.media.AudioAttributes}. + * <p> + * A Volume shaper configuration is generated with the provided duration and default + * volume curve definitions. This config is then used to fade in players with given usage. + * <p> + * <b>Note: </b>In order to clear previously set duration (example, if set through + * {@link #Builder(android.media.FadeManagerConfiguration)}), this method accepts + * {@link #DURATION_NOT_SET} and sets the corresponding fade in volume shaper config to + * {@code null} + * + * @param audioAttributes the {@link android.media.AudioAttributes} for which the fade in + * duration will be set/updated/reset + * @param fadeInDurationMillis positive duration in milliseconds or + * {@link #DURATION_NOT_SET} + * @return the same Builder instance + * @throws IllegalArgumentException if the fade in duration is non-positive with the + * exception of {@link #DURATION_NOT_SET} + * @see #getFadeInDurationForAudioAttributes(AudioAttributes) + * @see #setFadeInVolumeShaperConfigForAudioAttributes(AudioAttributes, + * VolumeShaper.Configuration) + */ + @NonNull + public Builder setFadeInDurationForAudioAttributes(@NonNull AudioAttributes audioAttributes, + long fadeInDurationMillis) { + Objects.requireNonNull(audioAttributes, "Audio attribute cannot be null"); + VolumeShaper.Configuration fadeInVShaperConfig = + createVolShaperConfigForDuration(fadeInDurationMillis, /* isFadeIn= */ true); + setFadeInVolumeShaperConfigForAudioAttributes(audioAttributes, fadeInVShaperConfig); + return this; + } + + /** + * Set the list of {@link android.media.AudioAttributes.AttributeUsage} that can be faded + * + * <p>This is a positive list. Players with matching usage will be considered for fading. + * Usages that are not part of this list will not be faded + * + * <p>Passing an empty list as input clears the existing list. This can be used to + * reset the list when using a copy constructor + * + * <p><b>Warning:</b> When fade state is set to enabled, the builder expects at least one + * usage to be set/added. Failure to do so will result in an exception during + * {@link #build()} + * + * @param usages List of the {@link android.media.AudioAttributes.AttributeUsage} + * @return the same Builder instance + * @throws IllegalArgumentException if the usages are invalid + * @throws NullPointerException if the usage list is {@code null} + * @see #getFadeableUsages() + */ + @NonNull + public Builder setFadeableUsages(@NonNull List<Integer> usages) { + Objects.requireNonNull(usages, "List of usages cannot be null"); + validateUsages(usages); + setFlag(IS_FADEABLE_USAGES_FIELD_SET); + mFadeableUsages.clear(); + mFadeableUsages.addAll(convertIntegerListToIntArray(usages)); + return this; + } + + /** + * Add the {@link android.media.AudioAttributes.AttributeUsage} to the fadeable list + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} + * @return the same Builder instance + * @throws IllegalArgumentException if the usage is invalid + * @see #getFadeableUsages() + * @see #setFadeableUsages(List) + */ + @NonNull + public Builder addFadeableUsage(@AudioAttributes.AttributeUsage int usage) { + validateUsage(usage); + setFlag(IS_FADEABLE_USAGES_FIELD_SET); + if (!mFadeableUsages.contains(usage)) { + mFadeableUsages.add(usage); + } + return this; + } + + /** + * Remove the {@link android.media.AudioAttributes.AttributeUsage} from the fadeable list + * <p> + * Players of this usage type will not be faded. + * + * @param usage the {@link android.media.AudioAttributes.AttributeUsage} + * @return the same Builder instance + * @throws IllegalArgumentException if the usage is invalid + * @see #getFadeableUsages() + * @see #setFadeableUsages(List) + */ + @NonNull + public Builder clearFadeableUsage(@AudioAttributes.AttributeUsage int usage) { + validateUsage(usage); + setFlag(IS_FADEABLE_USAGES_FIELD_SET); + int index = mFadeableUsages.indexOf(usage); + if (index != INVALID_INDEX) { + mFadeableUsages.remove(index); + } + return this; + } + + /** + * Set the list of {@link android.media.AudioAttributes.AttributeContentType} that can not + * be faded + * + * <p>This is a negative list. Players with matching content type of this list will not be + * faded. Content types that are not part of this list will be considered for fading. + * + * <p>Passing an empty list as input clears the existing list. This can be used to + * reset the list when using a copy constructor + * + * @param contentTypes list of {@link android.media.AudioAttributes.AttributeContentType} + * @return the same Builder instance + * @throws IllegalArgumentException if the content types are invalid + * @throws NullPointerException if the content type list is {@code null} + * @see #getUnfadeableContentTypes() + */ + @NonNull + public Builder setUnfadeableContentTypes(@NonNull List<Integer> contentTypes) { + Objects.requireNonNull(contentTypes, "List of content types cannot be null"); + validateContentTypes(contentTypes); + setFlag(IS_UNFADEABLE_CONTENT_TYPE_FIELD_SET); + mUnfadeableContentTypes.clear(); + mUnfadeableContentTypes.addAll(convertIntegerListToIntArray(contentTypes)); + return this; + } + + /** + * Add the {@link android.media.AudioAttributes.AttributeContentType} to unfadeable list + * + * @param contentType the {@link android.media.AudioAttributes.AttributeContentType} + * @return the same Builder instance + * @throws IllegalArgumentException if the content type is invalid + * @see #setUnfadeableContentTypes(List) + * @see #getUnfadeableContentTypes() + */ + @NonNull + public Builder addUnfadeableContentType( + @AudioAttributes.AttributeContentType int contentType) { + validateContentType(contentType); + setFlag(IS_UNFADEABLE_CONTENT_TYPE_FIELD_SET); + if (!mUnfadeableContentTypes.contains(contentType)) { + mUnfadeableContentTypes.add(contentType); + } + return this; + } + + /** + * Remove the {@link android.media.AudioAttributes.AttributeContentType} from the + * unfadeable list + * + * @param contentType the {@link android.media.AudioAttributes.AttributeContentType} + * @return the same Builder instance + * @throws IllegalArgumentException if the content type is invalid + * @see #setUnfadeableContentTypes(List) + * @see #getUnfadeableContentTypes() + */ + @NonNull + public Builder clearUnfadeableContentType( + @AudioAttributes.AttributeContentType int contentType) { + validateContentType(contentType); + setFlag(IS_UNFADEABLE_CONTENT_TYPE_FIELD_SET); + int index = mUnfadeableContentTypes.indexOf(contentType); + if (index != INVALID_INDEX) { + mUnfadeableContentTypes.remove(index); + } + return this; + } + + /** + * Set the uids that cannot be faded + * + * <p>This is a negative list. Players with matching uid of this list will not be faded. + * Uids that are not part of this list shall be considered for fading + * + * <p>Passing an empty list as input clears the existing list. This can be used to + * reset the list when using a copy constructor + * + * @param uids list of uids + * @return the same Builder instance + * @throws NullPointerException if the uid list is {@code null} + * @see #getUnfadeableUids() + */ + @NonNull + public Builder setUnfadeableUids(@NonNull List<Integer> uids) { + Objects.requireNonNull(uids, "List of uids cannot be null"); + mUnfadeableUids.clear(); + mUnfadeableUids.addAll(convertIntegerListToIntArray(uids)); + return this; + } + + /** + * Add uid to unfadeable list + * + * @param uid client uid + * @return the same Builder instance + * @see #setUnfadeableUids(List) + * @see #getUnfadeableUids() + */ + @NonNull + public Builder addUnfadeableUid(int uid) { + if (!mUnfadeableUids.contains(uid)) { + mUnfadeableUids.add(uid); + } + return this; + } + + /** + * Remove the uid from unfadeable list + * + * @param uid client uid + * @return the same Builder instance + * @see #setUnfadeableUids(List) + * @see #getUnfadeableUids() + */ + @NonNull + public Builder clearUnfadeableUid(int uid) { + int index = mUnfadeableUids.indexOf(uid); + if (index != INVALID_INDEX) { + mUnfadeableUids.remove(index); + } + return this; + } + + /** + * Set the list of {@link android.media.AudioAttributes} that can not be faded + * + * <p>This is a negative list. Players with matching audio attributes of this list will not + * be faded. Audio attributes that are not part of this list shall be considered for fading. + * + * <p>Passing an empty list as input clears any existing list. This can be used to + * reset the list when using a copy constructor + * + * <p><b>Note:</b> Be cautious when adding generic audio attributes into this list as it can + * negatively impact fadeability decision if such an audio attribute and corresponding + * usage fall into opposing lists. + * For example: + * <pre class=prettyprint> + * AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build() </pre> + * is a generic audio attribute for {@link android.media.AudioAttributes.USAGE_MEDIA}. + * It is an undefined behavior to have an + * {@link android.media.AudioAttributes.AttributeUsage} in the fadeable usage list and the + * corresponding generic {@link android.media.AudioAttributes} in the unfadeable list. Such + * cases will result in an exception during {@link #build()} + * + * @param attrs list of {@link android.media.AudioAttributes} + * @return the same Builder instance + * @throws NullPointerException if the audio attributes list is {@code null} + * @see #getUnfadeableAudioAttributes() + */ + @NonNull + public Builder setUnfadeableAudioAttributes(@NonNull List<AudioAttributes> attrs) { + Objects.requireNonNull(attrs, "List of audio attributes cannot be null"); + mUnfadeableAudioAttributes.clear(); + mUnfadeableAudioAttributes.addAll(attrs); + return this; + } + + /** + * Add the {@link android.media.AudioAttributes} to the unfadeable list + * + * @param audioAttributes the {@link android.media.AudioAttributes} + * @return the same Builder instance + * @throws NullPointerException if the audio attributes is {@code null} + * @see #setUnfadeableAudioAttributes(List) + * @see #getUnfadeableAudioAttributes() + */ + @NonNull + public Builder addUnfadeableAudioAttributes(@NonNull AudioAttributes audioAttributes) { + Objects.requireNonNull(audioAttributes, "Audio attributes cannot be null"); + if (!mUnfadeableAudioAttributes.contains(audioAttributes)) { + mUnfadeableAudioAttributes.add(audioAttributes); + } + return this; + } + + /** + * Remove the {@link android.media.AudioAttributes} from the unfadeable list. + * + * @param audioAttributes the {@link android.media.AudioAttributes} + * @return the same Builder instance + * @throws NullPointerException if the audio attributes is {@code null} + * @see #getUnfadeableAudioAttributes() + */ + @NonNull + public Builder clearUnfadeableAudioAttributes(@NonNull AudioAttributes audioAttributes) { + Objects.requireNonNull(audioAttributes, "Audio attributes cannot be null"); + if (mUnfadeableAudioAttributes.contains(audioAttributes)) { + mUnfadeableAudioAttributes.remove(audioAttributes); + } + return this; + } + + /** + * Set the delay after which the offending faded out player will be faded in. + * + * <p>This is the amount of time between the app being notified of the focus loss (when its + * muted by the fade out), and the time fade in (to unmute) starts + * + * @param delayMillis delay in milliseconds + * @return the same Builder instance + * @throws IllegalArgumentException if the delay is negative + * @see #getFadeInDelayForOffenders() + */ + @NonNull + public Builder setFadeInDelayForOffenders(long delayMillis) { + Preconditions.checkArgument(delayMillis >= 0, "Delay cannot be negative"); + mFadeInDelayForOffendersMillis = delayMillis; + return this; + } + + /** + * Builds the {@link FadeManagerConfiguration} with all of the fade configurations that + * have been set. + * + * @return a new {@link FadeManagerConfiguration} object + */ + @NonNull + public FadeManagerConfiguration build() { + if (!checkNotSet(IS_BUILDER_USED_FIELD_SET)) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + + setFlag(IS_BUILDER_USED_FIELD_SET); + + if (checkNotSet(IS_FADEABLE_USAGES_FIELD_SET)) { + mFadeableUsages = DEFAULT_FADEABLE_USAGES; + setVolShaperConfigsForUsages(mFadeableUsages); + } + + if (checkNotSet(IS_UNFADEABLE_CONTENT_TYPE_FIELD_SET)) { + mUnfadeableContentTypes = DEFAULT_UNFADEABLE_CONTENT_TYPES; + } + + validateFadeConfigurations(); + + return new FadeManagerConfiguration(mFadeState, mFadeOutDurationMillis, + mFadeInDurationMillis, mFadeInDelayForOffendersMillis, mUsageToFadeWrapperMap, + mAttrToFadeWrapperMap, mFadeableUsages, mUnfadeableContentTypes, + mUnfadeablePlayerTypes, mUnfadeableUids, mUnfadeableAudioAttributes); + } + + private void setFlag(long flag) { + mBuilderFieldsSet |= flag; + } + + private boolean checkNotSet(long flag) { + return (mBuilderFieldsSet & flag) == 0; + } + + private FadeVolumeShaperConfigsWrapper getFadeVolShaperConfigWrapperForUsage(int usage) { + if (!mUsageToFadeWrapperMap.contains(usage)) { + mUsageToFadeWrapperMap.put(usage, new FadeVolumeShaperConfigsWrapper()); + } + return mUsageToFadeWrapperMap.get(usage); + } + + private FadeVolumeShaperConfigsWrapper getFadeVolShaperConfigWrapperForAttr( + AudioAttributes attr) { + // if no entry, create a new one for setting/clearing + if (!mAttrToFadeWrapperMap.containsKey(attr)) { + mAttrToFadeWrapperMap.put(attr, new FadeVolumeShaperConfigsWrapper()); + } + return mAttrToFadeWrapperMap.get(attr); + } + + private VolumeShaper.Configuration createVolShaperConfigForDuration(long duration, + boolean isFadeIn) { + // used to reset the volume shaper config setting + if (duration == DURATION_NOT_SET) { + return null; + } + + VolumeShaper.Configuration.Builder builder = new VolumeShaper.Configuration.Builder() + .setId(VOLUME_SHAPER_SYSTEM_FADE_ID) + .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME) + .setDuration(duration); + + if (isFadeIn) { + builder.setCurve(/* times= */ new float[]{0.f, 0.50f, 1.0f}, + /* volumes= */ new float[]{0.f, 0.30f, 1.0f}); + } else { + builder.setCurve(/* times= */ new float[]{0.f, 0.25f, 1.0f}, + /* volumes= */ new float[]{1.f, 0.65f, 0.0f}); + } + + return builder.build(); + } + + private void cleanupInactiveWrapperEntries(int usage) { + FadeVolumeShaperConfigsWrapper fmcw = mUsageToFadeWrapperMap.get(usage); + // cleanup map entry if FadeVolumeShaperConfigWrapper is inactive + if (fmcw != null && fmcw.isInactive()) { + mUsageToFadeWrapperMap.remove(usage); + } + } + + private void cleanupInactiveWrapperEntries(AudioAttributes attr) { + FadeVolumeShaperConfigsWrapper fmcw = mAttrToFadeWrapperMap.get(attr); + // cleanup map entry if FadeVolumeShaperConfigWrapper is inactive + if (fmcw != null && fmcw.isInactive()) { + mAttrToFadeWrapperMap.remove(attr); + } + } + + private void setVolShaperConfigsForUsages(IntArray usages) { + // set default volume shaper configs for fadeable usages + for (int index = 0; index < usages.size(); index++) { + setMissingVolShaperConfigsForWrapper( + getFadeVolShaperConfigWrapperForUsage(usages.get(index))); + } + } + + private void setMissingVolShaperConfigsForWrapper(FadeVolumeShaperConfigsWrapper wrapper) { + if (!wrapper.isFadeOutConfigActive()) { + wrapper.setFadeOutVolShaperConfig(createVolShaperConfigForDuration( + mFadeOutDurationMillis, /* isFadeIn= */ false)); + } + if (!wrapper.isFadeInConfigActive()) { + wrapper.setFadeInVolShaperConfig(createVolShaperConfigForDuration( + mFadeInDurationMillis, /* isFadeIn= */ true)); + } + } + + private void validateFadeState(int state) { + switch(state) { + case FADE_STATE_DISABLED: + case FADE_STATE_ENABLED_DEFAULT: + case FADE_STATE_ENABLED_AUTO: + break; + default: + throw new IllegalArgumentException("Unknown fade state: " + state); + } + } + + private void validateUsages(List<Integer> usages) { + for (int index = 0; index < usages.size(); index++) { + validateUsage(usages.get(index)); + } + } + + private void validateContentTypes(List<Integer> contentTypes) { + for (int index = 0; index < contentTypes.size(); index++) { + validateContentType(contentTypes.get(index)); + } + } + + private void validateContentType(int contentType) { + Preconditions.checkArgument(AudioAttributes.isSdkContentType(contentType), + "Invalid content type: ", contentType); + } + + private void validateFadeConfigurations() { + validateFadeableUsages(); + validateFadeVolumeShaperConfigsWrappers(); + validateUnfadeableAudioAttributes(); + } + + /** Ensure fadeable usage list meets config requirements */ + private void validateFadeableUsages() { + // ensure at least one fadeable usage + Preconditions.checkArgumentPositive(mFadeableUsages.size(), + "Fadeable usage list cannot be empty when state set to enabled"); + // ensure all fadeable usages have volume shaper configs - both fade in and out + for (int index = 0; index < mFadeableUsages.size(); index++) { + setMissingVolShaperConfigsForWrapper( + getFadeVolShaperConfigWrapperForUsage(mFadeableUsages.get(index))); + } + } + + /** Ensure Fade volume shaper config wrappers meet requirements */ + private void validateFadeVolumeShaperConfigsWrappers() { + // ensure both fade in & out volume shaper configs are defined for all wrappers + // for usages - + for (int index = 0; index < mUsageToFadeWrapperMap.size(); index++) { + setMissingVolShaperConfigsForWrapper( + getFadeVolShaperConfigWrapperForUsage(mUsageToFadeWrapperMap.keyAt(index))); + } + + // for additional audio attributes - + for (int index = 0; index < mAttrToFadeWrapperMap.size(); index++) { + setMissingVolShaperConfigsForWrapper( + getFadeVolShaperConfigWrapperForAttr(mAttrToFadeWrapperMap.keyAt(index))); + } + } + + /** Ensure Unfadeable attributes meet configuration requirements */ + private void validateUnfadeableAudioAttributes() { + // ensure no generic AudioAttributes in unfadeable list with matching usage in fadeable + // list. failure results in an undefined behavior as the audio attributes + // shall be both fadeable (because of the usage) and unfadeable at the same time. + for (int index = 0; index < mUnfadeableAudioAttributes.size(); index++) { + AudioAttributes targetAttr = mUnfadeableAudioAttributes.get(index); + int usage = targetAttr.getSystemUsage(); + boolean isFadeableUsage = mFadeableUsages.contains(usage); + // cannot have a generic audio attribute that also is a fadeable usage + Preconditions.checkArgument( + !isFadeableUsage || (isFadeableUsage && !isGeneric(targetAttr)), + "Unfadeable audio attributes cannot be generic of the fadeable usage"); + } + } + + private static boolean isGeneric(AudioAttributes attr) { + return (attr.getContentType() == AudioAttributes.CONTENT_TYPE_UNKNOWN + && attr.getFlags() == 0x0 + && attr.getBundle() == null + && attr.getTags().isEmpty()); + } + } + + private static final class FadeVolumeShaperConfigsWrapper implements Parcelable { + // null volume shaper config refers to either init state or if its cleared/reset + private @Nullable VolumeShaper.Configuration mFadeOutVolShaperConfig; + private @Nullable VolumeShaper.Configuration mFadeInVolShaperConfig; + + FadeVolumeShaperConfigsWrapper() {} + + public void setFadeOutVolShaperConfig(@Nullable VolumeShaper.Configuration fadeOutConfig) { + mFadeOutVolShaperConfig = fadeOutConfig; + } + + public void setFadeInVolShaperConfig(@Nullable VolumeShaper.Configuration fadeInConfig) { + mFadeInVolShaperConfig = fadeInConfig; + } + + /** + * Query fade out volume shaper config + * + * @return configured fade out volume shaper config or {@code null} when initialized/reset + */ + @Nullable + public VolumeShaper.Configuration getFadeOutVolShaperConfig() { + return mFadeOutVolShaperConfig; + } + + /** + * Query fade in volume shaper config + * + * @return configured fade in volume shaper config or {@code null} when initialized/reset + */ + @Nullable + public VolumeShaper.Configuration getFadeInVolShaperConfig() { + return mFadeInVolShaperConfig; + } + + /** + * Wrapper is inactive if both fade out and in configs are cleared. + * + * @return {@code true} if configs are cleared. {@code false} if either of the configs is + * set + */ + public boolean isInactive() { + return !isFadeOutConfigActive() && !isFadeInConfigActive(); + } + + boolean isFadeOutConfigActive() { + return mFadeOutVolShaperConfig != null; + } + + boolean isFadeInConfigActive() { + return mFadeInVolShaperConfig != null; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof FadeVolumeShaperConfigsWrapper)) { + return false; + } + + FadeVolumeShaperConfigsWrapper rhs = (FadeVolumeShaperConfigsWrapper) o; + + if (mFadeInVolShaperConfig == null && rhs.mFadeInVolShaperConfig == null + && mFadeOutVolShaperConfig == null && rhs.mFadeOutVolShaperConfig == null) { + return true; + } + + boolean isEqual; + if (mFadeOutVolShaperConfig != null) { + isEqual = mFadeOutVolShaperConfig.equals(rhs.mFadeOutVolShaperConfig); + } else if (rhs.mFadeOutVolShaperConfig != null) { + return false; + } else { + isEqual = true; + } + + if (mFadeInVolShaperConfig != null) { + isEqual = isEqual && mFadeInVolShaperConfig.equals(rhs.mFadeInVolShaperConfig); + } else if (rhs.mFadeInVolShaperConfig != null) { + return false; + } + + return isEqual; + } + + @Override + public int hashCode() { + return Objects.hash(mFadeOutVolShaperConfig, mFadeInVolShaperConfig); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + mFadeOutVolShaperConfig.writeToParcel(dest, flags); + mFadeInVolShaperConfig.writeToParcel(dest, flags); + } + + /** + * Creates fade volume shaper config wrapper from parcel + * + * @hide + */ + @VisibleForTesting() + FadeVolumeShaperConfigsWrapper(Parcel in) { + mFadeOutVolShaperConfig = VolumeShaper.Configuration.CREATOR.createFromParcel(in); + mFadeInVolShaperConfig = VolumeShaper.Configuration.CREATOR.createFromParcel(in); + } + + @NonNull + public static final Creator<FadeVolumeShaperConfigsWrapper> CREATOR = new Creator<>() { + @Override + @NonNull + public FadeVolumeShaperConfigsWrapper createFromParcel(@NonNull Parcel in) { + return new FadeVolumeShaperConfigsWrapper(in); + } + + @Override + @NonNull + public FadeVolumeShaperConfigsWrapper[] newArray(int size) { + return new FadeVolumeShaperConfigsWrapper[size]; + } + }; + } +} + diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java index 0a0a6263686a..ab7c27f70e05 100644 --- a/media/java/android/media/MediaCas.java +++ b/media/java/android/media/MediaCas.java @@ -272,7 +272,7 @@ public final class MediaCas implements AutoCloseable { Log.d(TAG, "Trying to get AIDL service"); IMediaCasService serviceAidl = IMediaCasService.Stub.asInterface( - ServiceManager.getService( + ServiceManager.waitForDeclaredService( IMediaCasService.DESCRIPTOR + "/default")); if (serviceAidl != null) { return serviceAidl; diff --git a/media/java/android/media/flags/fade_manager_configuration.aconfig b/media/java/android/media/flags/fade_manager_configuration.aconfig new file mode 100644 index 000000000000..100e2235a7a8 --- /dev/null +++ b/media/java/android/media/flags/fade_manager_configuration.aconfig @@ -0,0 +1,8 @@ +package: "com.android.media.flags" + +flag { + namespace: "media_solutions" + name: "enable_fade_manager_configuration" + description: "Enable Fade Manager Configuration support to determine fade properties" + bug: "307354764" +}
\ No newline at end of file diff --git a/media/tests/AudioPolicyTest/Android.bp b/media/tests/AudioPolicyTest/Android.bp index 4624dfe70756..3dc2a0a9fd7c 100644 --- a/media/tests/AudioPolicyTest/Android.bp +++ b/media/tests/AudioPolicyTest/Android.bp @@ -17,6 +17,7 @@ android_test { "guava-android-testlib", "hamcrest-library", "platform-test-annotations", + "truth", ], platform_apis: true, certificate: "platform", diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java index 94df40da16c1..e9a0d3eceba3 100644 --- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java @@ -229,7 +229,7 @@ public class AudioManagerTest { @Test public void testSetGetVolumePerAttributes() { - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.getSdkUsages()) { if (usage == AudioAttributes.USAGE_UNKNOWN) { continue; } diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java index 266faae489dd..18e8608d3b4d 100644 --- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java @@ -169,7 +169,7 @@ public class AudioProductStrategyTest { assertNotNull(audioProductStrategies); assertTrue(audioProductStrategies.size() > 0); - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.getSdkUsages()) { AudioAttributes aaForUsage = new AudioAttributes.Builder().setUsage(usage).build(); int streamTypeFromUsage = diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/FadeManagerConfigurationUnitTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/FadeManagerConfigurationUnitTest.java new file mode 100644 index 000000000000..fb6bd489d5d0 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/FadeManagerConfigurationUnitTest.java @@ -0,0 +1,795 @@ +/* + * 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.audiopolicytest; + +import static com.android.media.flags.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION; + +import static org.junit.Assert.assertThrows; + +import android.media.AudioAttributes; +import android.media.AudioPlaybackConfiguration; +import android.media.FadeManagerConfiguration; +import android.media.VolumeShaper; +import android.os.Parcel; +import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.google.common.truth.Expect; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Presubmit +@RunWith(AndroidJUnit4.class) +@RequiresFlagsEnabled(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION) +public final class FadeManagerConfigurationUnitTest { + private static final long DEFAULT_FADE_OUT_DURATION_MS = 2_000; + private static final long DEFAULT_FADE_IN_DURATION_MS = 1_000; + private static final long TEST_FADE_OUT_DURATION_MS = 1_500; + private static final long TEST_FADE_IN_DURATION_MS = 750; + private static final int TEST_INVALID_USAGE = -10; + private static final int TEST_INVALID_CONTENT_TYPE = 100; + private static final int TEST_INVALID_FADE_STATE = 100; + private static final long TEST_INVALID_DURATION = -10; + private static final int TEST_UID_1 = 1010001; + private static final int TEST_UID_2 = 1000; + private static final int TEST_PARCEL_FLAGS = 0; + private static final AudioAttributes TEST_MEDIA_AUDIO_ATTRIBUTE = + createAudioAttributesForUsage(AudioAttributes.USAGE_MEDIA); + private static final AudioAttributes TEST_GAME_AUDIO_ATTRIBUTE = + createAudioAttributesForUsage(AudioAttributes.USAGE_GAME); + private static final AudioAttributes TEST_NAVIGATION_AUDIO_ATTRIBUTE = + new AudioAttributes.Builder().setUsage( + AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build(); + private static final AudioAttributes TEST_ASSISTANT_AUDIO_ATTRIBUTE = + new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ASSISTANT) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build(); + private static final List<Integer> TEST_FADEABLE_USAGES = Arrays.asList( + AudioAttributes.USAGE_MEDIA, + AudioAttributes.USAGE_GAME + ); + private static final List<Integer> TEST_UNFADEABLE_CONTENT_TYPES = Arrays.asList( + AudioAttributes.CONTENT_TYPE_SPEECH + ); + + private static final List<Integer> TEST_UNFADEABLE_PLAYER_TYPES = Arrays.asList( + AudioPlaybackConfiguration.PLAYER_TYPE_AAUDIO, + AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL + ); + private static final VolumeShaper.Configuration TEST_DEFAULT_FADE_OUT_VOLUME_SHAPER_CONFIG = + new VolumeShaper.Configuration.Builder() + .setId(FadeManagerConfiguration.VOLUME_SHAPER_SYSTEM_FADE_ID) + .setCurve(/* times= */new float[]{0.f, 0.25f, 1.0f}, + /* volumes= */new float[]{1.f, 0.65f, 0.0f}) + .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME) + .setDuration(DEFAULT_FADE_OUT_DURATION_MS) + .build(); + private static final VolumeShaper.Configuration TEST_DEFAULT_FADE_IN_VOLUME_SHAPER_CONFIG = + new VolumeShaper.Configuration.Builder() + .setId(FadeManagerConfiguration.VOLUME_SHAPER_SYSTEM_FADE_ID) + .setCurve(/* times= */new float[]{0.f, 0.50f, 1.0f}, + /* volumes= */new float[]{0.f, 0.30f, 1.0f}) + .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME) + .setDuration(DEFAULT_FADE_IN_DURATION_MS) + .build(); + private static final VolumeShaper.Configuration TEST_FADE_OUT_VOLUME_SHAPER_CONFIG = + new VolumeShaper.Configuration.Builder() + .setId(FadeManagerConfiguration.VOLUME_SHAPER_SYSTEM_FADE_ID) + .setCurve(/* times= */new float[]{0.f, 0.25f, 1.0f}, + /* volumes= */new float[]{1.f, 0.65f, 0.0f}) + .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME) + .setDuration(TEST_FADE_OUT_DURATION_MS) + .build(); + private static final VolumeShaper.Configuration TEST_FADE_IN_VOLUME_SHAPER_CONFIG = + new VolumeShaper.Configuration.Builder() + .setId(FadeManagerConfiguration.VOLUME_SHAPER_SYSTEM_FADE_ID) + .setCurve(/* times= */new float[]{0.f, 0.50f, 1.0f}, + /* volumes= */new float[]{0.f, 0.30f, 1.0f}) + .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME) + .setDuration(TEST_FADE_IN_DURATION_MS) + .build(); + + private FadeManagerConfiguration mFmc; + + @Rule + public final Expect expect = Expect.create(); + + @Before + public void setUp() { + mFmc = new FadeManagerConfiguration.Builder().build(); + } + + + @Test + public void build() { + expect.withMessage("Fade state for default builder") + .that(mFmc.getFadeState()) + .isEqualTo(FadeManagerConfiguration.FADE_STATE_ENABLED_DEFAULT); + expect.withMessage("Fadeable usages for default builder") + .that(mFmc.getFadeableUsages()) + .containsExactlyElementsIn(TEST_FADEABLE_USAGES); + expect.withMessage("Unfadeable content types usages for default builder") + .that(mFmc.getUnfadeableContentTypes()) + .containsExactlyElementsIn(TEST_UNFADEABLE_CONTENT_TYPES); + expect.withMessage("Unfadeable player types for default builder") + .that(mFmc.getUnfadeablePlayerTypes()) + .containsExactlyElementsIn(TEST_UNFADEABLE_PLAYER_TYPES); + expect.withMessage("Unfadeable uids for default builder") + .that(mFmc.getUnfadeableUids()).isEmpty(); + expect.withMessage("Unfadeable audio attributes for default builder") + .that(mFmc.getUnfadeableAudioAttributes()).isEmpty(); + expect.withMessage("Fade out volume shaper config for media usage") + .that(mFmc.getFadeOutVolumeShaperConfigForUsage(AudioAttributes.USAGE_MEDIA)) + .isEqualTo(TEST_DEFAULT_FADE_OUT_VOLUME_SHAPER_CONFIG); + expect.withMessage("Fade out duration for game usage") + .that(mFmc.getFadeOutDurationForUsage(AudioAttributes.USAGE_GAME)) + .isEqualTo(DEFAULT_FADE_OUT_DURATION_MS); + expect.withMessage("Fade in volume shaper config for media uasge") + .that(mFmc.getFadeInVolumeShaperConfigForUsage(AudioAttributes.USAGE_MEDIA)) + .isEqualTo(TEST_DEFAULT_FADE_IN_VOLUME_SHAPER_CONFIG); + expect.withMessage("Fade in duration for game audio usage") + .that(mFmc.getFadeInDurationForUsage(AudioAttributes.USAGE_GAME)) + .isEqualTo(DEFAULT_FADE_IN_DURATION_MS); + } + + @Test + public void build_withFadeDurations_succeeds() { + FadeManagerConfiguration fmc = new FadeManagerConfiguration + .Builder(TEST_FADE_OUT_DURATION_MS, TEST_FADE_IN_DURATION_MS).build(); + + expect.withMessage("Fade state for builder with duration").that(fmc.getFadeState()) + .isEqualTo(FadeManagerConfiguration.FADE_STATE_ENABLED_DEFAULT); + expect.withMessage("Fadeable usages for builder with duration") + .that(fmc.getFadeableUsages()) + .containsExactlyElementsIn(TEST_FADEABLE_USAGES); + expect.withMessage("Unfadeable content types usages for builder with duration") + .that(fmc.getUnfadeableContentTypes()) + .containsExactlyElementsIn(TEST_UNFADEABLE_CONTENT_TYPES); + expect.withMessage("Unfadeable player types for builder with duration") + .that(fmc.getUnfadeablePlayerTypes()) + .containsExactlyElementsIn(TEST_UNFADEABLE_PLAYER_TYPES); + expect.withMessage("Unfadeable uids for builder with duration") + .that(fmc.getUnfadeableUids()).isEmpty(); + expect.withMessage("Unfadeable audio attributes for builder with duration") + .that(fmc.getUnfadeableAudioAttributes()).isEmpty(); + expect.withMessage("Fade out volume shaper config for media usage") + .that(fmc.getFadeOutVolumeShaperConfigForUsage(AudioAttributes.USAGE_MEDIA)) + .isEqualTo(TEST_FADE_OUT_VOLUME_SHAPER_CONFIG); + expect.withMessage("Fade out duration for game usage") + .that(fmc.getFadeOutDurationForUsage(AudioAttributes.USAGE_GAME)) + .isEqualTo(TEST_FADE_OUT_DURATION_MS); + expect.withMessage("Fade in volume shaper config for media audio attributes") + .that(fmc.getFadeInVolumeShaperConfigForUsage(AudioAttributes.USAGE_MEDIA)) + .isEqualTo(TEST_FADE_IN_VOLUME_SHAPER_CONFIG); + expect.withMessage("Fade in duration for game audio attributes") + .that(fmc.getFadeInDurationForUsage(AudioAttributes.USAGE_GAME)) + .isEqualTo(TEST_FADE_IN_DURATION_MS); + + } + + @Test + public void build_withFadeManagerConfiguration_succeeds() { + FadeManagerConfiguration fmcObj = new FadeManagerConfiguration + .Builder(TEST_FADE_OUT_DURATION_MS, TEST_FADE_IN_DURATION_MS).build(); + + FadeManagerConfiguration fmc = new FadeManagerConfiguration + .Builder(fmcObj).build(); + + expect.withMessage("Fade state for copy builder").that(fmc.getFadeState()) + .isEqualTo(fmcObj.getFadeState()); + expect.withMessage("Fadeable usages for copy builder") + .that(fmc.getFadeableUsages()) + .containsExactlyElementsIn(fmcObj.getFadeableUsages()); + expect.withMessage("Unfadeable content types usages for copy builder") + .that(fmc.getUnfadeableContentTypes()) + .containsExactlyElementsIn(fmcObj.getUnfadeableContentTypes()); + expect.withMessage("Unfadeable player types for copy builder") + .that(fmc.getUnfadeablePlayerTypes()) + .containsExactlyElementsIn(fmcObj.getUnfadeablePlayerTypes()); + expect.withMessage("Unfadeable uids for copy builder") + .that(fmc.getUnfadeableUids()).isEqualTo(fmcObj.getUnfadeableUids()); + expect.withMessage("Unfadeable audio attributes for copy builder") + .that(fmc.getUnfadeableAudioAttributes()) + .isEqualTo(fmcObj.getUnfadeableAudioAttributes()); + expect.withMessage("Fade out volume shaper config for media usage") + .that(fmc.getFadeOutVolumeShaperConfigForUsage(AudioAttributes.USAGE_MEDIA)) + .isEqualTo(fmcObj.getFadeOutVolumeShaperConfigForUsage( + AudioAttributes.USAGE_MEDIA)); + expect.withMessage("Fade out volume shaper config for game usage") + .that(fmc.getFadeOutVolumeShaperConfigForUsage(AudioAttributes.USAGE_GAME)) + .isEqualTo(fmcObj.getFadeOutVolumeShaperConfigForUsage( + AudioAttributes.USAGE_GAME)); + expect.withMessage("Fade in volume shaper config for media usage") + .that(fmc.getFadeInVolumeShaperConfigForUsage(AudioAttributes.USAGE_MEDIA)) + .isEqualTo(fmcObj.getFadeInVolumeShaperConfigForUsage( + AudioAttributes.USAGE_MEDIA)); + expect.withMessage("Fade in volume shaper config for game usage") + .that(fmc.getFadeInVolumeShaperConfigForUsage(AudioAttributes.USAGE_GAME)) + .isEqualTo(fmcObj.getFadeInVolumeShaperConfigForUsage( + AudioAttributes.USAGE_GAME)); + expect.withMessage("Fade out volume shaper config for media audio attributes") + .that(fmc.getFadeOutVolumeShaperConfigForAudioAttributes( + TEST_MEDIA_AUDIO_ATTRIBUTE)) + .isEqualTo(fmcObj.getFadeOutVolumeShaperConfigForAudioAttributes( + TEST_MEDIA_AUDIO_ATTRIBUTE)); + expect.withMessage("Fade out duration for game audio attributes") + .that(fmc.getFadeOutDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE)) + .isEqualTo(fmcObj.getFadeOutDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE)); + expect.withMessage("Fade in volume shaper config for media audio attributes") + .that(fmc.getFadeInVolumeShaperConfigForAudioAttributes(TEST_MEDIA_AUDIO_ATTRIBUTE)) + .isEqualTo(fmcObj.getFadeInVolumeShaperConfigForAudioAttributes( + TEST_MEDIA_AUDIO_ATTRIBUTE)); + expect.withMessage("Fade in duration for game audio attributes") + .that(fmc.getFadeInDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE)) + .isEqualTo(fmcObj.getFadeInDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE)); + } + + @Test + public void testSetFadeState_toDisable() { + final int fadeState = FadeManagerConfiguration.FADE_STATE_DISABLED; + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setFadeState(fadeState).build(); + + expect.withMessage("Fade state when disabled").that(fmc.getFadeState()) + .isEqualTo(fadeState); + } + + @Test + public void testSetFadeState_toEnableAuto() { + final int fadeStateAuto = FadeManagerConfiguration.FADE_STATE_ENABLED_AUTO; + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setFadeState(fadeStateAuto).build(); + + expect.withMessage("Fade state when enabled for audio").that(fmc.getFadeState()) + .isEqualTo(fadeStateAuto); + } + + @Test + public void testSetFadeState_toInvalid_fails() { + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + new FadeManagerConfiguration.Builder() + .setFadeState(TEST_INVALID_FADE_STATE).build() + ); + + expect.withMessage("Invalid fade state exception").that(thrown) + .hasMessageThat().contains("Unknown fade state"); + } + + @Test + public void testSetFadeVolShaperConfig() { + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setFadeOutVolumeShaperConfigForAudioAttributes(TEST_ASSISTANT_AUDIO_ATTRIBUTE, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(TEST_ASSISTANT_AUDIO_ATTRIBUTE, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG).build(); + + expect.withMessage("Fade out volume shaper config set for assistant audio attributes") + .that(fmc.getFadeOutVolumeShaperConfigForAudioAttributes( + TEST_ASSISTANT_AUDIO_ATTRIBUTE)) + .isEqualTo(TEST_FADE_OUT_VOLUME_SHAPER_CONFIG); + expect.withMessage("Fade in volume shaper config set for assistant audio attributes") + .that(fmc.getFadeInVolumeShaperConfigForAudioAttributes( + TEST_ASSISTANT_AUDIO_ATTRIBUTE)) + .isEqualTo(TEST_FADE_IN_VOLUME_SHAPER_CONFIG); + } + + @Test + public void testSetFadeOutVolShaperConfig_withNullAudioAttributes_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder() + .setFadeOutVolumeShaperConfigForAudioAttributes(/* audioAttributes= */ null, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG).build() + ); + + expect.withMessage("Null audio attributes for fade out exception") + .that(thrown).hasMessageThat().contains("cannot be null"); + } + + @Test + public void testSetFadeVolShaperConfig_withNullVolumeShaper_getsNull() { + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder(mFmc) + .setFadeOutVolumeShaperConfigForAudioAttributes(TEST_MEDIA_AUDIO_ATTRIBUTE, + /* VolumeShaper.Configuration= */ null) + .setFadeInVolumeShaperConfigForAudioAttributes(TEST_MEDIA_AUDIO_ATTRIBUTE, + /* VolumeShaper.Configuration= */ null) + .clearFadeableUsage(AudioAttributes.USAGE_MEDIA).build(); + + expect.withMessage("Fade out volume shaper config set with null value") + .that(fmc.getFadeOutVolumeShaperConfigForAudioAttributes( + TEST_MEDIA_AUDIO_ATTRIBUTE)).isNull(); + } + + @Test + public void testSetFadeInVolShaperConfig_withNullAudioAttributes_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder() + .setFadeInVolumeShaperConfigForAudioAttributes(/* audioAttributes= */ null, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG).build() + ); + + expect.withMessage("Null audio attributes for fade in exception") + .that(thrown).hasMessageThat().contains("cannot be null"); + } + + @Test + public void testSetFadeDuration() { + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setFadeOutDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE, + TEST_FADE_OUT_DURATION_MS) + .setFadeInDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE, + TEST_FADE_IN_DURATION_MS).build(); + + expect.withMessage("Fade out duration set for audio attributes") + .that(fmc.getFadeOutDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE)) + .isEqualTo(TEST_FADE_OUT_DURATION_MS); + expect.withMessage("Fade in duration set for audio attributes") + .that(fmc.getFadeInDurationForAudioAttributes(TEST_GAME_AUDIO_ATTRIBUTE)) + .isEqualTo(TEST_FADE_IN_DURATION_MS); + } + + @Test + public void testSetFadeOutDuration_withNullAudioAttributes_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder().setFadeOutDurationForAudioAttributes( + /* audioAttributes= */ null, TEST_FADE_OUT_DURATION_MS).build() + ); + + expect.withMessage("Null audio attributes for fade out duration exception").that(thrown) + .hasMessageThat().contains("cannot be null"); + } + + @Test + public void testSetFadeOutDuration_withInvalidDuration_fails() { + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + new FadeManagerConfiguration.Builder().setFadeOutDurationForAudioAttributes( + TEST_NAVIGATION_AUDIO_ATTRIBUTE, TEST_INVALID_DURATION).build() + ); + + expect.withMessage("Invalid duration for fade out exception").that(thrown) + .hasMessageThat().contains("not positive"); + } + + @Test + public void testSetFadeInDuration_withNullAudioAttributes_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder().setFadeInDurationForAudioAttributes( + /* audioAttributes= */ null, TEST_FADE_IN_DURATION_MS).build() + ); + + expect.withMessage("Null audio attributes for fade in duration exception").that(thrown) + .hasMessageThat().contains("cannot be null"); + } + + @Test + public void testSetFadeInDuration_withInvalidDuration_fails() { + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + new FadeManagerConfiguration.Builder().setFadeInDurationForAudioAttributes( + TEST_NAVIGATION_AUDIO_ATTRIBUTE, TEST_INVALID_DURATION).build() + ); + + expect.withMessage("Invalid duration for fade in exception").that(thrown) + .hasMessageThat().contains("not positive"); + } + + @Test + public void testSetFadeableUsages() { + final List<Integer> fadeableUsages = List.of( + AudioAttributes.USAGE_VOICE_COMMUNICATION, + AudioAttributes.USAGE_ALARM, + AudioAttributes.USAGE_ASSISTANT + ); + AudioAttributes aaForVoiceComm = createAudioAttributesForUsage( + AudioAttributes.USAGE_VOICE_COMMUNICATION); + AudioAttributes aaForAlarm = createAudioAttributesForUsage(AudioAttributes.USAGE_ALARM); + AudioAttributes aaForAssistant = createAudioAttributesForUsage( + AudioAttributes.USAGE_ASSISTANT); + + + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setFadeableUsages(fadeableUsages) + .setFadeOutVolumeShaperConfigForAudioAttributes(aaForVoiceComm, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(aaForVoiceComm, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG) + .setFadeOutVolumeShaperConfigForAudioAttributes(aaForAlarm, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(aaForAlarm, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG) + .setFadeOutVolumeShaperConfigForAudioAttributes(aaForAssistant, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(aaForAssistant, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG).build(); + + expect.withMessage("Fadeable usages") + .that(fmc.getFadeableUsages()).isEqualTo(fadeableUsages); + } + + @Test + public void testSetFadeableUsages_withInvalidUsage_fails() { + final List<Integer> fadeableUsages = List.of( + AudioAttributes.USAGE_VOICE_COMMUNICATION, + TEST_INVALID_USAGE, + AudioAttributes.USAGE_ANNOUNCEMENT + ); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + new FadeManagerConfiguration.Builder().setFadeableUsages(fadeableUsages).build() + ); + + expect.withMessage("Fadeable usages set to invalid usage").that(thrown).hasMessageThat() + .contains("Invalid usage"); + } + + @Test + public void testSetFadeableUsages_withNullUsages_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder().setFadeableUsages(/* usages= */ null) + .build() + ); + + expect.withMessage("Fadeable usages set to null list").that(thrown).hasMessageThat() + .contains("cannot be null"); + } + + @Test + public void testSetFadeableUsages_withEmptyListClears_addsNewUsage() { + final List<Integer> fadeableUsages = List.of( + AudioAttributes.USAGE_VOICE_COMMUNICATION, + AudioAttributes.USAGE_ALARM, + AudioAttributes.USAGE_ASSISTANT + ); + FadeManagerConfiguration.Builder fmcBuilder = new FadeManagerConfiguration.Builder() + .setFadeableUsages(fadeableUsages); + + fmcBuilder.setFadeableUsages(List.of()); + + FadeManagerConfiguration fmc = fmcBuilder + .addFadeableUsage(AudioAttributes.USAGE_MEDIA) + .setFadeOutVolumeShaperConfigForAudioAttributes(TEST_MEDIA_AUDIO_ATTRIBUTE, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(TEST_MEDIA_AUDIO_ATTRIBUTE, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG).build(); + expect.withMessage("Fadeable usages set to empty list") + .that(fmc.getFadeableUsages()).isEqualTo(List.of(AudioAttributes.USAGE_MEDIA)); + } + + + @Test + public void testAddFadeableUsage() { + final int usageToAdd = AudioAttributes.USAGE_ASSISTANT; + AudioAttributes aaToAdd = createAudioAttributesForUsage(usageToAdd); + List<Integer> updatedUsages = new ArrayList<>(mFmc.getFadeableUsages()); + updatedUsages.add(usageToAdd); + + FadeManagerConfiguration updatedFmc = new FadeManagerConfiguration + .Builder(mFmc).addFadeableUsage(usageToAdd) + .setFadeOutVolumeShaperConfigForAudioAttributes(aaToAdd, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(aaToAdd, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG) + .build(); + + expect.withMessage("Fadeable usages").that(updatedFmc.getFadeableUsages()) + .containsExactlyElementsIn(updatedUsages); + } + + @Test + public void testAddFadeableUsage_withoutSetFadeableUsages() { + final int newUsage = AudioAttributes.USAGE_ASSISTANT; + AudioAttributes aaToAdd = createAudioAttributesForUsage(newUsage); + + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .addFadeableUsage(newUsage) + .setFadeOutVolumeShaperConfigForAudioAttributes(aaToAdd, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(aaToAdd, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG) + .build(); + + expect.withMessage("Fadeable usages").that(fmc.getFadeableUsages()) + .containsExactlyElementsIn(List.of(newUsage)); + } + + @Test + public void testAddFadeableUsage_withInvalidUsage_fails() { + List<Integer> setUsages = Arrays.asList( + AudioAttributes.USAGE_VOICE_COMMUNICATION, + AudioAttributes.USAGE_ASSISTANT + ); + AudioAttributes aaForVoiceComm = createAudioAttributesForUsage( + AudioAttributes.USAGE_VOICE_COMMUNICATION); + AudioAttributes aaForAssistant = createAudioAttributesForUsage( + AudioAttributes.USAGE_ASSISTANT); + FadeManagerConfiguration.Builder fmcBuilder = new FadeManagerConfiguration.Builder() + .setFadeableUsages(setUsages) + .setFadeOutVolumeShaperConfigForAudioAttributes(aaForVoiceComm, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(aaForVoiceComm, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG) + .setFadeOutVolumeShaperConfigForAudioAttributes(aaForAssistant, + TEST_FADE_OUT_VOLUME_SHAPER_CONFIG) + .setFadeInVolumeShaperConfigForAudioAttributes(aaForAssistant, + TEST_FADE_IN_VOLUME_SHAPER_CONFIG); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + fmcBuilder.addFadeableUsage(TEST_INVALID_USAGE) + ); + + FadeManagerConfiguration fmc = fmcBuilder.build(); + expect.withMessage("Fadeable usages ").that(thrown).hasMessageThat() + .contains("Invalid usage"); + expect.withMessage("Fadeable usages").that(fmc.getFadeableUsages()) + .containsExactlyElementsIn(setUsages); + } + + @Test + public void testClearFadeableUsage() { + final int usageToClear = AudioAttributes.USAGE_MEDIA; + List<Integer> updatedUsages = new ArrayList<>(mFmc.getFadeableUsages()); + updatedUsages.remove((Integer) usageToClear); + + FadeManagerConfiguration updatedFmc = new FadeManagerConfiguration + .Builder(mFmc).clearFadeableUsage(usageToClear).build(); + + expect.withMessage("Clear fadeable usage").that(updatedFmc.getFadeableUsages()) + .containsExactlyElementsIn(updatedUsages); + } + + @Test + public void testClearFadeableUsage_withInvalidUsage_fails() { + FadeManagerConfiguration.Builder fmcBuilder = new FadeManagerConfiguration.Builder(mFmc); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + fmcBuilder.clearFadeableUsage(TEST_INVALID_USAGE) + ); + + FadeManagerConfiguration fmc = fmcBuilder.build(); + expect.withMessage("Clear invalid usage").that(thrown).hasMessageThat() + .contains("Invalid usage"); + expect.withMessage("Fadeable usages").that(fmc.getFadeableUsages()) + .containsExactlyElementsIn(mFmc.getFadeableUsages()); + } + + @Test + public void testSetUnfadeableContentTypes() { + final List<Integer> unfadeableContentTypes = List.of( + AudioAttributes.CONTENT_TYPE_MOVIE, + AudioAttributes.CONTENT_TYPE_SONIFICATION + ); + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setUnfadeableContentTypes(unfadeableContentTypes).build(); + + expect.withMessage("Unfadeable content types set") + .that(fmc.getUnfadeableContentTypes()).isEqualTo(unfadeableContentTypes); + } + + @Test + public void testSetUnfadeableContentTypes_withInvalidContentType_fails() { + final List<Integer> invalidUnfadeableContentTypes = List.of( + AudioAttributes.CONTENT_TYPE_MOVIE, + TEST_INVALID_CONTENT_TYPE, + AudioAttributes.CONTENT_TYPE_SONIFICATION + ); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + new FadeManagerConfiguration.Builder() + .setUnfadeableContentTypes(invalidUnfadeableContentTypes).build() + ); + + expect.withMessage("Invalid content type set exception").that(thrown).hasMessageThat() + .contains("Invalid content type"); + } + + @Test + public void testSetUnfadeableContentTypes_withNullContentType_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder() + .setUnfadeableContentTypes(/* contentType= */ null).build() + ); + + expect.withMessage("Null content type set exception").that(thrown).hasMessageThat() + .contains("cannot be null"); + } + + @Test + public void testSetUnfadeableContentTypes_withEmptyList_clearsExistingList() { + final List<Integer> unfadeableContentTypes = List.of( + AudioAttributes.CONTENT_TYPE_MOVIE, + AudioAttributes.CONTENT_TYPE_SONIFICATION + ); + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setUnfadeableContentTypes(unfadeableContentTypes).build(); + + FadeManagerConfiguration fmcWithEmptyLsit = new FadeManagerConfiguration.Builder(fmc) + .setUnfadeableContentTypes(List.of()).build(); + + expect.withMessage("Unfadeable content types for empty list") + .that(fmcWithEmptyLsit.getUnfadeableContentTypes()).isEmpty(); + } + + @Test + public void testAddUnfadeableContentType() { + final int contentTypeToAdd = AudioAttributes.CONTENT_TYPE_MOVIE; + List<Integer> upatdedContentTypes = new ArrayList<>(mFmc.getUnfadeableContentTypes()); + upatdedContentTypes.add(contentTypeToAdd); + + FadeManagerConfiguration updatedFmc = new FadeManagerConfiguration + .Builder(mFmc).addUnfadeableContentType(contentTypeToAdd).build(); + + expect.withMessage("Unfadeable content types").that(updatedFmc.getUnfadeableContentTypes()) + .containsExactlyElementsIn(upatdedContentTypes); + } + + @Test + public void testAddUnfadeableContentTypes_withoutSetUnfadeableContentTypes() { + final int newContentType = AudioAttributes.CONTENT_TYPE_MOVIE; + + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .addUnfadeableContentType(newContentType).build(); + + expect.withMessage("Unfadeable content types").that(fmc.getUnfadeableContentTypes()) + .containsExactlyElementsIn(List.of(newContentType)); + } + + @Test + public void testAddunfadeableContentTypes_withInvalidContentType_fails() { + final List<Integer> unfadeableContentTypes = List.of( + AudioAttributes.CONTENT_TYPE_MOVIE, + AudioAttributes.CONTENT_TYPE_SONIFICATION + ); + FadeManagerConfiguration.Builder fmcBuilder = new FadeManagerConfiguration.Builder() + .setUnfadeableContentTypes(unfadeableContentTypes); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + fmcBuilder.addUnfadeableContentType(TEST_INVALID_CONTENT_TYPE).build() + ); + + expect.withMessage("Invalid content types exception").that(thrown).hasMessageThat() + .contains("Invalid content type"); + } + + @Test + public void testClearUnfadeableContentType() { + List<Integer> unfadeableContentTypes = new ArrayList<>(Arrays.asList( + AudioAttributes.CONTENT_TYPE_MOVIE, + AudioAttributes.CONTENT_TYPE_SONIFICATION + )); + final int contentTypeToClear = AudioAttributes.CONTENT_TYPE_MOVIE; + + FadeManagerConfiguration updatedFmc = new FadeManagerConfiguration.Builder() + .setUnfadeableContentTypes(unfadeableContentTypes) + .clearUnfadeableContentType(contentTypeToClear).build(); + + unfadeableContentTypes.remove((Integer) contentTypeToClear); + expect.withMessage("Unfadeable content types").that(updatedFmc.getUnfadeableContentTypes()) + .containsExactlyElementsIn(unfadeableContentTypes); + } + + @Test + public void testClearUnfadeableContentType_withInvalidContentType_fails() { + FadeManagerConfiguration.Builder fmcBuilder = new FadeManagerConfiguration.Builder(mFmc); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + fmcBuilder.clearUnfadeableContentType(TEST_INVALID_CONTENT_TYPE).build() + ); + + expect.withMessage("Invalid content type exception").that(thrown).hasMessageThat() + .contains("Invalid content type"); + } + + @Test + public void testSetUnfadeableUids() { + final List<Integer> unfadeableUids = List.of( + TEST_UID_1, + TEST_UID_2 + ); + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setUnfadeableUids(unfadeableUids).build(); + + expect.withMessage("Unfadeable uids set") + .that(fmc.getUnfadeableUids()).isEqualTo(unfadeableUids); + } + + @Test + public void testSetUnfadeableUids_withNullUids_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder() + .setUnfadeableUids(/* uids= */ null).build() + ); + + expect.withMessage("Null unfadeable uids").that(thrown).hasMessageThat() + .contains("cannot be null"); + } + + @Test + public void testAddUnfadeableUid() { + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .addUnfadeableUid(TEST_UID_1).build(); + + expect.withMessage("Unfadeable uids") + .that(fmc.getUnfadeableUids()).isEqualTo(List.of(TEST_UID_1)); + } + + @Test + public void testClearUnfadebaleUid() { + final List<Integer> unfadeableUids = List.of( + TEST_UID_1, + TEST_UID_2 + ); + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setUnfadeableUids(unfadeableUids).build(); + + FadeManagerConfiguration updatedFmc = new FadeManagerConfiguration.Builder(fmc) + .clearUnfadeableUid(TEST_UID_1).build(); + + expect.withMessage("Unfadeable uids").that(updatedFmc.getUnfadeableUids()) + .isEqualTo(List.of(TEST_UID_2)); + } + + @Test + public void testSetUnfadeableAudioAttributes() { + final List<AudioAttributes> unfadeableAttrs = List.of( + TEST_ASSISTANT_AUDIO_ATTRIBUTE, + TEST_NAVIGATION_AUDIO_ATTRIBUTE + ); + + FadeManagerConfiguration fmc = new FadeManagerConfiguration.Builder() + .setUnfadeableAudioAttributes(unfadeableAttrs).build(); + + expect.withMessage("Unfadeable audio attributes") + .that(fmc.getUnfadeableAudioAttributes()).isEqualTo(unfadeableAttrs); + } + + @Test + public void testSetUnfadeableAudioAttributes_withNullAttributes_fails() { + NullPointerException thrown = assertThrows(NullPointerException.class, () -> + new FadeManagerConfiguration.Builder() + .setUnfadeableAudioAttributes(/* attrs= */ null).build() + ); + + expect.withMessage("Null audio attributes exception").that(thrown).hasMessageThat() + .contains("cannot be null"); + } + + @Test + public void testWriteToParcel_andCreateFromParcel() { + Parcel parcel = Parcel.obtain(); + + mFmc.writeToParcel(parcel, TEST_PARCEL_FLAGS); + parcel.setDataPosition(/* position= */ 0); + expect.withMessage("Fade manager configuration write to and create from parcel") + .that(mFmc) + .isEqualTo(FadeManagerConfiguration.CREATOR.createFromParcel(parcel)); + } + + private static AudioAttributes createAudioAttributesForUsage(int usage) { + if (AudioAttributes.isSystemUsage(usage)) { + return new AudioAttributes.Builder().setSystemUsage(usage).build(); + } + return new AudioAttributes.Builder().setUsage(usage).build(); + } +} diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index fea6c5f95358..9f2a9ac4798d 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -336,6 +336,13 @@ LIBANDROID { APerformanceHint_closeSession; # introduced=Tiramisu APerformanceHint_setThreads; # introduced=UpsideDownCake APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream + APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream + AWorkDuration_create; # introduced=VanillaIceCream + AWorkDuration_release; # introduced=VanillaIceCream + AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream + AWorkDuration_setActualTotalDurationNanos; # introduced=VanillaIceCream + AWorkDuration_setActualCpuDurationNanos; # introduced=VanillaIceCream + AWorkDuration_setActualGpuDurationNanos; # introduced=VanillaIceCream local: *; }; diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp index c25df6e08fd0..c4c81284780e 100644 --- a/native/android/performance_hint.cpp +++ b/native/android/performance_hint.cpp @@ -18,12 +18,14 @@ #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionMode.h> +#include <android/WorkDuration.h> #include <android/os/IHintManager.h> #include <android/os/IHintSession.h> #include <android/performance_hint.h> #include <binder/Binder.h> #include <binder/IBinder.h> #include <binder/IServiceManager.h> +#include <inttypes.h> #include <performance_hint_private.h> #include <utils/SystemClock.h> @@ -75,10 +77,13 @@ public: int setThreads(const int32_t* threadIds, size_t size); int getThreadIds(int32_t* const threadIds, size_t* size); int setPreferPowerEfficiency(bool enabled); + int reportActualWorkDuration(AWorkDuration* workDuration); private: friend struct APerformanceHintManager; + int reportActualWorkDurationInternal(WorkDuration* workDuration); + sp<IHintManager> mHintManager; sp<IHintSession> mHintSession; // HAL preferred update rate @@ -92,8 +97,7 @@ private: // Last hint reported from sendHint indexed by hint value std::vector<int64_t> mLastHintSentTimestamp; // Cached samples - std::vector<int64_t> mActualDurationsNanos; - std::vector<int64_t> mTimestampsNanos; + std::vector<WorkDuration> mActualWorkDurations; }; static IHintManager* gIHintManagerForTesting = nullptr; @@ -195,8 +199,7 @@ int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNano * Most of the workload is target_duration dependent, so now clear the cached samples * as they are most likely obsolete. */ - mActualDurationsNanos.clear(); - mTimestampsNanos.clear(); + mActualWorkDurations.clear(); mFirstTargetMetTimestamp = 0; mLastTargetMetTimestamp = 0; return 0; @@ -207,43 +210,10 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__); return EINVAL; } - int64_t now = elapsedRealtimeNano(); - mActualDurationsNanos.push_back(actualDurationNanos); - mTimestampsNanos.push_back(now); - if (actualDurationNanos >= mTargetDurationNanos) { - // Reset timestamps if we are equal or over the target. - mFirstTargetMetTimestamp = 0; - } else { - // Set mFirstTargetMetTimestamp for first time meeting target. - if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp || - (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) { - mFirstTargetMetTimestamp = now; - } - /** - * Rate limit the change if the update is over mPreferredRateNanos since first - * meeting target and less than mPreferredRateNanos since last meeting target. - */ - if (now - mFirstTargetMetTimestamp > mPreferredRateNanos && - now - mLastTargetMetTimestamp <= mPreferredRateNanos) { - return 0; - } - mLastTargetMetTimestamp = now; - } + WorkDuration workDuration(0, actualDurationNanos, actualDurationNanos, 0); - binder::Status ret = - mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos); - if (!ret.isOk()) { - ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__, - ret.exceptionMessage().c_str()); - mFirstTargetMetTimestamp = 0; - mLastTargetMetTimestamp = 0; - return EPIPE; - } - mActualDurationsNanos.clear(); - mTimestampsNanos.clear(); - - return 0; + return reportActualWorkDurationInternal(&workDuration); } int APerformanceHintSession::sendHint(SessionHint hint) { @@ -322,6 +292,67 @@ int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) { return OK; } +int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* aWorkDuration) { + WorkDuration* workDuration = static_cast<WorkDuration*>(aWorkDuration); + if (workDuration->workPeriodStartTimestampNanos <= 0) { + ALOGE("%s: workPeriodStartTimestampNanos must be positive", __FUNCTION__); + return EINVAL; + } + if (workDuration->actualTotalDurationNanos <= 0) { + ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__); + return EINVAL; + } + if (workDuration->actualCpuDurationNanos <= 0) { + ALOGE("%s: cpuDurationNanos must be positive", __FUNCTION__); + return EINVAL; + } + if (workDuration->actualGpuDurationNanos < 0) { + ALOGE("%s: gpuDurationNanos must be non negative", __FUNCTION__); + return EINVAL; + } + + return reportActualWorkDurationInternal(workDuration); +} + +int APerformanceHintSession::reportActualWorkDurationInternal(WorkDuration* workDuration) { + int64_t actualTotalDurationNanos = workDuration->actualTotalDurationNanos; + int64_t now = uptimeNanos(); + workDuration->timestampNanos = now; + mActualWorkDurations.push_back(std::move(*workDuration)); + + if (actualTotalDurationNanos >= mTargetDurationNanos) { + // Reset timestamps if we are equal or over the target. + mFirstTargetMetTimestamp = 0; + } else { + // Set mFirstTargetMetTimestamp for first time meeting target. + if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp || + (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) { + mFirstTargetMetTimestamp = now; + } + /** + * Rate limit the change if the update is over mPreferredRateNanos since first + * meeting target and less than mPreferredRateNanos since last meeting target. + */ + if (now - mFirstTargetMetTimestamp > mPreferredRateNanos && + now - mLastTargetMetTimestamp <= mPreferredRateNanos) { + return 0; + } + mLastTargetMetTimestamp = now; + } + + binder::Status ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations); + if (!ret.isOk()) { + ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__, + ret.exceptionMessage().c_str()); + mFirstTargetMetTimestamp = 0; + mLastTargetMetTimestamp = 0; + return ret.exceptionCode() == binder::Status::EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE; + } + mActualWorkDurations.clear(); + + return 0; +} + // ===================================== C API APerformanceHintManager* APerformanceHint_getManager() { return APerformanceHintManager::getInstance(); @@ -376,6 +407,64 @@ int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, return session->setPreferPowerEfficiency(enabled); } +int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session, + AWorkDuration* workDuration) { + if (session == nullptr || workDuration == nullptr) { + ALOGE("Invalid value: (session %p, workDuration %p)", session, workDuration); + return EINVAL; + } + return session->reportActualWorkDuration(workDuration); +} + +AWorkDuration* AWorkDuration_create() { + WorkDuration* workDuration = new WorkDuration(); + return static_cast<AWorkDuration*>(workDuration); +} + +void AWorkDuration_release(AWorkDuration* aWorkDuration) { + if (aWorkDuration == nullptr) { + ALOGE("%s: aWorkDuration is nullptr", __FUNCTION__); + } + delete aWorkDuration; +} + +void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration, + int64_t workPeriodStartTimestampNanos) { + if (aWorkDuration == nullptr || workPeriodStartTimestampNanos <= 0) { + ALOGE("%s: Invalid value. (AWorkDuration: %p, workPeriodStartTimestampNanos: %" PRIi64 ")", + __FUNCTION__, aWorkDuration, workPeriodStartTimestampNanos); + } + static_cast<WorkDuration*>(aWorkDuration)->workPeriodStartTimestampNanos = + workPeriodStartTimestampNanos; +} + +void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration, + int64_t actualTotalDurationNanos) { + if (aWorkDuration == nullptr || actualTotalDurationNanos <= 0) { + ALOGE("%s: Invalid value. (AWorkDuration: %p, actualTotalDurationNanos: %" PRIi64 ")", + __FUNCTION__, aWorkDuration, actualTotalDurationNanos); + } + static_cast<WorkDuration*>(aWorkDuration)->actualTotalDurationNanos = actualTotalDurationNanos; +} + +void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration, + int64_t actualCpuDurationNanos) { + if (aWorkDuration == nullptr || actualCpuDurationNanos <= 0) { + ALOGE("%s: Invalid value. (AWorkDuration: %p, actualCpuDurationNanos: %" PRIi64 ")", + __FUNCTION__, aWorkDuration, actualCpuDurationNanos); + } + static_cast<WorkDuration*>(aWorkDuration)->actualCpuDurationNanos = actualCpuDurationNanos; +} + +void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration, + int64_t actualGpuDurationNanos) { + if (aWorkDuration == nullptr || actualGpuDurationNanos < 0) { + ALOGE("%s: Invalid value. (AWorkDuration: %p, actualGpuDurationNanos: %" PRIi64 ")", + __FUNCTION__, aWorkDuration, actualGpuDurationNanos); + } + static_cast<WorkDuration*>(aWorkDuration)->actualGpuDurationNanos = actualGpuDurationNanos; +} + void APerformanceHint_setIHintManagerForTesting(void* iManager) { delete gHintManagerForTesting; gHintManagerForTesting = nullptr; diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index 22d33b139ccf..4553b4919d2d 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "PerformanceHintNativeTest" +#include <android/WorkDuration.h> #include <android/os/IHintManager.h> #include <android/os/IHintSession.h> #include <android/performance_hint.h> @@ -60,6 +61,8 @@ public: MOCK_METHOD(Status, setMode, (int32_t mode, bool enabled), (override)); MOCK_METHOD(Status, close, (), (override)); MOCK_METHOD(IBinder*, onAsBinder, (), (override)); + MOCK_METHOD(Status, reportActualWorkDuration2, + (const ::std::vector<android::os::WorkDuration>& workDurations), (override)); }; class PerformanceHintTest : public Test { @@ -120,6 +123,7 @@ TEST_F(PerformanceHintTest, TestSession) { std::vector<int64_t> actualDurations; actualDurations.push_back(20); EXPECT_CALL(*iSession, reportActualWorkDuration(Eq(actualDurations), _)).Times(Exactly(1)); + EXPECT_CALL(*iSession, reportActualWorkDuration2(_)).Times(Exactly(1)); result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos); EXPECT_EQ(0, result); @@ -238,4 +242,125 @@ TEST_F(PerformanceHintTest, CreateZeroTargetDurationSession) { APerformanceHintSession* session = APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); ASSERT_TRUE(session); -}
\ No newline at end of file +} + +MATCHER_P(WorkDurationEq, expected, "") { + if (arg.size() != expected.size()) { + *result_listener << "WorkDuration vectors are different sizes. Expected: " + << expected.size() << ", Actual: " << arg.size(); + return false; + } + for (int i = 0; i < expected.size(); ++i) { + android::os::WorkDuration expectedWorkDuration = expected[i]; + android::os::WorkDuration actualWorkDuration = arg[i]; + if (!expectedWorkDuration.equalsWithoutTimestamp(actualWorkDuration)) { + *result_listener << "WorkDuration at [" << i << "] is different: " + << "Expected: " << expectedWorkDuration + << ", Actual: " << actualWorkDuration; + return false; + } + } + return true; +} + +TEST_F(PerformanceHintTest, TestAPerformanceHint_reportActualWorkDuration2) { + APerformanceHintManager* manager = createManager(); + + std::vector<int32_t> tids; + tids.push_back(1); + tids.push_back(2); + int64_t targetDuration = 56789L; + + StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>(); + sp<IHintSession> session_sp(iSession); + + EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _)) + .Times(Exactly(1)) + .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status()))); + + APerformanceHintSession* session = + APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration); + ASSERT_TRUE(session); + + int64_t targetDurationNanos = 10; + EXPECT_CALL(*iSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1)); + int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos); + EXPECT_EQ(0, result); + + usleep(2); // Sleep for longer than preferredUpdateRateNanos. + { + std::vector<android::os::WorkDuration> actualWorkDurations; + android::os::WorkDuration workDuration(1, 20, 13, 8); + actualWorkDurations.push_back(workDuration); + + EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) + .Times(Exactly(1)); + result = APerformanceHint_reportActualWorkDuration2(session, + static_cast<AWorkDuration*>( + &workDuration)); + EXPECT_EQ(0, result); + } + + { + std::vector<android::os::WorkDuration> actualWorkDurations; + android::os::WorkDuration workDuration(-1, 20, 13, 8); + actualWorkDurations.push_back(workDuration); + + EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) + .Times(Exactly(1)); + result = APerformanceHint_reportActualWorkDuration2(session, + static_cast<AWorkDuration*>( + &workDuration)); + EXPECT_EQ(22, result); + } + { + std::vector<android::os::WorkDuration> actualWorkDurations; + android::os::WorkDuration workDuration(1, -20, 13, 8); + actualWorkDurations.push_back(workDuration); + + EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) + .Times(Exactly(1)); + result = APerformanceHint_reportActualWorkDuration2(session, + static_cast<AWorkDuration*>( + &workDuration)); + EXPECT_EQ(22, result); + } + { + std::vector<android::os::WorkDuration> actualWorkDurations; + android::os::WorkDuration workDuration(1, 20, -13, 8); + actualWorkDurations.push_back(workDuration); + + EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) + .Times(Exactly(1)); + result = APerformanceHint_reportActualWorkDuration2(session, + static_cast<AWorkDuration*>( + &workDuration)); + EXPECT_EQ(EINVAL, result); + } + { + std::vector<android::os::WorkDuration> actualWorkDurations; + android::os::WorkDuration workDuration(1, 20, 13, -8); + actualWorkDurations.push_back(workDuration); + + EXPECT_CALL(*iSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations))) + .Times(Exactly(1)); + result = APerformanceHint_reportActualWorkDuration2(session, + static_cast<AWorkDuration*>( + &workDuration)); + EXPECT_EQ(EINVAL, result); + } + + EXPECT_CALL(*iSession, close()).Times(Exactly(1)); + APerformanceHint_closeSession(session); +} + +TEST_F(PerformanceHintTest, TestAWorkDuration) { + AWorkDuration* aWorkDuration = AWorkDuration_create(); + ASSERT_NE(aWorkDuration, nullptr); + + AWorkDuration_setWorkPeriodStartTimestampNanos(aWorkDuration, 1); + AWorkDuration_setActualTotalDurationNanos(aWorkDuration, 20); + AWorkDuration_setActualCpuDurationNanos(aWorkDuration, 13); + AWorkDuration_setActualGpuDurationNanos(aWorkDuration, 8); + AWorkDuration_release(aWorkDuration); +} diff --git a/packages/InputDevices/res/raw/keyboard_layout_ukrainian.kcm b/packages/InputDevices/res/raw/keyboard_layout_ukrainian.kcm index 90041da529c0..24b4d2fd6487 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_ukrainian.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_ukrainian.kcm @@ -14,8 +14,8 @@ # # Ukrainian keyboard layout. -# This is a typical Ukrainian PC keyboard layout. -# As an added convenience, English characters are accessible using ralt (Alt Gr). +# Based on PC enhanced Ukrainian layout with added Unicode keys based on +# the Linux one. # type OVERLAY @@ -25,32 +25,34 @@ map key 86 PLUS ### ROW 1 key GRAVE { - label: '\u0401' - base: '\u0451' - shift, capslock: '\u0401' - shift+capslock: '\u0451' - ralt: '`' + label: '\'' + base: '\'' + shift: '\u02bc' + ralt: '\u0301' ralt+shift: '~' } key 1 { label: '1' base: '1' - shift, ralt: '!' + shift: '!' + ralt: '\u00b9' } key 2 { label: '2' base: '2' shift: '"' - ralt: '@' + ralt: '\u00b2' + ralt+shift: '\u2019' } key 3 { label: '3' base: '3' shift: '\u2116' - ralt: '#' + ralt: '\u00a7' + ralt+shift: '\u20b4' } key 4 { @@ -58,60 +60,67 @@ key 4 { base: '4' shift: ';' ralt: '$' + ralt+shift: '\u20ac' } key 5 { label: '5' base: '5' - shift, ralt: '%' + shift: '%' + ralt: '\u00b0' } key 6 { label: '6' base: '6' shift: ':' - ralt: '^' + ralt: '<' } key 7 { label: '7' base: '7' shift: '?' - ralt: '&' + ralt: '>' } key 8 { label: '8' base: '8' - shift, ralt: '*' + shift: '*' + ralt: '\u2022' } key 9 { label: '9' base: '9' - shift, ralt: '(' + shift: '(' + ralt: '[' + ralt+shift: '{' } key 0 { label: '0' base: '0' - shift, ralt: ')' + shift: ')' + ralt: ']' + ralt+shift: '}' } key MINUS { label: '-' base: '-' shift: '_' - ralt: '-' - shift+ralt: '_' + ralt: '\u2014' + shift+ralt: '\u2013' } key EQUALS { label: '=' base: '=' shift: '+' - ralt: '=' - shift+ralt: '+' + ralt: '\u2260' + shift+ralt: '\u00b1' } ### ROW 2 @@ -121,6 +130,9 @@ key Q { base: '\u0439' shift, capslock: '\u0419' shift+capslock: '\u0439' + ralt: '\u0458' + ralt+shift, ralt+capslock: '\u0408' + ralt+shift+capslock: '\u0458' } key W { @@ -128,6 +140,9 @@ key W { base: '\u0446' shift, capslock: '\u0426' shift+capslock: '\u0446' + ralt: '\u045f' + ralt+shift, ralt+capslock: '\u040f' + ralt+shift+capslock: '\u045f' } key E { @@ -135,6 +150,9 @@ key E { base: '\u0443' shift, capslock: '\u0423' shift+capslock: '\u0443' + ralt: '\u045e' + ralt+shift, ralt+capslock: '\u040e' + ralt+shift+capslock: '\u045e' } key R { @@ -142,6 +160,7 @@ key R { base: '\u043a' shift, capslock: '\u041a' shift+capslock: '\u043a' + ralt: '\u00ae' } key T { @@ -149,6 +168,9 @@ key T { base: '\u0435' shift, capslock: '\u0415' shift+capslock: '\u0435' + ralt: '\u0451' + ralt+shift, ralt+capslock: '\u0401' + ralt+shift+capslock: '\u0451' } key Y { @@ -156,6 +178,9 @@ key Y { base: '\u043d' shift, capslock: '\u041d' shift+capslock: '\u043d' + ralt: '\u045a' + ralt+shift, ralt+capslock: '\u040a' + ralt+shift+capslock: '\u045a' } key U { @@ -164,8 +189,8 @@ key U { shift, capslock: '\u0413' shift+capslock: '\u0433' ralt: '\u0491' - shift+ralt, capslock+ralt: '\u0490' - shift+capslock+ralt: '\u0491' + ralt+shift, ralt+capslock: '\u0490' + ralt+shift+capslock: '\u0491' } key I { @@ -201,6 +226,9 @@ key RIGHT_BRACKET { base: '\u0457' shift, capslock: '\u0407' shift+capslock: '\u0457' + ralt: '\u044a' + ralt+shift, ralt+capslock: '\u042a' + ralt+shift+capslock: '\u044a' } ### ROW 3 @@ -217,6 +245,9 @@ key S { base: '\u0456' shift, capslock: '\u0406' shift+capslock: '\u0456' + ralt: '\u044b' + ralt+shift, ralt+capslock: '\u042b' + ralt+shift+capslock: '\u044b' } key D { @@ -259,6 +290,9 @@ key K { base: '\u043b' shift, capslock: '\u041b' shift+capslock: '\u043b' + ralt: '\u0459' + ralt+shift, ralt+capslock: '\u0409' + ralt+shift+capslock: '\u0459' } key L { @@ -266,6 +300,9 @@ key L { base: '\u0434' shift, capslock: '\u0414' shift+capslock: '\u0434' + ralt: '\u0452' + ralt+shift, ralt+capslock: '\u0402' + ralt+shift+capslock: '\u0452' } key SEMICOLON { @@ -282,15 +319,18 @@ key APOSTROPHE { base: '\u0454' shift, capslock: '\u0404' shift+capslock: '\u0454' - ralt: '\'' - ralt+shift: '"' + ralt: '\u044d' + ralt+shift, ralt+capslock: '\u042d' + ralt+shift+capslock: '\u044d' } key BACKSLASH { label: '\\' base: '\\' shift: '/' - ralt: '|' + ralt: '\u0491' + ralt+shift, ralt+capslock: '\u0490' + ralt+shift+capslock: '\u0491' } ### ROW 4 @@ -316,6 +356,9 @@ key X { base: '\u0447' shift, capslock: '\u0427' shift+capslock: '\u0447' + ralt: '\u045b' + ralt+shift, ralt+capslock: '\u040b' + ralt+shift+capslock: '\u045b' } key C { @@ -323,6 +366,7 @@ key C { base: '\u0441' shift, capslock: '\u0421' shift+capslock: '\u0441' + ralt: '\u00a9' } key V { @@ -344,6 +388,7 @@ key N { base: '\u0442' shift, capslock: '\u0422' shift+capslock: '\u0442' + ralt: '\u2122' } key M { @@ -358,8 +403,8 @@ key COMMA { base: '\u0431' shift, capslock: '\u0411' shift+capslock: '\u0431' - ralt: ',' - ralt+shift: '<' + ralt: '\u00ab' + ralt+shift: '\u201e' } key PERIOD { @@ -367,8 +412,8 @@ key PERIOD { base: '\u044e' shift, capslock: '\u042e' shift+capslock: '\u044e' - ralt: '.' - ralt+shift: '>' + ralt: '\u00bb' + ralt+shift: '\u201c' } key SLASH { @@ -376,5 +421,5 @@ key SLASH { base: '.' shift: ',' ralt: '/' - ralt+shift: '?' + ralt+shift: '\u2026' } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java index 4e28d77aed08..09be76814d92 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java @@ -116,6 +116,7 @@ public class UninstallUninstalling extends Activity implements int flags = allUsers ? PackageManager.DELETE_ALL_USERS : 0; flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0; + flags |= getIntent().getIntExtra(PackageInstaller.EXTRA_DELETE_FLAGS, 0); createContextAsUser(user, 0).getPackageManager().getPackageInstaller().uninstall( new VersionedPackage(mAppInfo.packageName, diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java index ba627e9e9202..5c9b728a0f9d 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java @@ -19,6 +19,7 @@ package com.android.packageinstaller; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.content.pm.Flags.usePiaV2; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionForUid; import android.Manifest; @@ -55,8 +56,8 @@ import com.android.packageinstaller.handheld.UninstallAlertDialogFragment; import com.android.packageinstaller.television.ErrorFragment; import com.android.packageinstaller.television.UninstallAlertFragment; import com.android.packageinstaller.television.UninstallAppProgress; - import com.android.packageinstaller.v2.ui.UninstallLaunch; + import java.util.List; /* @@ -76,6 +77,7 @@ public class UninstallerActivity extends Activity { public boolean allUsers; public UserHandle user; public PackageManager.UninstallCompleteCallback callback; + public int deleteFlags; } private String mPackageName; @@ -226,10 +228,26 @@ public class UninstallerActivity extends Activity { // Continue as the ActivityInfo isn't critical. } } + parseDeleteFlags(intent); showConfirmationDialog(); } + /** + * Parses specific {@link android.content.pm.PackageManager.DeleteFlags} from {@link Intent} + * to archive an app if requested. + * + * Do not parse any flags because developers might pass here any flags which might cause + * unintended behaviour. + * For more context {@link com.android.server.pm.PackageArchiver#requestArchive}. + */ + private void parseDeleteFlags(Intent intent) { + int deleteFlags = intent.getIntExtra(PackageInstaller.EXTRA_DELETE_FLAGS, 0); + int archive = deleteFlags & PackageManager.DELETE_ARCHIVE; + int keepData = deleteFlags & PackageManager.DELETE_KEEP_DATA; + mDialogInfo.deleteFlags = archive | keepData; + } + public DialogInfo getDialogInfo() { return mDialogInfo; } @@ -347,7 +365,10 @@ public class UninstallerActivity extends Activity { if (returnResult || getCallingActivity() != null) { newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); } - + if (mDialogInfo.deleteFlags != 0) { + newIntent.putExtra(PackageInstaller.EXTRA_DELETE_FLAGS, + mDialogInfo.deleteFlags); + } startActivity(newIntent); } else { int uninstallId; @@ -393,6 +414,7 @@ public class UninstallerActivity extends Activity { int flags = mDialogInfo.allUsers ? PackageManager.DELETE_ALL_USERS : 0; flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0; + flags |= mDialogInfo.deleteFlags; createContextAsUser(mDialogInfo.user, 0).getPackageManager().getPackageInstaller() .uninstall(new VersionedPackage(mDialogInfo.appInfo.packageName, diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml index 6979825c9a20..e4befc290939 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/style_preference.xml @@ -70,6 +70,7 @@ <style name="SettingsSwitchPreferenceCompat.SettingsLib" parent="@style/Preference.SwitchPreferenceCompat.Material"> <item name="layout">@layout/settingslib_preference</item> + <item name="singleLineTitle">false</item> <item name="iconSpaceReserved">@bool/settingslib_config_icon_space_reserved</item> </style> diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/database/ContentChangeFlow.kt index de5c558fea56..8f67354b76f3 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalFlow.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/database/ContentChangeFlow.kt @@ -14,12 +14,11 @@ * limitations under the License. */ -package com.android.settingslib.spaprivileged.settingsprovider +package com.android.settingslib.spaprivileged.database import android.content.Context import android.database.ContentObserver -import android.os.Handler -import android.provider.Settings +import android.net.Uri import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -27,20 +26,19 @@ import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.flowOn -internal fun <T> Context.settingsGlobalFlow( - name: String, - sendInitialValue: Boolean = true, - value: () -> T, -): Flow<T> = callbackFlow { - val contentObserver = object : ContentObserver(Handler.getMain()) { +/** Content change flow for the given [uri]. */ +internal fun Context.contentChangeFlow( + uri: Uri, + sendInitial: Boolean = true, +): Flow<Unit> = callbackFlow { + val contentObserver = object : ContentObserver(null) { override fun onChange(selfChange: Boolean) { - trySend(value()) + trySend(Unit) } } - val uri = Settings.Global.getUriFor(name) contentResolver.registerContentObserver(uri, false, contentObserver) - if (sendInitialValue) { - trySend(value()) + if (sendInitial) { + trySend(Unit) } awaitClose { contentResolver.unregisterContentObserver(contentObserver) } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt index 8e28bf8e632d..5d67f57136e3 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBoolean.kt @@ -22,13 +22,15 @@ import android.provider.Settings import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map fun Context.settingsGlobalBoolean(name: String, defaultValue: Boolean = false): ReadWriteProperty<Any?, Boolean> = SettingsGlobalBooleanDelegate(this, name, defaultValue) fun Context.settingsGlobalBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> { val value by settingsGlobalBoolean(name, defaultValue) - return settingsGlobalFlow(name) { value } + return settingsGlobalChangeFlow(name).map { value }.distinctUntilChanged() } private class SettingsGlobalBooleanDelegate( diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlow.kt index 4098987256a2..675b2e5db430 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlow.kt @@ -17,7 +17,9 @@ package com.android.settingslib.spaprivileged.settingsprovider import android.content.Context +import android.provider.Settings +import com.android.settingslib.spaprivileged.database.contentChangeFlow import kotlinx.coroutines.flow.Flow fun Context.settingsGlobalChangeFlow(name: String, sendInitialValue: Boolean = true): Flow<Unit> = - settingsGlobalFlow(name, sendInitialValue) { } + contentChangeFlow(Settings.Global.getUriFor(name), sendInitialValue) diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt new file mode 100644 index 000000000000..25090a4140a4 --- /dev/null +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBoolean.kt @@ -0,0 +1,51 @@ +/* + * 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.settingslib.spaprivileged.settingsprovider + +import android.content.ContentResolver +import android.content.Context +import android.provider.Settings +import com.android.settingslib.spaprivileged.database.contentChangeFlow +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map + +fun Context.settingsSecureBoolean(name: String, defaultValue: Boolean = false): + ReadWriteProperty<Any?, Boolean> = SettingsSecureBooleanDelegate(this, name, defaultValue) + +fun Context.settingsSecureBooleanFlow(name: String, defaultValue: Boolean = false): Flow<Boolean> { + val value by settingsSecureBoolean(name, defaultValue) + return contentChangeFlow(Settings.Secure.getUriFor(name)).map { value }.distinctUntilChanged() +} + +private class SettingsSecureBooleanDelegate( + context: Context, + private val name: String, + private val defaultValue: Boolean = false, +) : ReadWriteProperty<Any?, Boolean> { + + private val contentResolver: ContentResolver = context.contentResolver + + override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean = + Settings.Secure.getInt(contentResolver, name, if (defaultValue) 1 else 0) != 0 + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) { + Settings.Secure.putInt(contentResolver, name, if (value) 1 else 0) + } +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt index 45295b013cf9..f306918ec72f 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt @@ -89,7 +89,7 @@ class AppInfoProvider(private val packageInfo: PackageInfo) { @Composable fun FooterAppVersion(showPackageName: Boolean = rememberIsDevelopmentSettingsEnabled()) { val context = LocalContext.current - val footer = remember(showPackageName) { + val footer = remember(packageInfo, showPackageName) { val list = mutableListOf<String>() packageInfo.versionNameBidiWrapped?.let { list += context.getString(R.string.version_text, it) diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt index 626c913ac9e6..7a4f81cc1321 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppStorageSize.kt @@ -37,7 +37,7 @@ private const val TAG = "AppStorageSize" @Composable fun ApplicationInfo.getStorageSize(): State<String> { val context = LocalContext.current - return remember { + return remember(this) { flow { val sizeBytes = calculateSizeBytes(context) this.emit(if (sizeBytes != null) Formatter.formatFileSize(context, sizeBytes) else "") diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt index 44973a743c76..f2922316dbde 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt @@ -126,10 +126,7 @@ class AppListRepositoryTest { val flags = argumentCaptor<ApplicationInfoFlags> { verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID)) }.firstValue - assertThat(flags.value).isEqualTo( - PackageManager.MATCH_DISABLED_COMPONENTS or - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - ) + assertThat(flags.value and PackageManager.MATCH_ANY_USER.toLong()).isEqualTo(0L) } @Test @@ -276,21 +273,6 @@ class AppListRepositoryTest { } @Test - fun loadApps_archivedAppsDisabled() = runTest { - mockInstalledApplications(listOf(NORMAL_APP), ADMIN_USER_ID) - val appList = repository.loadApps(userId = ADMIN_USER_ID) - - assertThat(appList).containsExactly(NORMAL_APP) - val flags = argumentCaptor<ApplicationInfoFlags> { - verify(packageManager).getInstalledApplicationsAsUser(capture(), eq(ADMIN_USER_ID)) - }.firstValue - assertThat(flags.value).isEqualTo( - PackageManager.MATCH_DISABLED_COMPONENTS or - PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - ) - } - - @Test fun showSystemPredicate_showSystem() = runTest { val app = SYSTEM_APP diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt index 996c2d57c38a..70b38feae9d5 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt @@ -30,7 +30,7 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class SettingsGlobalBooleanRepositoryTest { +class SettingsGlobalBooleanTest { private val context: Context = ApplicationProvider.getApplicationContext() diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt index 37e00e6f671b..2e6a39603deb 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt @@ -29,7 +29,7 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class SettingsGlobalChangeRepositoryTest { +class SettingsGlobalChangeFlowTest { private val context: Context = ApplicationProvider.getApplicationContext() @@ -52,7 +52,7 @@ class SettingsGlobalChangeRepositoryTest { var value by context.settingsGlobalBoolean(TEST_NAME) value = false - val flow = context.settingsGlobalBooleanFlow(TEST_NAME) + val flow = context.settingsGlobalChangeFlow(TEST_NAME) value = true assertThat(flow.toListWithTimeout()).hasSize(1) diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt new file mode 100644 index 000000000000..29a89be87acd --- /dev/null +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt @@ -0,0 +1,111 @@ +/* + * 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.settingslib.spaprivileged.settingsprovider + +import android.content.Context +import android.provider.Settings +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull +import com.android.settingslib.spa.testutils.toListWithTimeout +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.async +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SettingsSecureBooleanTest { + + private val context: Context = ApplicationProvider.getApplicationContext() + + @Test + fun getValue_setTrue_returnTrue() { + Settings.Secure.putInt(context.contentResolver, TEST_NAME, 1) + + val value by context.settingsSecureBoolean(TEST_NAME) + + assertThat(value).isTrue() + } + + @Test + fun getValue_setFalse_returnFalse() { + Settings.Secure.putInt(context.contentResolver, TEST_NAME, 0) + + val value by context.settingsSecureBoolean(TEST_NAME) + + assertThat(value).isFalse() + } + + @Test + fun setValue_setTrue_returnTrue() { + var value by context.settingsSecureBoolean(TEST_NAME) + + value = true + + assertThat(Settings.Secure.getInt(context.contentResolver, TEST_NAME, 0)).isEqualTo(1) + } + + @Test + fun setValue_setFalse_returnFalse() { + var value by context.settingsSecureBoolean(TEST_NAME) + + value = false + + assertThat(Settings.Secure.getInt(context.contentResolver, TEST_NAME, 1)).isEqualTo(0) + } + + @Test + fun settingsSecureBooleanFlow_valueNotChanged() = runBlocking { + var value by context.settingsSecureBoolean(TEST_NAME) + value = false + + val flow = context.settingsSecureBooleanFlow(TEST_NAME) + + assertThat(flow.firstWithTimeoutOrNull()).isFalse() + } + + @Test + fun settingsSecureBooleanFlow_collectAfterValueChanged_onlyKeepLatest() = runBlocking { + var value by context.settingsSecureBoolean(TEST_NAME) + value = false + + val flow = context.settingsSecureBooleanFlow(TEST_NAME) + value = true + + assertThat(flow.firstWithTimeoutOrNull()).isTrue() + } + + @Test + fun settingsSecureBooleanFlow_collectBeforeValueChanged_getBoth() = runBlocking { + var value by context.settingsSecureBoolean(TEST_NAME) + value = false + + val listDeferred = async { + context.settingsSecureBooleanFlow(TEST_NAME).toListWithTimeout() + } + delay(100) + value = true + + assertThat(listDeferred.await()).containsExactly(false, true).inOrder() + } + + private companion object { + const val TEST_NAME = "test_boolean_delegate" + } +} diff --git a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig index 4936f882f91e..f3e537b33230 100644 --- a/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig +++ b/packages/SettingsLib/aconfig/settingslib_media_flag_declarations.aconfig @@ -12,4 +12,11 @@ flag { namespace: "tv_system_ui" description: "Gates all the changes for the tv specific media output dialog" bug: "303205631" -}
\ No newline at end of file +} + +flag { + name: "enable_output_switcher_for_system_routing" + namespace: "media_solutions" + description: "Enable Output Switcher when no media is playing." + bug: "284227163" +} diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index ed5654d4f259..ec50323dd91d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -2432,9 +2432,7 @@ class DatabaseHelper extends SQLiteOpenHelper { R.bool.def_auto_time_zone); // Sync timezone to NITZ loadSetting(stmt, Settings.Global.STAY_ON_WHILE_PLUGGED_IN, - ("1".equals(SystemProperties.get("ro.boot.qemu")) - || res.getBoolean(R.bool.def_stay_on_while_plugged_in)) - ? 1 : 0); + res.getBoolean(R.bool.def_stay_on_while_plugged_in) ? 1 : 0); loadIntegerSetting(stmt, Settings.Global.WIFI_SLEEP_POLICY, R.integer.def_wifi_sleep_policy); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 650319fd58f9..b6a0c7bafa44 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -442,6 +442,9 @@ <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" /> <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS" /> + <!-- Permission required for CTS test - CtsNfcResolverDerviceTest --> + <uses-permission android:name="android.permission.SHOW_CUSTOMIZED_RESOLVER" /> + <!-- Permission needed for CTS test - MusicRecognitionManagerTest --> <uses-permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION" /> diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 77c4aa602f27..d8d3f87c9566 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -188,3 +188,9 @@ flag { bug: "305049544" } +flag { + name: "fast_unlock_transition" + namespace: "systemui" + description: "Faster wallpaper unlock transition" + bug: "298186160" +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt index ba80a8deffb7..1a653c316db1 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt @@ -34,9 +34,9 @@ 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 import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -66,6 +66,7 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp @@ -97,7 +98,7 @@ import kotlin.math.pow fun BouncerContent( viewModel: BouncerViewModel, dialogFactory: BouncerDialogFactory, - modifier: Modifier + modifier: Modifier = Modifier, ) { val isFullScreenUserSwitcherEnabled = viewModel.isUserSwitcherVisible val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsState() @@ -142,6 +143,7 @@ private fun StandardLayout( viewModel: BouncerViewModel, dialogFactory: BouncerDialogFactory, modifier: Modifier = Modifier, + layout: BouncerSceneLayout = BouncerSceneLayout.STANDARD, outputOnly: Boolean = false, ) { val foldPosture: FoldPosture by foldPosture() @@ -161,6 +163,7 @@ private fun StandardLayout( FoldSplittable( viewModel = viewModel, dialogFactory = dialogFactory, + layout = layout, outputOnly = outputOnly, isSplit = false, ) @@ -170,6 +173,7 @@ private fun StandardLayout( FoldSplittable( viewModel = viewModel, dialogFactory = dialogFactory, + layout = layout, outputOnly = outputOnly, isSplit = true, ) @@ -193,6 +197,7 @@ private fun StandardLayout( private fun SceneScope.FoldSplittable( viewModel: BouncerViewModel, dialogFactory: BouncerDialogFactory, + layout: BouncerSceneLayout, outputOnly: Boolean, isSplit: Boolean, modifier: Modifier = Modifier, @@ -210,13 +215,21 @@ private fun SceneScope.FoldSplittable( // Content above the fold, when split on a foldable device in a "table top" posture: Box( modifier = - Modifier.element(SceneElements.AboveFold).fillMaxWidth().thenIf(isSplit) { - Modifier.weight(splitRatio) - }, + Modifier.element(SceneElements.AboveFold) + .fillMaxWidth() + .then( + if (isSplit) { + Modifier.weight(splitRatio) + } else if (outputOnly) { + Modifier.fillMaxHeight() + } else { + Modifier + } + ), ) { Column( horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxWidth().padding(top = 92.dp), + modifier = Modifier.fillMaxWidth().padding(top = layout.topPadding), ) { Crossfade( targetState = message, @@ -230,11 +243,23 @@ private fun SceneScope.FoldSplittable( ) } - Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp)) + if (!outputOnly) { + Spacer(Modifier.height(layout.spacingBetweenMessageAndEnteredInput)) + + UserInputArea( + viewModel = viewModel, + visibility = UserInputAreaVisibility.OUTPUT_ONLY, + layout = layout, + ) + } + } + if (outputOnly) { UserInputArea( viewModel = viewModel, visibility = UserInputAreaVisibility.OUTPUT_ONLY, + layout = layout, + modifier = Modifier.align(Alignment.Center), ) } } @@ -242,25 +267,32 @@ private fun SceneScope.FoldSplittable( // Content below the fold, when split on a foldable device in a "table top" posture: Box( modifier = - Modifier.element(SceneElements.BelowFold).fillMaxWidth().thenIf(isSplit) { - Modifier.weight(1 - splitRatio) - }, + Modifier.element(SceneElements.BelowFold) + .fillMaxWidth() + .weight( + if (isSplit) { + 1 - splitRatio + } else { + 1f + } + ), ) { Column( horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxSize() ) { if (!outputOnly) { Box(Modifier.weight(1f)) { UserInputArea( viewModel = viewModel, visibility = UserInputAreaVisibility.INPUT_ONLY, - modifier = Modifier.align(Alignment.Center), + layout = layout, + modifier = Modifier.align(Alignment.BottomCenter), ) } } - Spacer(Modifier.heightIn(min = 21.dp, max = 48.dp)) + Spacer(Modifier.height(48.dp)) val actionButtonModifier = Modifier.height(56.dp) @@ -275,7 +307,7 @@ private fun SceneScope.FoldSplittable( } } - Spacer(Modifier.height(48.dp)) + Spacer(Modifier.height(layout.bottomPadding)) } } @@ -311,6 +343,7 @@ private fun SceneScope.FoldSplittable( private fun UserInputArea( viewModel: BouncerViewModel, visibility: UserInputAreaVisibility, + layout: BouncerSceneLayout, modifier: Modifier = Modifier, ) { val authMethodViewModel: AuthMethodBouncerViewModel? by @@ -327,6 +360,7 @@ private fun UserInputArea( UserInputAreaVisibility.INPUT_ONLY -> PinPad( viewModel = nonNullViewModel, + layout = layout, modifier = modifier, ) } @@ -341,7 +375,8 @@ private fun UserInputArea( if (visibility == UserInputAreaVisibility.INPUT_ONLY) { PatternBouncer( viewModel = nonNullViewModel, - modifier = modifier.aspectRatio(1f, matchHeightConstraintsFirst = false) + layout = layout, + modifier = modifier.aspectRatio(1f, matchHeightConstraintsFirst = false), ) } else -> Unit @@ -449,7 +484,7 @@ private fun UserSwitcher( } /** - * Renders the dropdown menu that displays the actual users and/or user actions that can be + * Renders the dropdowm menu that displays the actual users and/or user actions that can be * selected. */ @Composable @@ -519,6 +554,7 @@ private fun SplitLayout( StandardLayout( viewModel = viewModel, dialogFactory = dialogFactory, + layout = BouncerSceneLayout.SPLIT, outputOnly = true, modifier = startContentModifier, ) @@ -527,10 +563,12 @@ private fun SplitLayout( UserInputArea( viewModel = viewModel, visibility = UserInputAreaVisibility.INPUT_ONLY, + layout = BouncerSceneLayout.SPLIT, modifier = endContentModifier, ) }, - modifier = modifier + layout = BouncerSceneLayout.SPLIT, + modifier = modifier, ) } @@ -542,6 +580,7 @@ private fun SplitLayout( private fun SwappableLayout( startContent: @Composable (Modifier) -> Unit, endContent: @Composable (Modifier) -> Unit, + layout: BouncerSceneLayout, modifier: Modifier = Modifier, ) { val layoutDirection = LocalLayoutDirection.current @@ -597,7 +636,7 @@ private fun SwappableLayout( alpha = animatedAlpha(animatedOffset) } ) { - endContent(Modifier.widthIn(max = 400.dp).align(Alignment.BottomCenter)) + endContent(Modifier.align(layout.swappableEndContentAlignment).widthIn(max = 400.dp)) } } } @@ -635,9 +674,11 @@ private fun SideBySideLayout( StandardLayout( viewModel = viewModel, dialogFactory = dialogFactory, + layout = BouncerSceneLayout.SIDE_BY_SIDE, modifier = endContentModifier, ) }, + layout = BouncerSceneLayout.SIDE_BY_SIDE, modifier = modifier, ) } @@ -663,6 +704,7 @@ private fun StackedLayout( StandardLayout( viewModel = viewModel, dialogFactory = dialogFactory, + layout = BouncerSceneLayout.STACKED, modifier = Modifier.fillMaxWidth().weight(1f), ) } @@ -732,3 +774,48 @@ private object SceneElements { private val SceneTransitions = transitions { from(SceneKeys.ContiguousSceneKey, to = SceneKeys.SplitSceneKey) { spec = tween() } } + +/** Whether a more compact size should be used for various spacing dimensions. */ +internal val BouncerSceneLayout.isUseCompactSize: Boolean + get() = + when (this) { + BouncerSceneLayout.SIDE_BY_SIDE -> true + BouncerSceneLayout.SPLIT -> true + else -> false + } + +/** Amount of space to place between the message and the entered input UI elements, in dips. */ +private val BouncerSceneLayout.spacingBetweenMessageAndEnteredInput: Dp + get() = + when { + this == BouncerSceneLayout.STACKED -> 24.dp + isUseCompactSize -> 96.dp + else -> 128.dp + } + +/** Amount of space to place above the topmost UI element, in dips. */ +private val BouncerSceneLayout.topPadding: Dp + get() = + if (this == BouncerSceneLayout.SPLIT) { + 40.dp + } else { + 92.dp + } + +/** Amount of space to place below the bottommost UI element, in dips. */ +private val BouncerSceneLayout.bottomPadding: Dp + get() = + if (this == BouncerSceneLayout.SPLIT) { + 40.dp + } else { + 48.dp + } + +/** The in-a-box alignment for the content on the "end" side of a swappable layout. */ +private val BouncerSceneLayout.swappableEndContentAlignment: Alignment + get() = + if (this == BouncerSceneLayout.SPLIT) { + Alignment.Center + } else { + Alignment.BottomCenter + } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt index eb0688914b9d..279995959da2 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt @@ -18,8 +18,6 @@ package com.android.systemui.bouncer.ui.composable import android.view.ViewTreeObserver import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.LocalTextStyle @@ -31,7 +29,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -64,10 +61,6 @@ internal fun PasswordBouncer( focusRequester.requestFocus() } } - val (isTextFieldFocused, onTextFieldFocusChanged) = remember { mutableStateOf(false) } - LaunchedEffect(isTextFieldFocused) { - viewModel.onTextFieldFocusChanged(isFocused = isTextFieldFocused) - } val password: String by viewModel.password.collectAsState() val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState() @@ -113,7 +106,7 @@ internal fun PasswordBouncer( ), modifier = Modifier.focusRequester(focusRequester) - .onFocusChanged { onTextFieldFocusChanged(it.isFocused) } + .onFocusChanged { viewModel.onTextFieldFocusChanged(it.isFocused) } .drawBehind { drawLine( color = color, @@ -123,8 +116,6 @@ internal fun PasswordBouncer( ) }, ) - - Spacer(Modifier.height(100.dp)) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt index ff1cbd6b04c3..a4b195508b3d 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt @@ -48,6 +48,7 @@ import androidx.compose.ui.unit.dp import com.android.compose.animation.Easings import com.android.compose.modifiers.thenIf import com.android.internal.R +import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.PatternDotViewModel import kotlin.math.min @@ -64,6 +65,7 @@ import kotlinx.coroutines.launch @Composable internal fun PatternBouncer( viewModel: PatternBouncerViewModel, + layout: BouncerSceneLayout, modifier: Modifier = Modifier, ) { DisposableEffect(Unit) { @@ -190,6 +192,8 @@ internal fun PatternBouncer( // This is the position of the input pointer. var inputPosition: Offset? by remember { mutableStateOf(null) } var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) } + var offset: Offset by remember { mutableStateOf(Offset.Zero) } + var scale: Float by remember { mutableStateOf(1f) } Canvas( modifier @@ -224,21 +228,42 @@ internal fun PatternBouncer( }, ) { change, _ -> inputPosition = change.position - viewModel.onDrag( - xPx = change.position.x, - yPx = change.position.y, - containerSizePx = size.width, - ) + change.position.minus(offset).div(scale).let { + viewModel.onDrag( + xPx = it.x, + yPx = it.y, + containerSizePx = size.width, + ) + } } } } ) { gridCoordinates?.let { nonNullCoordinates -> val containerSize = nonNullCoordinates.size + if (containerSize.width <= 0 || containerSize.height <= 0) { + return@let + } + val horizontalSpacing = containerSize.width.toFloat() / colCount val verticalSpacing = containerSize.height.toFloat() / rowCount val spacing = min(horizontalSpacing, verticalSpacing) - val verticalOffset = containerSize.height - spacing * rowCount + val horizontalOffset = + offset( + availableSize = containerSize.width, + spacingPerDot = spacing, + dotCount = colCount, + isCentered = true, + ) + val verticalOffset = + offset( + availableSize = containerSize.height, + spacingPerDot = spacing, + dotCount = rowCount, + isCentered = layout.isCenteredVertically, + ) + offset = Offset(horizontalOffset, verticalOffset) + scale = (colCount * spacing) / containerSize.width if (isAnimationEnabled) { // Draw lines between dots. @@ -248,8 +273,9 @@ internal fun PatternBouncer( val lineFadeOutAnimationProgress = lineFadeOutAnimatables[previousDot]!!.value val startLerp = 1 - lineFadeOutAnimationProgress - val from = pixelOffset(previousDot, spacing, verticalOffset) - val to = pixelOffset(dot, spacing, verticalOffset) + val from = + pixelOffset(previousDot, spacing, horizontalOffset, verticalOffset) + val to = pixelOffset(dot, spacing, horizontalOffset, verticalOffset) val lerpedFrom = Offset( x = from.x + (to.x - from.x) * startLerp, @@ -270,7 +296,7 @@ internal fun PatternBouncer( // position. inputPosition?.let { lineEnd -> currentDot?.let { dot -> - val from = pixelOffset(dot, spacing, verticalOffset) + val from = pixelOffset(dot, spacing, horizontalOffset, verticalOffset) val lineLength = sqrt((from.y - lineEnd.y).pow(2) + (from.x - lineEnd.x).pow(2)) drawLine( @@ -288,7 +314,7 @@ internal fun PatternBouncer( // Draw each dot on the grid. dots.forEach { dot -> drawCircle( - center = pixelOffset(dot, spacing, verticalOffset), + center = pixelOffset(dot, spacing, horizontalOffset, verticalOffset), color = dotColor, radius = dotRadius * (dotScalingAnimatables[dot]?.value ?: 1f), ) @@ -301,10 +327,11 @@ internal fun PatternBouncer( private fun pixelOffset( dot: PatternDotViewModel, spacing: Float, + horizontalOffset: Float, verticalOffset: Float, ): Offset { return Offset( - x = dot.x * spacing + spacing / 2, + x = dot.x * spacing + spacing / 2 + horizontalOffset, y = dot.y * spacing + spacing / 2 + verticalOffset, ) } @@ -371,6 +398,35 @@ private suspend fun showFailureAnimation( } } +/** + * Returns the amount of offset along the axis, in pixels, that should be applied to all dots. + * + * @param availableSize The size of the container, along the axis of interest. + * @param spacingPerDot The amount of pixels that each dot should take (including the area around + * that dot). + * @param dotCount The number of dots along the axis (e.g. if the axis of interest is the + * horizontal/x axis, this is the number of columns in the dot grid). + * @param isCentered Whether the dots should be centered along the axis of interest; if `false`, the + * dots will be pushed towards to end/bottom of the axis. + */ +private fun offset( + availableSize: Int, + spacingPerDot: Float, + dotCount: Int, + isCentered: Boolean = false, +): Float { + val default = availableSize - spacingPerDot * dotCount + return if (isCentered) { + default / 2 + } else { + default + } +} + +/** Whether the UI should be centered vertically. */ +private val BouncerSceneLayout.isCenteredVertically: Boolean + get() = this == BouncerSceneLayout.SPLIT + private const val DOT_DIAMETER_DP = 16 private const val SELECTED_DOT_DIAMETER_DP = 24 private const val SELECTED_DOT_REACTION_ANIMATION_DURATION_MS = 83 diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt index 59617c9022ab..8f5d9f4a1790 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt @@ -52,6 +52,7 @@ import androidx.compose.ui.unit.dp import com.android.compose.animation.Easings import com.android.compose.grid.VerticalGrid import com.android.compose.modifiers.thenIf +import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout import com.android.systemui.bouncer.ui.viewmodel.ActionButtonAppearance import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel import com.android.systemui.common.shared.model.ContentDescription @@ -65,9 +66,11 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +/** Renders the PIN button pad. */ @Composable fun PinPad( viewModel: PinBouncerViewModel, + layout: BouncerSceneLayout, modifier: Modifier = Modifier, ) { DisposableEffect(Unit) { @@ -92,9 +95,9 @@ fun PinPad( } VerticalGrid( - columns = 3, - verticalSpacing = 12.dp, - horizontalSpacing = 20.dp, + columns = columns, + verticalSpacing = layout.verticalSpacing, + horizontalSpacing = calculateHorizontalSpacingBetweenColumns(layout.gridWidth), modifier = modifier, ) { repeat(9) { index -> @@ -254,7 +257,7 @@ private fun PinPadButton( val cornerRadius: Dp by animateDpAsState( - if (isAnimationEnabled && isPressed) 24.dp else pinButtonSize / 2, + if (isAnimationEnabled && isPressed) 24.dp else pinButtonMaxSize / 2, label = "PinButton round corners", animationSpec = tween(animDurationMillis, easing = animEasing) ) @@ -284,7 +287,7 @@ private fun PinPadButton( contentAlignment = Alignment.Center, modifier = modifier - .sizeIn(maxWidth = pinButtonSize, maxHeight = pinButtonSize) + .sizeIn(maxWidth = pinButtonMaxSize, maxHeight = pinButtonMaxSize) .aspectRatio(1f) .drawBehind { drawRoundRect( @@ -345,10 +348,32 @@ private suspend fun showFailureAnimation( } } -private val pinButtonSize = 84.dp -private val pinButtonErrorShrinkFactor = 67.dp / pinButtonSize +/** Returns the amount of horizontal spacing between columns, in dips. */ +private fun calculateHorizontalSpacingBetweenColumns( + gridWidth: Dp, +): Dp { + return (gridWidth - (pinButtonMaxSize * columns)) / (columns - 1) +} + +/** The width of the grid of PIN pad buttons, in dips. */ +private val BouncerSceneLayout.gridWidth: Dp + get() = if (isUseCompactSize) 292.dp else 300.dp + +/** The spacing between rows of PIN pad buttons, in dips. */ +private val BouncerSceneLayout.verticalSpacing: Dp + get() = if (isUseCompactSize) 8.dp else 12.dp + +/** Number of columns in the PIN pad grid. */ +private const val columns = 3 +/** Maximum size (width and height) of each PIN pad button. */ +private val pinButtonMaxSize = 84.dp +/** Scale factor to apply to buttons when animating the "error" animation on them. */ +private val pinButtonErrorShrinkFactor = 67.dp / pinButtonMaxSize +/** Animation duration of the "shrink" phase of the error animation, on each PIN pad button. */ private const val pinButtonErrorShrinkMs = 50 +/** Amount of time to wait between application of the "error" animation to each row of buttons. */ private const val pinButtonErrorStaggerDelayMs = 33 +/** Animation duration of the "revert" phase of the error animation, on each PIN pad button. */ private const val pinButtonErrorRevertMs = 617 // Pin button motion spec: http://shortn/_9TTIG6SoEa diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index 2c4dc806f468..185a06c70f9e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close @@ -19,8 +20,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInteropFilter import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.ElementKey @@ -28,6 +31,7 @@ import com.android.compose.animation.scene.FixedSizeEdgeDetector import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.SceneTransitionLayout +import com.android.compose.animation.scene.SceneTransitionLayoutState import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.transitions @@ -56,6 +60,7 @@ val sceneTransitions = transitions { * This is a temporary container to allow the communal UI to use [SceneTransitionLayout] for gesture * handling and transitions before the full Flexiglass layout is ready. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun CommunalContainer( modifier: Modifier = Modifier, @@ -65,6 +70,7 @@ fun CommunalContainer( viewModel.currentScene .transform<CommunalSceneKey, SceneKey> { value -> value.toTransitionSceneKey() } .collectAsState(TransitionSceneKey.Blank) + val sceneTransitionLayoutState = remember { SceneTransitionLayoutState(currentScene) } // Don't show hub mode UI if keyguard is present. This is important since we're in the shade, // which can be opened from many locations. val isKeyguardShowing by viewModel.isKeyguardVisible.collectAsState(initial = false) @@ -75,32 +81,59 @@ fun CommunalContainer( return } - SceneTransitionLayout( - modifier = modifier.fillMaxSize(), - currentScene = currentScene, - onChangeScene = { sceneKey -> viewModel.onSceneChanged(sceneKey.toCommunalSceneKey()) }, - transitions = sceneTransitions, - edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize) - ) { - scene( - TransitionSceneKey.Blank, - userActions = - mapOf( - Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to TransitionSceneKey.Communal - ) + Box(modifier = modifier.fillMaxSize()) { + SceneTransitionLayout( + modifier = Modifier.fillMaxSize(), + currentScene = currentScene, + onChangeScene = { sceneKey -> viewModel.onSceneChanged(sceneKey.toCommunalSceneKey()) }, + transitions = sceneTransitions, + state = sceneTransitionLayoutState, + edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize) ) { - BlankScene { showSceneTransitionLayout = false } - } + scene( + TransitionSceneKey.Blank, + userActions = + mapOf( + Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to + TransitionSceneKey.Communal + ) + ) { + BlankScene { showSceneTransitionLayout = false } + } - scene( - TransitionSceneKey.Communal, - userActions = - mapOf( - Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TransitionSceneKey.Blank - ), - ) { - CommunalScene(viewModel, modifier = modifier) + scene( + TransitionSceneKey.Communal, + userActions = + mapOf( + Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to + TransitionSceneKey.Blank + ), + ) { + CommunalScene(viewModel, modifier = modifier) + } } + + // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't + // block touches anymore. + Box( + modifier = + Modifier.fillMaxSize() + // Offsetting to the left so that edge swipe to open the hub still works. This + // does mean that the very right edge of the hub won't refresh the screen + // timeout, but should be good enough for a temporary solution. + .offset(x = -ContainerDimensions.EdgeSwipeSize) + .pointerInteropFilter { + viewModel.onUserActivity() + if ( + sceneTransitionLayoutState.transitionState.currentScene == + TransitionSceneKey.Blank + ) { + viewModel.onOuterTouch(it) + return@pointerInteropFilter true + } + false + } + ) } } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index 651594c2d8f9..ca24d94070f9 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -30,15 +30,15 @@ import com.android.systemui.log.core.Logger import com.android.systemui.log.core.MessageBuffer import com.android.systemui.log.core.MessageInitializer import com.android.systemui.log.core.MessagePrinter -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockId -import com.android.systemui.plugins.ClockMetadata -import com.android.systemui.plugins.ClockProvider -import com.android.systemui.plugins.ClockProviderPlugin -import com.android.systemui.plugins.ClockSettings import com.android.systemui.plugins.PluginLifecycleManager import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginManager +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockId +import com.android.systemui.plugins.clocks.ClockMetadata +import com.android.systemui.plugins.clocks.ClockProvider +import com.android.systemui.plugins.clocks.ClockProviderPlugin +import com.android.systemui.plugins.clocks.ClockSettings import com.android.systemui.util.Assert import java.io.PrintWriter import java.util.concurrent.ConcurrentHashMap diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt index 42ba6431822e..141e1c13758c 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -25,16 +25,18 @@ import android.widget.FrameLayout import androidx.annotation.VisibleForTesting import com.android.systemui.customization.R import com.android.systemui.log.core.MessageBuffer -import com.android.systemui.plugins.ClockAnimations -import com.android.systemui.plugins.ClockConfig -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockEvents -import com.android.systemui.plugins.ClockFaceConfig -import com.android.systemui.plugins.ClockFaceController -import com.android.systemui.plugins.ClockFaceEvents -import com.android.systemui.plugins.ClockSettings -import com.android.systemui.plugins.DefaultClockFaceLayout -import com.android.systemui.plugins.WeatherData +import com.android.systemui.plugins.clocks.AlarmData +import com.android.systemui.plugins.clocks.ClockAnimations +import com.android.systemui.plugins.clocks.ClockConfig +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockEvents +import com.android.systemui.plugins.clocks.ClockFaceConfig +import com.android.systemui.plugins.clocks.ClockFaceController +import com.android.systemui.plugins.clocks.ClockFaceEvents +import com.android.systemui.plugins.clocks.ClockSettings +import com.android.systemui.plugins.clocks.DefaultClockFaceLayout +import com.android.systemui.plugins.clocks.WeatherData +import com.android.systemui.plugins.clocks.ZenData import java.io.PrintWriter import java.util.Locale import java.util.TimeZone @@ -53,6 +55,7 @@ class DefaultClockController( private val resources: Resources, private val settings: ClockSettings?, private val hasStepClockAnimation: Boolean = false, + private val migratedClocks: Boolean = false, ) : ClockController { override val smallClock: DefaultClockFaceController override val largeClock: LargeClockFaceController @@ -195,6 +198,10 @@ class DefaultClockController( } override fun recomputePadding(targetRegion: Rect?) { + // TODO(b/310989341): remove after changing migrate_clocks_to_blueprint to aconfig + if (migratedClocks) { + return + } // We center the view within the targetRegion instead of within the parent // view by computing the difference and adding that to the padding. val lp = view.getLayoutParams() as FrameLayout.LayoutParams @@ -251,6 +258,8 @@ class DefaultClockController( } override fun onWeatherDataChanged(data: WeatherData) {} + override fun onAlarmDataChanged(data: AlarmData) {} + override fun onZenDataChanged(data: ZenData) {} } open inner class DefaultClockAnimations( diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt index dd52e39488ac..a219be53bd1a 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -18,11 +18,11 @@ import android.content.res.Resources import android.graphics.drawable.Drawable import android.view.LayoutInflater import com.android.systemui.customization.R -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockId -import com.android.systemui.plugins.ClockMetadata -import com.android.systemui.plugins.ClockProvider -import com.android.systemui.plugins.ClockSettings +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockId +import com.android.systemui.plugins.clocks.ClockMetadata +import com.android.systemui.plugins.clocks.ClockProvider +import com.android.systemui.plugins.clocks.ClockSettings private val TAG = DefaultClockProvider::class.simpleName const val DEFAULT_CLOCK_ID = "DEFAULT" @@ -32,7 +32,8 @@ class DefaultClockProvider( val ctx: Context, val layoutInflater: LayoutInflater, val resources: Resources, - val hasStepClockAnimation: Boolean = false + val hasStepClockAnimation: Boolean = false, + val migratedClocks: Boolean = false ) : ClockProvider { override fun getClocks(): List<ClockMetadata> = listOf(ClockMetadata(DEFAULT_CLOCK_ID)) @@ -47,6 +48,7 @@ class DefaultClockProvider( resources, settings, hasStepClockAnimation, + migratedClocks, ) } diff --git a/packages/SystemUI/docs/clock-plugins.md b/packages/SystemUI/docs/clock-plugins.md index 9cb115a696c9..fee82dfcf2e3 100644 --- a/packages/SystemUI/docs/clock-plugins.md +++ b/packages/SystemUI/docs/clock-plugins.md @@ -12,7 +12,7 @@ responsible for maintaining the view within the hierarchy and propagating events clock controller. ### Clock Library Code -[ClockProvider and ClockController](../plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt) +[ClockProvider and ClockController](../plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt) serve as the interface between the lockscreen (or other host application) and the clock that is being rendered. Implementing these interfaces is the primary integration point for rendering clocks in SystemUI. Many of the methods have an empty default implementation and are optional for @@ -29,12 +29,12 @@ versions of android. The [ClockRegistry](../customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt) determines which clock should be shown, and handles creating them. It does this by maintaining a -list of [ClockProviders](../plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt) and +list of [ClockProviders](../plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt) and delegating work to them as appropriate. The DefaultClockProvider is compiled in so that it is guaranteed to be available, and additional ClockProviders are loaded at runtime via [PluginManager](../plugin_core/src/com/android/systemui/plugins/PluginManager.java). -[ClockPlugin](../plugin/src/com/android/systemui/plugins/ClockPlugin.java) is deprecated and no +[ClockPlugin](../plugin/src/com/android/systemui/plugins/clocks/ClockPlugin.java) is deprecated and no longer used by keyguard to render clocks. The host code has been disabled but most of it is still present in the source tree, although it will likely be removed in a later patch. diff --git a/packages/SystemUI/docs/plugin_hooks.md b/packages/SystemUI/docs/plugin_hooks.md index 6ce7ee08da81..bfccbac4767e 100644 --- a/packages/SystemUI/docs/plugin_hooks.md +++ b/packages/SystemUI/docs/plugin_hooks.md @@ -52,7 +52,7 @@ Expected interface: [NotificationSwipeActionHelper](/frameworks/base/packages/Sy Use: Control over swipes/input for notification views, can be used to control what happens when you swipe/long-press ### Action: com.android.systemui.action.PLUGIN_CLOCK_PROVIDER -Expected interface: [ClockProviderPlugin](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt) +Expected interface: [ClockProviderPlugin](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt) Use: Allows replacement of the keyguard main clock. See [additional Documentation](./clock-plugins.md). diff --git a/packages/SystemUI/docs/qs-tiles.md b/packages/SystemUI/docs/qs-tiles.md index bd0b4abbeb34..ee388ec8e5c5 100644 --- a/packages/SystemUI/docs/qs-tiles.md +++ b/packages/SystemUI/docs/qs-tiles.md @@ -4,25 +4,37 @@ ## About this document -This document is a more or less comprehensive summary of the state and infrastructure used by Quick Settings tiles. It provides descriptions about the lifecycle of a tile, how to create new tiles and how SystemUI manages and displays tiles, among other topics. +This document is a more or less comprehensive summary of the state and infrastructure used by Quick +Settings tiles. It provides descriptions about the lifecycle of a tile, how to create new tiles and +how SystemUI manages and displays tiles, among other topics. ## What are Quick Settings Tiles? -Quick Settings (from now on, QS) is the expanded panel that contains shortcuts for the user to toggle many settings. This is opened by expanding the notification drawer twice (or once when phone is locked). Quick Quick Settings (QQS) is the smaller panel that appears on top of the notifications before expanding twice and contains some of the toggles with no secondary line. +Quick Settings (from now on, QS) is the expanded panel that contains shortcuts for the user to +toggle many settings. This is opened by expanding the notification drawer twice (or once when phone +is locked). Quick Quick Settings (QQS) is the smaller panel that appears on top of the notifications +before expanding twice and contains some of the toggles with no secondary line. -Each of these toggles that appear either in QS or QQS are called Quick Settings Tiles (or tiles for short). They allow the user to enable or disable settings quickly and sometimes provides access to more comprehensive settings pages. +Each of these toggles that appear either in QS or QQS are called Quick Settings Tiles (or tiles for +short). They allow the user to enable or disable settings quickly and sometimes provides access to +more comprehensive settings pages. The following image shows QQS on the left and QS on the right, with the tiles highlighted.  -QS Tiles usually depend on one or more Controllers that bind the tile with the necessary service. Controllers are obtained by the backend and used for communication between the user and the device. +QS Tiles usually depend on one or more Controllers that bind the tile with the necessary service. +Controllers are obtained by the backend and used for communication between the user and the device. ### A note on multi-user support -All the classes described in this document that live inside SystemUI are only instantiated in the process of user 0. The different controllers that back the QS Tiles (also instantiated just in user 0) are user aware and provide an illusion of different instances for different users. +All the classes described in this document that live inside SystemUI are only instantiated in the +process of user 0. The different controllers that back the QS Tiles (also instantiated just in user +0) are user aware and provide an illusion of different instances for different users. -For an example on this, see [`RotationLockController`](/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java). This controller for the `RotationLockTile` listens to changes in all users. +For an example on this, +see [`RotationLockController`](/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java). +This controller for the `RotationLockTile` listens to changes in all users. ## What are tiles made of? @@ -30,104 +42,161 @@ For an example on this, see [`RotationLockController`](/packages/SystemUI/src/co QS Tiles are composed of the following backend classes. -* [`QSTile`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java): Interface providing common behavior for all Tiles. This class also contains some useful utility classes needed for the tiles. - * `Icon`: Defines the basic interface for an icon as used by the tiles. - * `State`: Encapsulates the state of the Tile in order to communicate between the backend and the UI. -* [`QSTileImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java): Abstract implementation of `QSTile`, providing basic common behavior for all tiles. Also implements extensions for different types of `Icon`. All tiles currently defined in SystemUI subclass from this implementation. -* [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles): Each tile from SystemUI is defined here by a class that extends `QSTileImpl`. These implementations connect to corresponding controllers. The controllers serve two purposes: - * track the state of the device and notify the tile when a change has occurred (for example, bluetooth connected to a device) - * accept actions from the tiles to modify the state of the phone (for example, enablind and disabling wifi). -* [`CustomTile`](/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java): Equivalent to the tiles in the previous item, but used for 3rd party tiles. In depth information to be found in [`CustomTile`](#customtile) - -All the elements in SystemUI that work with tiles operate on `QSTile` or the interfaces defined in it. However, all the current implementations of tiles in SystemUI subclass from `QSTileImpl`, as it takes care of many common situations. Throughout this document, we will focus on `QSTileImpl` as examples of tiles. - -The interfaces in `QSTile` as well as other interfaces described in this document can be used to implement plugins to add additional tiles or different behavior. For more information, see [plugins.md](plugins.md) +* [`QSTile`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java): Interface + providing common behavior for all Tiles. This class also contains some useful utility classes + needed for the tiles. + * `Icon`: Defines the basic interface for an icon as used by the tiles. + * `State`: Encapsulates the state of the Tile in order to communicate between the backend and + the UI. +* [`QSTileImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java): Abstract + implementation of `QSTile`, providing basic common behavior for all tiles. Also implements + extensions for different types of `Icon`. All tiles currently defined in SystemUI subclass from + this implementation. +* [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles): + Each tile from SystemUI is defined here by a class that extends `QSTileImpl`. These + implementations connect to corresponding controllers. The controllers serve two purposes: + * track the state of the device and notify the tile when a change has occurred (for example, + bluetooth connected to a device) + * accept actions from the tiles to modify the state of the phone (for example, enablind and + disabling wifi). +* [`CustomTile`](/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java): + Equivalent to the tiles in the previous item, but used for 3rd party tiles. In depth information + to be found in [`CustomTile`](#customtile) + +All the elements in SystemUI that work with tiles operate on `QSTile` or the interfaces defined in +it. However, all the current implementations of tiles in SystemUI subclass from `QSTileImpl`, as it +takes care of many common situations. Throughout this document, we will focus on `QSTileImpl` as +examples of tiles. + +The interfaces in `QSTile` as well as other interfaces described in this document can be used to +implement plugins to add additional tiles or different behavior. For more information, +see [plugins.md](plugins.md) #### Tile State -Each tile has an associated `State` object that is used to communicate information to the corresponding view. The base class `State` has (among others) the following fields: +Each tile has an associated `State` object that is used to communicate information to the +corresponding view. The base class `State` has (among others) the following fields: * **`state`**: one of `Tile#STATE_UNAVAILABLE`, `Tile#STATE_ACTIVE`, `Tile#STATE_INACTIVE`. * **`icon`**; icon to display. It may depend on the current state. * **`label`**: usually the name of the tile. * **`secondaryLabel`**: text to display in a second line. Usually extra state information. * **`contentDescription`** -* **`expandedAccessibilityClassName`**: usually `Switch.class.getName()` for boolean Tiles. This will make screen readers read the current state of the tile as well as the new state when it's toggled. For this, the Tile has to use `BooleanState`. -* **`handlesLongClick`**: whether the Tile will handle long click. If it won't, it should be set to `false` so it will not be announced for accessibility. +* **`expandedAccessibilityClassName`**: usually `Switch.class.getName()` for boolean Tiles. This + will make screen readers read the current state of the tile as well as the new state when it's + toggled. For this, the Tile has to use `BooleanState`. +* **`handlesLongClick`**: whether the Tile will handle long click. If it won't, it should be set + to `false` so it will not be announced for accessibility. Setting any of these fields during `QSTileImpl#handleUpdateState` will update the UI after it. -Additionally. `BooleanState` has a `value` boolean field that usually would be set to `state == Tile#STATE_ACTIVE`. This is used by accessibility services along with `expandedAccessibilityClassName`. +Additionally. `BooleanState` has a `value` boolean field that usually would be set +to `state == Tile#STATE_ACTIVE`. This is used by accessibility services along +with `expandedAccessibilityClassName`. #### SystemUI tiles -Each tile defined in SystemUI extends `QSTileImpl`. This abstract class implements some common functions and leaves others to be implemented by each tile, in particular those that determine how to handle different events (refresh, click, etc.). +Each tile defined in SystemUI extends `QSTileImpl`. This abstract class implements some common +functions and leaves others to be implemented by each tile, in particular those that determine how +to handle different events (refresh, click, etc.). -For more information on how to implement a tile in SystemUI, see [Implementing a SystemUI tile](#implementing-a-systemui-tile). +For more information on how to implement a tile in SystemUI, +see [Implementing a SystemUI tile](#implementing-a-systemui-tile). ### Tile views -Each Tile has a couple of associated views for displaying it in QS and QQS. These views are updated after the backend updates the `State` using `QSTileImpl#handleUpdateState`. - -* **[`QSTileView`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java)**: Abstract class that provides basic Tile functionality. These allows external [Factories](#qsfactory) to create Tiles. -* **[`QSTileViewImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.java)**: Implementation of `QSTileView`. It takes care of the following: - * Holding the icon - * Background color and shape - * Ripple - * Click listening - * Labels +Each Tile has a couple of associated views for displaying it in QS and QQS. These views are updated +after the backend updates the `State` using `QSTileImpl#handleUpdateState`. + +* **[`QSTileView`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java)**: + Abstract class that provides basic Tile functionality. These allows + external [Factories](#qsfactory) to create Tiles. +* **[`QSTileViewImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.java)**: + Implementation of `QSTileView`. It takes care of the following: + * Holding the icon + * Background color and shape + * Ripple + * Click listening + * Labels * **[`QSIconView`](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSIconView.java)** * **[`QSIconViewImpl`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java)** #### QSIconView and QSIconViewImpl -`QSIconView` is an interface that define the basic actions that icons have to respond to. Its base implementation in SystemUI is `QSIconViewImpl` and it and its subclasses are used by all QS tiles. +`QSIconView` is an interface that define the basic actions that icons have to respond to. Its base +implementation in SystemUI is `QSIconViewImpl` and it and its subclasses are used by all QS tiles. -This `ViewGroup` is a container for the icon used in each tile. It has methods to apply the current `State` of the tile, modifying the icon (color and animations). Classes that inherit from this can add other details that are modified when the `State` changes. +This `ViewGroup` is a container for the icon used in each tile. It has methods to apply the +current `State` of the tile, modifying the icon (color and animations). Classes that inherit from +this can add other details that are modified when the `State` changes. -Each `QSTileImpl` can specify that they use a particular implementation of this class when creating an icon. +Each `QSTileImpl` can specify that they use a particular implementation of this class when creating +an icon. ### How are the backend and the views related? -The backend of the tiles (all the implementations of `QSTileImpl`) communicate with the views by using a `State`. The backend populates the state, and then the view maps the state to a visual representation. +The backend of the tiles (all the implementations of `QSTileImpl`) communicate with the views by +using a `State`. The backend populates the state, and then the view maps the state to a visual +representation. -It's important to notice that the state of the tile (internal or visual) is not directly modified by a user action like clicking on the tile. Instead, acting on a tile produces internal state changes on the device, and those trigger the changes on the tile state and UI. +It's important to notice that the state of the tile (internal or visual) is not directly modified by +a user action like clicking on the tile. Instead, acting on a tile produces internal state changes +on the device, and those trigger the changes on the tile state and UI. -When a container for tiles (`QuickQSPanel` or `QSPanel`) has to display tiles, they create a [`TileRecord`](/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java). This associates the corresponding `QSTile` with its `QSTileView`, doing the following: +When a container for tiles (`QuickQSPanel` or `QSPanel`) has to display tiles, they create +a [`TileRecord`](/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java). This associates the +corresponding `QSTile` with its `QSTileView`, doing the following: * Create the corresponding `QSTileView` to display in that container. -* Create a callback for `QSTile` to call when its state changes. Note that a single tile will normally have up to two callbacks: one for QS and one for QQS. +* Create a callback for `QSTile` to call when its state changes. Note that a single tile will + normally have up to two callbacks: one for QS and one for QQS. #### Life of a tile click -This is a brief run-down of what happens when a user clicks on a tile. Internal changes on the device (for example, changes from Settings) will trigger this process starting in step 3. Throughout this section, we assume that we are dealing with a `QSTileImpl`. +This is a brief run-down of what happens when a user clicks on a tile. Internal changes on the +device (for example, changes from Settings) will trigger this process starting in step 3. Throughout +this section, we assume that we are dealing with a `QSTileImpl`. 1. User clicks on tile. The following calls happen in sequence: - 1. `QSTileViewImpl#onClickListener`. - 2. `QSTile#click`. - 3. `QSTileImpl#handleClick`. This last call sets the new state for the device by using the associated controller. + 1. `QSTileViewImpl#onClickListener`. + 2. `QSTile#click`. + 3. `QSTileImpl#handleClick`. This last call sets the new state for the device by using the + associated controller. 2. State in the device changes. This is normally outside of SystemUI's control. -3. Controller receives a callback (or `Intent`) indicating the change in the device. The following calls happen: - 1. `QSTileImpl#refreshState`, maybe passing an object with necessary information regarding the new state. - 2. `QSTileImpl#handleRefreshState` -4. `QSTileImpl#handleUpdateState` is called to update the state with the new information. This information can be obtained both from the `Object` passed to `refreshState` as well as from the controller. -5. If the state has changed (in at least one element), `QSTileImpl#handleStateChanged` is called. This will trigger a call to all the associated `QSTile.Callback#onStateChanged`, passing the new `State`. -6. `QSTileView#onStateChanged` is called and this calls `QSTileView#handleStateChanged`. This method maps the state into the view: - * The tile colors change to match the new state. - * `QSIconView.setIcon` is called to apply the correct state to the icon and the correct icon to the view. - * The tile labels change to match the new state. +3. Controller receives a callback (or `Intent`) indicating the change in the device. The following + calls happen: + 1. `QSTileImpl#refreshState`, maybe passing an object with necessary information regarding the + new state. + 2. `QSTileImpl#handleRefreshState` +4. `QSTileImpl#handleUpdateState` is called to update the state with the new information. This + information can be obtained both from the `Object` passed to `refreshState` as well as from the + controller. +5. If the state has changed (in at least one element), `QSTileImpl#handleStateChanged` is called. + This will trigger a call to all the associated `QSTile.Callback#onStateChanged`, passing the + new `State`. +6. `QSTileView#onStateChanged` is called and this calls `QSTileView#handleStateChanged`. This method + maps the state into the view: + * The tile colors change to match the new state. + * `QSIconView.setIcon` is called to apply the correct state to the icon and the correct icon to + the view. + * The tile labels change to match the new state. ## Third party tiles (TileService) -A third party tile is any Quick Settings tile that is provided by an app (that's not SystemUI). This is implemented by developers subclassing [`TileService`](/core/java/android/service/quicksettings/TileService.java) and interacting with its API. +A third party tile is any Quick Settings tile that is provided by an app (that's not SystemUI). This +is implemented by developers +subclassing [`TileService`](/core/java/android/service/quicksettings/TileService.java) and +interacting with its API. ### API classes -The classes that define the public API are in [core/java/android/service/quicksettings](/core/java/android/service/quicksettings). +The classes that define the public API are +in [core/java/android/service/quicksettings](/core/java/android/service/quicksettings). #### Tile -Parcelable class used to communicate information about the state between the external app and SystemUI. The class supports the following fields: +Parcelable class used to communicate information about the state between the external app and +SystemUI. The class supports the following fields: * Label * Subtitle @@ -135,18 +204,25 @@ Parcelable class used to communicate information about the state between the ext * State (`Tile#STATE_ACTIVE`, `Tile#STATE_INACTIVE`, `Tile#STATE_UNAVAILABLE`) * Content description -Additionally, it provides a method to notify SystemUI that the information may have changed and the tile should be refreshed. +Additionally, it provides a method to notify SystemUI that the information may have changed and the +tile should be refreshed. #### TileService -This is an abstract Service that needs to be implemented by the developer. The Service manifest must have the permission `android.permission.BIND_QUICK_SETTINGS_TILE` and must respond to the action `android.service.quicksettings.action.QS_TILE`. This will allow SystemUI to find the available tiles and display them to the user. +This is an abstract Service that needs to be implemented by the developer. The Service manifest must +have the permission `android.permission.BIND_QUICK_SETTINGS_TILE` and must respond to the +action `android.service.quicksettings.action.QS_TILE`. This will allow SystemUI to find the +available tiles and display them to the user. -The implementer is responsible for creating the methods that will respond to the following calls from SystemUI: +The implementer is responsible for creating the methods that will respond to the following calls +from SystemUI: * **`onTileAdded`**: called when the tile is added to QS. * **`onTileRemoved`**: called when the tile is removed from QS. -* **`onStartListening`**: called when QS is opened and the tile is showing. This marks the start of the window when calling `getQSTile` is safe and will provide the correct object. -* **`onStopListening`**: called when QS is closed or the tile is no longer visible by the user. This marks the end of the window described in `onStartListening`. +* **`onStartListening`**: called when QS is opened and the tile is showing. This marks the start of + the window when calling `getQSTile` is safe and will provide the correct object. +* **`onStopListening`**: called when QS is closed or the tile is no longer visible by the user. This + marks the end of the window described in `onStartListening`. * **`onClick`**: called when the user clicks on the tile. Additionally, the following final methods are provided: @@ -155,7 +231,8 @@ Additionally, the following final methods are provided: public final Tile getQsTile() ``` - Provides the tile object that can be modified. This should only be called in the window between `onStartListening` and `onStopListening`. + Provides the tile object that can be modified. This should only be called in the window + between `onStartListening` and `onStopListening`. * ```java public final boolean isLocked() @@ -163,13 +240,15 @@ Additionally, the following final methods are provided: public final boolean isSecure() ``` - Provide information about the secure state of the device. This can be used by the tile to accept or reject actions on the tile. + Provide information about the secure state of the device. This can be used by the tile to accept + or reject actions on the tile. * ```java public final void unlockAndRun(Runnable) ``` - May prompt the user to unlock the device if locked. Once the device is unlocked, it runs the given `Runnable`. + May prompt the user to unlock the device if locked. Once the device is unlocked, it runs the + given `Runnable`. * ```java public final void showDialog(Dialog) @@ -179,162 +258,272 @@ Additionally, the following final methods are provided: ##### Binding -When the Service is bound, a callback Binder is provided by SystemUI for all the callbacks, as well as an identifier token (`Binder`). This token is used in the callbacks to identify this `TileService` and match it to the corresponding tile. +When the Service is bound, a callback Binder is provided by SystemUI for all the callbacks, as well +as an identifier token (`Binder`). This token is used in the callbacks to identify +this `TileService` and match it to the corresponding tile. -The tiles are bound once immediately on creation. After that, the tile is bound whenever it should start listening. When the panels are closed, and the tile is set to stop listening, it will be unbound after a delay of `TileServiceManager#UNBIND_DELAY` (30s), if it's not set to listening again. +The tiles are bound once immediately on creation. After that, the tile is bound whenever it should +start listening. When the panels are closed, and the tile is set to stop listening, it will be +unbound after a delay of `TileServiceManager#UNBIND_DELAY` (30s), if it's not set to listening +again. ##### Active tile -A `TileService` can be declared as an active tile by adding specific meta-data to its manifest (see [TileService#META_DATA_ACTIVE_TILE](https://developer.android.com/reference/android/service/quicksettings/TileService#META_DATA_ACTIVE_TILE)). In this case, it won't receive a call of `onStartListening` when QS is opened. Instead, the tile must request listening status by making a call to `TileService#requestListeningState` with its component name. This will initiate a window that will last until the tile is updated. +A `TileService` can be declared as an active tile by adding specific meta-data to its manifest ( +see [TileService#META_DATA_ACTIVE_TILE](https://developer.android.com/reference/android/service/quicksettings/TileService#META_DATA_ACTIVE_TILE)). +In this case, it won't receive a call of `onStartListening` when QS is opened. Instead, the tile +must request listening status by making a call to `TileService#requestListeningState` with its +component name. This will initiate a window that will last until the tile is updated. The tile will also be granted listening status if it's clicked by the user. ### SystemUI classes -The following sections describe the classes that live in SystemUI to support third party tiles. These classes live in [SystemUI/src/com/android/systemui/qs/external](/packages/SystemUI/src/com/android/systemui/qs/external/) +The following sections describe the classes that live in SystemUI to support third party tiles. +These classes live +in [SystemUI/src/com/android/systemui/qs/external](/packages/SystemUI/src/com/android/systemui/qs/external/) #### CustomTile -This class is an subclass of `QSTileImpl` to be used with third party tiles. It provides similar behavior to SystemUI tiles as well as handling exclusive behavior like lifting default icons and labels from the application manifest. +This class is an subclass of `QSTileImpl` to be used with third party tiles. It provides similar +behavior to SystemUI tiles as well as handling exclusive behavior like lifting default icons and +labels from the application manifest. #### TileServices -This class is the central controller for all tile services that are currently in Quick Settings as well as provides the support for starting new ones. It is also an implementation of the `Binder` that receives all calls from current `TileService` components and dispatches them to SystemUI or the corresponding `CustomTile`. +This class is the central controller for all tile services that are currently in Quick Settings as +well as provides the support for starting new ones. It is also an implementation of the `Binder` +that receives all calls from current `TileService` components and dispatches them to SystemUI or the +corresponding `CustomTile`. -Whenever a binder call is made to this class, it matches the corresponding token assigned to the `TileService` with the `ComponentName` and verifies that the call comes from the right UID to prevent spoofing. +Whenever a binder call is made to this class, it matches the corresponding token assigned to +the `TileService` with the `ComponentName` and verifies that the call comes from the right UID to +prevent spoofing. -As this class is the only one that's aware of every `TileService` that's currently bound, it is also in charge of requesting some to be unbound whenever there is a low memory situation. +As this class is the only one that's aware of every `TileService` that's currently bound, it is also +in charge of requesting some to be unbound whenever there is a low memory situation. #### TileLifecycleManager -This class is in charge of binding and unbinding to a particular `TileService` when necessary, as well as sending the corresponding binder calls. It does not decide whether the tile should be bound or unbound, unless it's requested to process a message. It additionally handles errors in the `Binder` as well as changes in the corresponding component (like updates and enable/disable). +This class is in charge of binding and unbinding to a particular `TileService` when necessary, as +well as sending the corresponding binder calls. It does not decide whether the tile should be bound +or unbound, unless it's requested to process a message. It additionally handles errors in +the `Binder` as well as changes in the corresponding component (like updates and enable/disable). -The class has a queue that stores requests while the service is not bound, to be processed as soon as the service is bound. +The class has a queue that stores requests while the service is not bound, to be processed as soon +as the service is bound. -Each `TileService` gets assigned an exclusive `TileLifecycleManager` when its corresponding tile is added to the set of current ones and kept as long as the tile is available to the user. +Each `TileService` gets assigned an exclusive `TileLifecycleManager` when its corresponding tile is +added to the set of current ones and kept as long as the tile is available to the user. #### TileServiceManager -Each instance of this class is an intermediary between the `TileServices` controller and a `TileLifecycleManager` corresponding to a particular `TileService`. +Each instance of this class is an intermediary between the `TileServices` controller and +a `TileLifecycleManager` corresponding to a particular `TileService`. This class handles management of the service, including: * Deciding when to bind and unbind, requesting it to the `TileLifecycleManager`. * Relaying messages to the `TileService` through the `TileLifecycleManager`. * Determining the service's bind priority (to deal with OOM situations). -* Detecting when the package/component has been removed in order to remove the tile and references to it. +* Detecting when the package/component has been removed in order to remove the tile and references + to it. ## How are tiles created/instantiated? -This section describes the classes that aid in the creation of each tile as well as the complete lifecycle of a tile. First we describe two important interfaces/classes. +This section describes the classes that aid in the creation of each tile as well as the complete +lifecycle of a tile. The current system makes use of flows to propagate information downstream. + +First we describe three important interfaces/classes. + +### TileSpecRepository (and UserTileSpecRepository) -### QSTileHost +These classes keep track of the current tiles for each user, as a list of Tile specs. While the +device is running, this is the source of truth of tiles for that user. -This class keeps track of the tiles selected by the current user (backed in the Secure Setting `sysui_qs_tiles`) to be displayed in Quick Settings. Whenever the value of this setting changes (or on device start), the whole list of tiles is read. This is compared with the current tiles, destroying unnecessary ones and creating needed ones. +The list is persisted to `Settings.Secure` every time it changes so it will be available upon +restart or backup. In particular, any changes in the secure setting while this repository is +tracking the list of tiles will be reverted. -It additionally provides a point of communication between the tiles and the StatusBar, for example to open it and collapse it. And a way for the StatusBar service to add tiles (only works for `CustomTile`). +The class provides a `Flow<List<TileSpec>>` for each user that can be collected to keep track of the +current list of tiles. #### Tile specs -Each single tile is identified by a spec, which is a unique String for that type of tile. The current tiles are stored as a Setting string of comma separated values of these specs. Additionally, the default tiles (that appear on a fresh system) configuration value is stored likewise. +Each single tile is identified by a spec, which is a unique String for that type of tile. The +current tiles are stored as a Setting string of comma separated values of these specs. Additionally, +the default tiles (that appear on a fresh system) configuration value is stored likewise. + +SystemUI tile specs are usually a single simple word identifying the tile (like `wifi` +or `battery`). Custom tile specs are always a string of the form `custom(...)` where the ellipsis is +a flattened String representing the `ComponentName` for the corresponding `TileService`. + +We represent these internally using a `TileSpec` class that can distinguish between platform tiles +and custom tiles. + +### CurrentTilesInteractor + +This class consumes the lists of specs provided by `TileSpecRepository` and produces a +`Flow<List<Pair<TileSpec, QSTile>>>` with the current tiles for the current user. + +Internally, whenever the list of tiles changes, the following operation is performed: +* Properly dispose of tiles that are no longer in the current list. +* Properly dispose of tiles that are no longer available. +* If the user has changed, relay the new user to the platform tiles and destroy any custom tiles. +* Create new tiles as needed, disposing those that are not available or when the corresponding + service does not exist. +* Reorder the tiles. -SystemUI tile specs are usually a single simple word identifying the tile (like `wifi` or `battery`). Custom tile specs are always a string of the form `custom(...)` where the ellipsis is a flattened String representing the `ComponentName` for the corresponding `TileService`. +Also, when this is completed, we pass the final list back to the repository so it matches the +correct list of tiles. ### QSFactory -This interface provides a way of creating tiles and views from a spec. It can be used in plugins to provide different definitions for tiles. +This interface provides a way of creating tiles and views from a spec. It can be used in plugins to +provide different definitions for tiles. -In SystemUI there is only one implementation of this factory and that is the default factory (`QSFactoryImpl`) in `QSTileHost`. +In SystemUI there is only one implementation of this factory and that is the default +factory (`QSFactoryImpl`) in `CurrentTilesInteractorImpl`. #### QSFactoryImpl -This class implements two methods as specified in the `QSFactory` interface: +This class implements the following method as specified in the `QSFactory` interface: * ```java public QSTile createTile(String) ``` - Creates a tile (backend) from a given spec. The factory has providers for all of the SystemUI tiles, returning one when the correct spec is used. + Creates a tile (backend) from a given spec. The factory has a map with providers for all of the + SystemUI tiles, returning one when the correct spec is used. - If the spec is not recognized but it has the `custom(` prefix, the factory tries to create a `CustomTile` for the component in the spec. This could fail (the component is not a valid `TileService` or is not enabled) and will be detected later when the tile is polled to determine if it's available. + If the spec is not recognized but it has the `custom(` prefix, the factory tries to create + a `CustomTile` for the component in the spec. -* ```java - public QSTileView createTileView(QSTile, boolean) - ``` - - Creates a view for the corresponding `QSTile`. The second parameter determines if the view that is created should be a collapsed one (for using in QQS) or not (for using in QS). + As part of filtering not valid tiles, custom tiles that don't have a corresponding valid service + component are never instantiated. ### Lifecycle of a Tile -We describe first the parts of the lifecycle that are common to SystemUI tiles and third party tiles. Following that, there will be a section with the steps that are exclusive to third party tiles. - -1. The tile is added through the QS customizer by the user. This will immediately save the new list of tile specs to the Secure Setting `sysui_qs_tiles`. This step could also happend if `StatusBar` adds tiles (either through adb, or through its service interface as with the `DevelopmentTiles`). -2. This triggers a "setting changed" that is caught by `QSTileHost`. This class processes the new value of the setting and finds out that there is a new spec in the list. Alternatively, when the device is booted, all tiles in the setting are considered as "new". -3. `QSTileHost` calls all the available `QSFactory` classes that it has registered in order to find the first one that will be able to create a tile with that spec. Assume that `QSFactoryImpl` managed to create the tile, which is some implementation of `QSTile` (either a SystemUI subclass of `QSTileImpl` or a `CustomTile`). If the tile is available, it's stored in a map and things proceed forward. -4. `QSTileHost` calls its callbacks indicating that the tiles have changed. In particular, `QSPanel` and `QuickQSPanel` receive this call with the full list of tiles. We will focus on these two classes. -5. For each tile in this list, a `QSTileView` is created (collapsed or expanded) and attached to a `TileRecord` containing the tile backend and the view. Additionally: - * a callback is attached to the tile to communicate between the backend and the view or the panel. +We describe first the parts of the lifecycle that are common to SystemUI tiles and third party +tiles. Following that, there will be a section with the steps that are exclusive to third party +tiles. + +1. The tile is added through the QS customizer by the user. This will send the new list of tiles to + `TileSpecRepository` which will update its internal state and also store the new value in the + secure setting `sysui_qs_tiles`. This step could also happen if `StatusBar` adds tiles (either + through adb, or through its service interface as with the `DevelopmentTiles`). +2. This updates the flow that `CurrentTilesInteractor` is collecting from, triggering the process + described above. +3. `CurrentTilesInteractor` calls the available `QSFactory` classes in order to find one that will + be able to create a tile with that spec. Assuming that `QSFactoryImpl` managed to create the + tile, which is some implementation of `QSTile` (either a SystemUI subclass + of `QSTileImpl` or a `CustomTile`) it will be added to the current list. + If the tile is available, it's stored in a map and things proceed forward. +4. `CurrentTilesInteractor` updates its flow and classes collecting from it will be notified of the + change. In particular, `QSPanel` and `QuickQSPanel` receive this call with the full list of + tiles. We will focus on these two classes. +5. For each tile in this list, a `QSTileView` is created (collapsed or expanded) and attached to + a `TileRecord` containing the tile backend and the view. Additionally: + * a callback is attached to the tile to communicate between the backend and the view or the + panel. * the click listeners in the tile are attached to those of the view. 6. The tile view is added to the corresponding layout. -When the tile is removed from the list of current tiles, all these classes are properly disposed including removing the callbacks and making sure that the backends remove themselves from the controllers they were listening to. +When the tile is removed from the list of current tiles, all these classes are properly disposed +including removing the callbacks and making sure that the backends remove themselves from the +controllers they were listening to. #### Lifecycle of a CustomTile -In step 3 of the previous process, when a `CustomTile` is created, additional steps are taken to ensure the proper binding to the service as described in [Third party tiles (TileService)](#third-party-tiles-tileservice). +In step 3 of the previous process, when a `CustomTile` is created, additional steps are taken to +ensure the proper binding to the service as described +in [Third party tiles (TileService)](#third-party-tiles-tileservice). -1. The `CustomTile` obtains the `TileServices` class from the `QSTileHost` and request the creation of a `TileServiceManager` with its token. As the spec for the `CustomTile` contains the `ComponentName` of the associated service, this can be used to bind to it. -2. The `TileServiceManager` creates its own `TileLifecycleManager` to take care of binding to the service. -3. `TileServices` creates maps between the token, the `CustomTile`, the `TileServiceManager`, the token and the `ComponentName`. +1. The `CustomTile` obtains the `TileServices` class from the `QSTileHost` and request the creation + of a `TileServiceManager` with its token. As the spec for the `CustomTile` contains + the `ComponentName` of the associated service, this can be used to bind to it. +2. The `TileServiceManager` creates its own `TileLifecycleManager` to take care of binding to the + service. +3. `TileServices` creates maps between the token, the `CustomTile`, the `TileServiceManager`, the + token and the `ComponentName`. ## Implementing a tile -This section describes necessary and recommended steps when implementing a Quick Settings tile. Some of them are optional and depend on the requirements of the tile. +This section describes necessary and recommended steps when implementing a Quick Settings tile. Some +of them are optional and depend on the requirements of the tile. ### Implementing a SystemUI tile -1. Create a class (preferably in [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles)) implementing `QSTileImpl` with a particular type of `State` as a parameter. -2. Create an injectable constructor taking a `QSHost` and whichever classes are needed for the tile's operation. Normally this would be other SystemUI controllers. -3. Implement the methods described in [Abstract methods in QSTileImpl](#abstract-methods-in-qstileimpl). Look at other tiles for help. Some considerations to have in mind: - * If the tile will not support long click (like the `FlashlightTile`), set `state.handlesLongClick` to `false` (maybe in `newTileState`). +1. Create a class (preferably + in [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles)) + implementing `QSTileImpl` with a particular type of `State` as a parameter. +2. Create an injectable constructor taking a `QSHost` and whichever classes are needed for the + tile's operation. Normally this would be other SystemUI controllers. +3. Implement the methods described + in [Abstract methods in QSTileImpl](#abstract-methods-in-qstileimpl). Look at other tiles for + help. Some considerations to have in mind: + * If the tile will not support long click (like the `FlashlightTile`), + set `state.handlesLongClick` to `false` (maybe in `newTileState`). * Changes to the tile state (either from controllers or from clicks) should call `refreshState`. - * Use only `handleUpdateState` to modify the values of the state to the new ones. This can be done by polling controllers or through the `arg` parameter. - * If the controller is not a `CallbackController`, respond to `handleSetListening` by attaching/dettaching from controllers. + * Use only `handleUpdateState` to modify the values of the state to the new ones. This can be + done by polling controllers or through the `arg` parameter. + * If the controller is not a `CallbackController`, respond to `handleSetListening` by + attaching/dettaching from controllers. * Implement `isAvailable` so the tile will not be created when it's not necessary. -4. Either create a new feature module or find an existing related feature module and add the following binding method: +4. Either create a new feature module or find an existing related feature module and add the + following binding method: * ```kotlin @Binds @IntoMap @StringKey(YourNewTile.TILE_SPEC) // A unique word that will map to YourNewTile fun bindYourNewTile(yourNewTile: YourNewTile): QSTileImpl<*> ``` -5. In [SystemUI/res/values/config.xml](/packages/SystemUI/res/values/config.xml), modify `quick_settings_tiles_stock` and add the spec defined in the previous step. If necessary, add it also to `quick_settings_tiles_default`. The first one contains a list of all the tiles that SystemUI knows how to create (to show to the user in the customization screen). The second one contains only the default tiles that the user will experience on a fresh boot or after they reset their tiles. -6. In [SystemUI/res/values/tiles_states_strings.xml](/packages/SystemUI/res/values/tiles_states_strings.xml), add a new array for your tile. The name has to be `tile_states_<spec>`. Use a good description to help the translators. -7. In [`SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt), add a new element to the map in `SubtitleArrayMapping` corresponding to the resource created in the previous step. +5. In [SystemUI/res/values/config.xml](/packages/SystemUI/res/values/config.xml), + modify `quick_settings_tiles_stock` and add the spec defined in the previous step. If necessary, + add it also to `quick_settings_tiles_default`. The first one contains a list of all the tiles + that SystemUI knows how to create (to show to the user in the customization screen). The second + one contains only the default tiles that the user will experience on a fresh boot or after they + reset their tiles. +6. In [SystemUI/res/values/tiles_states_strings.xml](/packages/SystemUI/res/values/tiles_states_strings.xml), +add a new array for your tile. The name has to be `tile_states_<spec>`. Use a good description to +help the translators. +7. In [`SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt`](/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt), +add a new element to the map in `SubtitleArrayMapping` corresponding to the resource created in the +previous step. #### Abstract methods in QSTileImpl -Following are methods that need to be implemented when creating a new SystemUI tile. `TState` is a type variable of type `State`. +Following are methods that need to be implemented when creating a new SystemUI tile. `TState` is a +type variable of type `State`. * ```java public TState newTileState() ``` - Creates a new `State` for this tile to use. Each time the state changes, it is copied into a new one and the corresponding fields are modified. The framework provides `State`, `BooleanState` (has an on and off state and provides this as a content description), `SignalState` (`BooleanState` with `activityIn` and `activityOut`), and `SlashState` (can be rotated or slashed through). + Creates a new `State` for this tile to use. Each time the state changes, it is copied into a new + one and the corresponding fields are modified. The framework provides `State`, `BooleanState` (has + an on and off state and provides this as a content description), `SignalState` (`BooleanState` + with `activityIn` and `activityOut`), and `SlashState` (can be rotated or slashed through). - If a tile has special behavior (no long click, no ripple), it can be set in its state here. + If a tile has special behavior (no long click, no ripple), it can be set in its state here. * ```java public void handleSetListening(boolean) ``` - Initiates or terminates listening behavior, like listening to Callbacks from controllers. This gets triggered when QS is expanded or collapsed (i.e., when the tile is visible and actionable). Most tiles (like `WifiTile`) do not implement this. Instead, Tiles are LifecycleOwner and are marked as `RESUMED` or `DESTROYED` in `QSTileImpl#handleListening` and handled as part of the lifecycle of [CallbackController](/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java) + Initiates or terminates listening behavior, like listening to Callbacks from controllers. This + gets triggered when QS is expanded or collapsed (i.e., when the tile is visible and actionable). + Most tiles (like `WifiTile`) do not implement this. Instead, Tiles are LifecycleOwner and are + marked as `RESUMED` or `DESTROYED` in `QSTileImpl#handleListening` and handled as part of the + lifecycle + of [CallbackController](/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java) * ```java public QSIconView createTileView(Context) ``` - Allows a Tile to use a `QSIconView` different from `QSIconViewImpl` (see [Tile views](#tile-views)), which is the default defined in `QSTileImpl` + Allows a Tile to use a `QSIconView` different from `QSIconViewImpl` ( + see [Tile views](#tile-views)), which is the default defined in `QSTileImpl` * ```java public Intent getLongClickIntent() @@ -350,36 +539,137 @@ Following are methods that need to be implemented when creating a new SystemUI t protected void handleLongClick() ``` - Handles what to do when the Tile is clicked. In general, a Tile will make calls to its controller here and maybe update its state immediately (by calling `QSTileImpl#refreshState`). A Tile can also decide to ignore the click here, if it's `Tile#STATE_UNAVAILABLE`. + Handles what to do when the Tile is clicked. In general, a Tile will make calls to its controller + here and maybe update its state immediately (by calling `QSTileImpl#refreshState`). A Tile can + also decide to ignore the click here, if it's `Tile#STATE_UNAVAILABLE`. - By default long click redirects to click and long click launches the intent defined in `getLongClickIntent`. + By default long click redirects to click and long click launches the intent defined + in `getLongClickIntent`. * ```java protected void handleUpdateState(TState, Object) ``` - Updates the `State` of the Tile based on the state of the device as provided by the respective controller. It will be called every time the Tile becomes visible, is interacted with or `QSTileImpl#refreshState` is called. After this is done, the updated state will be reflected in the UI. + Updates the `State` of the Tile based on the state of the device as provided by the respective + controller. It will be called every time the Tile becomes visible, is interacted with + or `QSTileImpl#refreshState` is called. After this is done, the updated state will be reflected in + the UI. * ```java @Deprecated public int getMetricsCategory() ``` - ~~Identifier for this Tile, as defined in [proto/src/metrics_constants/metrics_constants.proto](/proto/src/metrics_constants/metrics_constants.proto). This is used to log events related to this Tile.~~ + ~~Identifier for this Tile, as defined + in [proto/src/metrics_constants/metrics_constants.proto](/proto/src/metrics_constants/metrics_constants.proto). + This is used to log events related to this Tile.~~ This is now deprecated in favor of `UiEvent` that use the tile spec. * ```java public boolean isAvailable() ``` - Determines if a Tile is available to be used (for example, disable `WifiTile` in devices with no Wifi support). If this is false, the Tile will be destroyed upon creation. + Determines if a Tile is available to be used (for example, disable `WifiTile` in devices with no + Wifi support). If this is false, the Tile will be destroyed upon creation. * ```java public CharSequence getTileLabel() ``` - Provides a default label for this Tile. Used by the QS Panel customizer to show a name next to each available tile. + Provides a default label for this Tile. Used by the QS Panel customizer to show a name next to + each available tile. ### Implementing a third party tile -For information about this, use the Android Developer documentation for [TileService](https://developer.android.com/reference/android/service/quicksettings/TileService).
\ No newline at end of file +For information about this, use the Android Developer documentation +for [TileService](https://developer.android.com/reference/android/service/quicksettings/TileService). + +## AutoAddable tiles + +AutoAddable tiles are tiles that are not part of the default set, but will be automatically added +for the user, when the user enabled a feature for the first time. For example: +* When the user creates a work profile, the work profile tile is automatically added. +* When the user sets up a hotspot for the first time, the hotspot tile is automatically added. + +In order to declare a tile as auto-addable, there are two ways: + +* If the tile can be tied to a secure setting such that the tile should be auto added after that + setting has changed to a non-zero value for the first time, a new line can be added to the + string-array `config_quickSettingsAutoAdd` in [config.xml](/packages/SystemUI/res/values/config.xml). +* If more specific behavior is needed, a new + [AutoAddable](/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddable.kt) + can be added in the `autoaddables` package. This can have custom logic that produces a flow of + signals on when the tile should be auto-added (or auto-removed in special cases). + + *Special case: If the data comes from a `CallbackController`, a special + `CallbackControllerAutoAddable` can be created instead that handles a lot of the common code.* + +### AutoAddRepository (and UserAutoAddRepository) + +These classes keep track of tiles that have been auto-added for each user, as a list of Tile specs. +While the device is running, this is the source of truth of already auto-added tiles for that user. + +The list is persisted to `Settings.Secure` every time it changes so it will be available upon +restart or backup. In particular, any changes in the secure setting while this repository is +tracking the list of tiles will be reverted. + +The class provides a `Flow<Set<TileSpec>>` for each user that can be collected to keep track of the +set of already auto added tiles. + +### AutoAddInteractor + +This class collects all registered (through Dagger) `AutoAddables` and merges all the signals for +the current user. It will add/remove tiles as necessary and mark them as such in the +`AutoAddRepository`. + +## Backup and restore + +It's important to point out that B&R of Quick Settings tiles only concerns itself with restoring, +for each user, the list of current tiles and their order. The state of the tiles (or other things +that can be accessed from them like list of WiFi networks) is the concern of each feature team and +out of the scope of Quick Settings. + +In order to provide better support to restoring Quick Settings tiles and prevent overwritten or +inconsistent data, the system has the following steps: + +1. When `Settings.Secure.SYSUI_QS_TILES` and `Settings.Secure.QS_AUTO_TILES` are restored, a + broadcast is sent to SystemUI. This is handled by + [SettingsHelper](/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java). + The broadcasts are received by [QSSettingsRestoredRepository](/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/QSSettingsRestoredRepository.kt) + and grouped by user into a data object. As described above, the change performed by the restore in + settings is overriden by the corresponding repositories. +2. Once both settings have been restored, the data is reconciled with the current data, to account + for tiles that may have been auto-added between the start of SystemUI and the time the restore + happened. The guiding principles for the reconciliation are as follows: + * We assume that the user expects the restored tiles to be the ones to be present after restore, + so those are taken as the basis for the reconciliation. + * Any tile that was auto-added before the restore, but had not been auto-added in the source + device, is auto-added again (preferably in a similar position). + * Any tile that was auto-added before the restore, and it was also auto-added in the source + device, but not present in the restored tiles, is considered removed by the user and therefore + not restored. + * Every tile that was marked as auto-added (all tiles in source + tiles added before restore) + are set as auto-added. + +## Logs for debugging + +The following log buffers are used for Quick Settings debugging purposes: + +### QSLog + +Logs events in the individual tiles, like listening state, clicks, and status updates. + +### QSTileListLog + +Logs changes in the current set of tiles for each user, including when tiles are created or +destroyed, and the reason for that. It also logs what operation caused the tiles to change +(add, remove, change, restore). + +### QSAutoAddLog + +Logs operations of auto-add (or auto-remove) of tiles. + +### QSRestoreLog + +Logs the data obtained after a successful restore of the settings. This is the data that will be +used for reconciliation.
\ No newline at end of file diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt index 80d45bcc23dd..78b854e39d13 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt @@ -22,8 +22,11 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.internal.logging.UiEventLogger import com.android.internal.util.LatencyTracker import com.android.internal.widget.LockPatternUtils +import com.android.internal.widget.LockscreenCredential +import com.android.keyguard.KeyguardPinViewController.PinBouncerUiEvent import com.android.keyguard.KeyguardSecurityModel.SecurityMode import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector @@ -91,6 +94,7 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { @Mock lateinit var passwordTextView: PasswordTextView @Mock lateinit var deleteButton: NumPadButton @Mock lateinit var enterButton: View + @Mock lateinit var uiEventLogger: UiEventLogger @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback> @@ -137,6 +141,7 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { postureController, featureFlags, mSelectedUserInteractor, + uiEventLogger ) } @@ -251,4 +256,21 @@ class KeyguardPinViewControllerTest : SysuiTestCase() { verify(lockPatternUtils).getCurrentFailedPasswordAttempts(anyInt()) } + + @Test + fun onUserInput_autoConfirmation_attemptsUnlock() { + val pinViewController = constructPinViewController(mockKeyguardPinView) + whenever(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true) + whenever(lockPatternUtils.getPinLength(anyInt())).thenReturn(6) + whenever(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true) + whenever(passwordTextView.text).thenReturn("000000") + whenever(enterButton.visibility).thenReturn(View.INVISIBLE) + whenever(mockKeyguardPinView.enteredCredential) + .thenReturn(LockscreenCredential.createPin("000000")) + + pinViewController.onUserInput() + + verify(uiEventLogger).log(PinBouncerUiEvent.ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE) + verify(keyguardUpdateMonitor).setCredentialAttempted() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java index 602f3dc29491..da97a1283261 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -1041,8 +1041,9 @@ public class AuthControllerTest extends SysuiTestCase { mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSideFpsController, mDisplayManager, mWakefulnessLifecycle, - mPanelInteractionDetector, mUserManager, mLockPatternUtils, mUdfpsLogger, - mLogContextInteractor, () -> mBiometricPromptCredentialInteractor, + mPanelInteractionDetector, mUserManager, mLockPatternUtils, () -> mUdfpsLogger, + () -> mLogContextInteractor, + () -> mBiometricPromptCredentialInteractor, () -> mPromptSelectionInteractor, () -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor, mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt index 79f062536404..cbb772f49c93 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerWithCoroutinesTest.kt @@ -396,7 +396,7 @@ class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest : .onDozeAmountChanged( eq(.3f), eq(.3f), - eq(UdfpsKeyguardViewLegacy.ANIMATION_UNLOCKED_SCREEN_OFF) + eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF) ) transitionRepository.sendTransitionStep( @@ -413,9 +413,130 @@ class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest : .onDozeAmountChanged( eq(1f), eq(1f), - eq(UdfpsKeyguardViewLegacy.ANIMATION_UNLOCKED_SCREEN_OFF) + eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF) ) job.cancel() } + + @Test + fun aodToOccluded_dozeAmountChanged() = + testScope.runTest { + // GIVEN view is attached + mController.onViewAttached() + Mockito.reset(mView) + + val job = mController.listenForAodToOccludedTransitions(this) + + // WHEN transitioning from aod to occluded + transitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.OCCLUDED, + value = .3f, + transitionState = TransitionState.RUNNING + ) + ) + runCurrent() + // THEN doze amount is updated + verify(mView) + .onDozeAmountChanged(eq(.7f), eq(.7f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE)) + + transitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.OCCLUDED, + value = 1f, + transitionState = TransitionState.FINISHED + ) + ) + runCurrent() + // THEN doze amount is updated + verify(mView) + .onDozeAmountChanged(eq(0f), eq(0f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE)) + + job.cancel() + } + + @Test + fun occludedToAod_dozeAmountChanged() = + testScope.runTest { + // GIVEN view is attached + mController.onViewAttached() + Mockito.reset(mView) + + val job = mController.listenForOccludedToAodTransition(this) + + // WHEN transitioning from occluded to aod + transitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.OCCLUDED, + to = KeyguardState.AOD, + value = .3f, + transitionState = TransitionState.RUNNING + ) + ) + runCurrent() + // THEN doze amount is updated + verify(mView) + .onDozeAmountChanged( + eq(.3f), + eq(.3f), + eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF) + ) + + transitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.OCCLUDED, + to = KeyguardState.AOD, + value = 1f, + transitionState = TransitionState.FINISHED + ) + ) + runCurrent() + // THEN doze amount is updated + verify(mView) + .onDozeAmountChanged( + eq(1f), + eq(1f), + eq(UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF) + ) + + job.cancel() + } + + @Test + fun cancelledAodToLockscreen_dozeAmountChangedToZero() = + testScope.runTest { + // GIVEN view is attached + mController.onViewAttached() + Mockito.reset(mView) + + val job = mController.listenForLockscreenAodTransitions(this) + // WHEN aod to lockscreen transition is cancelled + transitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + value = 1f, + transitionState = TransitionState.CANCELED + ) + ) + runCurrent() + // ... and WHEN the next transition is from lockscreen => occluded + transitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.OCCLUDED, + value = .4f, + transitionState = TransitionState.STARTED + ) + ) + runCurrent() + + // THEN doze amount is updated to zero + verify(mView) + .onDozeAmountChanged(eq(0f), eq(0f), eq(UdfpsKeyguardViewLegacy.ANIMATION_NONE)) + job.cancel() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt index ce7db80db7da..ea3006f0b502 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.communal.view.viewmodel import android.app.smartspace.SmartspaceTarget +import android.os.PowerManager import android.provider.Settings import android.widget.RemoteViews import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -33,6 +34,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.media.controls.ui.MediaHost +import com.android.systemui.shade.ShadeViewController import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever @@ -50,6 +52,8 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class CommunalEditModeViewModelTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost + @Mock private lateinit var shadeViewController: ShadeViewController + @Mock private lateinit var powerManager: PowerManager private lateinit var testScope: TestScope @@ -79,6 +83,8 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { underTest = CommunalEditModeViewModel( withDeps.communalInteractor, + shadeViewController, + powerManager, mediaHost, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt index 32f4d075a873..9bd083501780 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.communal.view.viewmodel import android.app.smartspace.SmartspaceTarget +import android.os.PowerManager import android.provider.Settings import android.widget.RemoteViews import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -33,6 +34,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.media.controls.ui.MediaHost +import com.android.systemui.shade.ShadeViewController import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever @@ -50,6 +52,8 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class CommunalViewModelTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost + @Mock private lateinit var shadeViewController: ShadeViewController + @Mock private lateinit var powerManager: PowerManager private lateinit var testScope: TestScope @@ -80,6 +84,8 @@ class CommunalViewModelTest : SysuiTestCase() { CommunalViewModel( withDeps.communalInteractor, withDeps.tutorialInteractor, + shadeViewController, + powerManager, mediaHost, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt index 706f94e412ac..11939c1120d9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt @@ -23,6 +23,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeCommandQueue import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel @@ -53,7 +54,6 @@ class KeyguardInteractorTest : SysuiTestCase() { private val sceneInteractor = testUtils.sceneInteractor() private val commandQueue = FakeCommandQueue() private val bouncerRepository = FakeKeyguardBouncerRepository() - private val configurationRepository = FakeConfigurationRepository() private val shadeRepository = FakeShadeRepository() private val transitionState: MutableStateFlow<ObservableTransitionState> = MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Gone)) @@ -65,7 +65,7 @@ class KeyguardInteractorTest : SysuiTestCase() { powerInteractor = PowerInteractorFactory.create().powerInteractor, sceneContainerFlags = testUtils.sceneContainerFlags, bouncerRepository = bouncerRepository, - configurationRepository = configurationRepository, + configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()), shadeRepository = shadeRepository, sceneInteractorProvider = { sceneInteractor }, ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt index fd125e099f1b..53bca483f73f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt @@ -19,14 +19,11 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository 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.DREAMING @@ -38,16 +35,12 @@ import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING import com.android.systemui.keyguard.shared.model.TransitionState.STARTED import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.util.mockito.mock +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.collect.Range 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.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -55,223 +48,201 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: DreamingToLockscreenTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - fingerprintPropertyRepository = FakeFingerprintPropertyRepository() - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = - DreamingToLockscreenTransitionViewModel( - interactor, - mock(), - DeviceEntryUdfpsInteractor( - fingerprintPropertyRepository = fingerprintPropertyRepository, - fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(), - biometricSettingsRepository = FakeBiometricSettingsRepository(), - ), - ) - } + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + private val underTest = kosmos.dreamingToLockscreenTransitionViewModel @Test fun dreamOverlayTranslationY() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - + testScope.runTest { val pixels = 100 - val job = - underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) + val values by collectValues(underTest.dreamOverlayTranslationY(pixels)) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.3f), + step(0.5f), + step(0.6f), + step(0.8f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(7) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } - - job.cancel() } @Test fun dreamOverlayFadeOut() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - - val job = underTest.dreamOverlayAlpha.onEach { values.add(it) }.launchIn(this) - - // Should start running here... - repository.sendTransitionStep(step(0f, STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.5f)) - // ...up to here - repository.sendTransitionStep(step(1f)) + testScope.runTest { + val values by collectValues(underTest.dreamOverlayAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + // Should start running here... + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.5f), + // ...up to here + step(1f), + ), + testScope, + ) - // Only two values should be present, since the dream overlay runs for a small fraction - // of the overall animation time assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } - - job.cancel() } @Test fun lockscreenFadeIn() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - - val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.2f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(1f)) + testScope.runTest { + val values by collectValues(underTest.lockscreenAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } - - job.cancel() } @Test fun deviceEntryParentViewFadeIn() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - - val job = underTest.deviceEntryParentViewAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.2f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(1f)) + testScope.runTest { + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } - - job.cancel() } @Test fun deviceEntryBackgroundViewAppear() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { fingerprintPropertyRepository.setProperties( sensorId = 0, strength = SensorStrength.STRONG, sensorType = FingerprintSensorType.UDFPS_OPTICAL, sensorLocations = emptyMap(), ) - val values = mutableListOf<Float>() - - val job = - underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.2f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(1f)) + val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) values.forEach { assertThat(it).isEqualTo(1f) } - - job.cancel() } @Test fun deviceEntryBackground_noUdfps_noUpdates() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { fingerprintPropertyRepository.setProperties( sensorId = 0, strength = SensorStrength.STRONG, sensorType = FingerprintSensorType.REAR, sensorLocations = emptyMap(), ) - val values = mutableListOf<Float>() - - val job = - underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.2f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(1f)) + val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(0) // no updates - - job.cancel() } @Test fun lockscreenTranslationY() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - + testScope.runTest { val pixels = 100 - val job = - underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(1f)) + val values by collectValues(underTest.lockscreenTranslationY(pixels)) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.3f), + step(0.5f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } - - job.cancel() } @Test fun transitionEnded() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<TransitionStep>() - - val job = underTest.transitionEnded.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(TransitionStep(DOZING, DREAMING, 0.0f, STARTED)) - repository.sendTransitionStep(TransitionStep(DOZING, DREAMING, 1.0f, FINISHED)) - - repository.sendTransitionStep(TransitionStep(DREAMING, LOCKSCREEN, 0.0f, STARTED)) - repository.sendTransitionStep(TransitionStep(DREAMING, LOCKSCREEN, 0.1f, RUNNING)) - repository.sendTransitionStep(TransitionStep(DREAMING, LOCKSCREEN, 1.0f, FINISHED)) - - repository.sendTransitionStep(TransitionStep(LOCKSCREEN, DREAMING, 0.0f, STARTED)) - repository.sendTransitionStep(TransitionStep(LOCKSCREEN, DREAMING, 0.5f, RUNNING)) - repository.sendTransitionStep(TransitionStep(LOCKSCREEN, DREAMING, 1.0f, FINISHED)) - - repository.sendTransitionStep(TransitionStep(DREAMING, GONE, 0.0f, STARTED)) - repository.sendTransitionStep(TransitionStep(DREAMING, GONE, 0.5f, RUNNING)) - repository.sendTransitionStep(TransitionStep(DREAMING, GONE, 1.0f, CANCELED)) - - repository.sendTransitionStep(TransitionStep(DREAMING, AOD, 0.0f, STARTED)) - repository.sendTransitionStep(TransitionStep(DREAMING, AOD, 1.0f, FINISHED)) + testScope.runTest { + val values by collectValues(underTest.transitionEnded) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + TransitionStep(DOZING, DREAMING, 0.0f, STARTED), + TransitionStep(DOZING, DREAMING, 1.0f, FINISHED), + TransitionStep(DREAMING, LOCKSCREEN, 0.0f, STARTED), + TransitionStep(DREAMING, LOCKSCREEN, 0.1f, RUNNING), + TransitionStep(DREAMING, LOCKSCREEN, 1.0f, FINISHED), + TransitionStep(LOCKSCREEN, DREAMING, 0.0f, STARTED), + TransitionStep(LOCKSCREEN, DREAMING, 0.5f, RUNNING), + TransitionStep(LOCKSCREEN, DREAMING, 1.0f, FINISHED), + TransitionStep(DREAMING, GONE, 0.0f, STARTED), + TransitionStep(DREAMING, GONE, 0.5f, RUNNING), + TransitionStep(DREAMING, GONE, 1.0f, CANCELED), + TransitionStep(DREAMING, AOD, 0.0f, STARTED), + TransitionStep(DREAMING, AOD, 1.0f, FINISHED), + ), + testScope, + ) assertThat(values.size).isEqualTo(3) values.forEach { assertThat(it.transitionState == FINISHED || it.transitionState == CANCELED) .isTrue() } - - job.cancel() } private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt index cf2012989624..3c07034f0e12 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt @@ -19,85 +19,73 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: GoneToDreamingTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = GoneToDreamingTransitionViewModel(interactor) - } + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val repository = kosmos.fakeKeyguardTransitionRepository + private val underTest = kosmos.goneToDreamingTransitionViewModel @Test - fun lockscreenFadeOut() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - - val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this) + fun runTest() = + testScope.runTest { + val values by collectValues(underTest.lockscreenAlpha) - // Should start running here... - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.2f)) - repository.sendTransitionStep(step(0.3f)) - // ...up to here - repository.sendTransitionStep(step(1f)) + repository.sendTransitionSteps( + listOf( + // Should start running here... + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + // ...up to here + step(1f), + ), + testScope, + ) // Only three values should be present, since the dream overlay runs for a small // fraction of the overall animation time assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } - - job.cancel() } @Test fun lockscreenTranslationY() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - + testScope.runTest { val pixels = 100 - val job = - underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this) + val values by collectValues(underTest.lockscreenTranslationY(pixels)) - // Should start running here... - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.5f)) - // And a final reset event on CANCEL - repository.sendTransitionStep(step(0.8f, TransitionState.CANCELED)) + repository.sendTransitionSteps( + listOf( + // Should start running here... + step(0f, TransitionState.STARTED), + step(0f), + step(0.3f), + step(0.5f), + // And a final reset event on CANCEL + step(0.8f, TransitionState.CANCELED) + ), + testScope, + ) assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } - - job.cancel() } private fun step( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt index ba72b4c95a44..9226c0d61a3c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt @@ -27,7 +27,6 @@ import com.android.systemui.flags.Flags import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState @@ -55,11 +54,7 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { private val repository = kosmos.fakeKeyguardTransitionRepository private val shadeRepository = kosmos.shadeRepository private val keyguardRepository = kosmos.fakeKeyguardRepository - private val underTest = - LockscreenToDreamingTransitionViewModel( - interactor = kosmos.keyguardTransitionInteractor, - shadeDependentFlows = kosmos.shadeDependentFlows, - ) + private val underTest = kosmos.lockscreenToDreamingTransitionViewModel @Test fun lockscreenFadeOut() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt index 3536d5c77c93..bcad72bef1e6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt @@ -21,18 +21,19 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.Flags import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope +import com.android.systemui.res.R import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.testKosmos import com.google.common.collect.Range @@ -46,7 +47,6 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { - private val kosmos = testKosmos().apply { featureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) } @@ -55,11 +55,8 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { private val repository = kosmos.fakeKeyguardTransitionRepository private val shadeRepository = kosmos.shadeRepository private val keyguardRepository = kosmos.fakeKeyguardRepository - private val underTest = - LockscreenToOccludedTransitionViewModel( - interactor = kosmos.keyguardTransitionInteractor, - shadeDependentFlows = kosmos.shadeDependentFlows, - ) + private val configurationRepository = kosmos.fakeConfigurationRepository + private val underTest = kosmos.lockscreenToOccludedTransitionViewModel @Test fun lockscreenFadeOut() = @@ -86,8 +83,11 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenTranslationY() = testScope.runTest { - val pixels = 100 - val values by collectValues(underTest.lockscreenTranslationY(pixels)) + configurationRepository.setDimensionPixelSize( + R.dimen.lockscreen_to_occluded_transition_lockscreen_translation_y, + 100 + ) + val values by collectValues(underTest.lockscreenTranslationY) repository.sendTransitionSteps( steps = listOf( @@ -106,8 +106,11 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenTranslationYIsCanceled() = testScope.runTest { - val pixels = 100 - val values by collectValues(underTest.lockscreenTranslationY(pixels)) + configurationRepository.setDimensionPixelSize( + R.dimen.lockscreen_to_occluded_transition_lockscreen_translation_y, + 100 + ) + val values by collectValues(underTest.lockscreenTranslationY) repository.sendTransitionSteps( steps = listOf( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt index d0772270ed5e..d419d4a2534c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt @@ -19,24 +19,21 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.res.R +import com.android.systemui.testKosmos import com.google.common.collect.Range 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.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -44,163 +41,139 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: OccludedToLockscreenTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - fingerprintPropertyRepository = FakeFingerprintPropertyRepository() - biometricSettingsRepository = FakeBiometricSettingsRepository() - underTest = - OccludedToLockscreenTransitionViewModel( - interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor, - deviceEntryUdfpsInteractor = - DeviceEntryUdfpsInteractor( - fingerprintPropertyRepository = fingerprintPropertyRepository, - fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(), - biometricSettingsRepository = biometricSettingsRepository, - ), - ) - } + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val biometricSettingsRepository = kosmos.biometricSettingsRepository + val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + val configurationRepository = kosmos.fakeConfigurationRepository + val underTest = kosmos.occludedToLockscreenTransitionViewModel @Test fun lockscreenFadeIn() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - - val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - // Should start running here... - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.4f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - // ...up to here - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) + testScope.runTest { + val values by collectValues(underTest.lockscreenAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.1f), + // Should start running here... + step(0.3f), + step(0.4f), + step(0.5f), + step(0.6f), + // ...up to here + step(0.8f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } - - job.cancel() } @Test fun lockscreenTranslationY() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - - val pixels = 100 - val job = - underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(1f)) + testScope.runTest { + configurationRepository.setDimensionPixelSize( + R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y, + 100 + ) + val values by collectValues(underTest.lockscreenTranslationY) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.3f), + step(0.5f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } - - job.cancel() } @Test fun lockscreenTranslationYResettedAfterJobCancelled() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() + testScope.runTest { + configurationRepository.setDimensionPixelSize( + R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y, + 100 + ) + val values by collectValues(underTest.lockscreenTranslationY) - val pixels = 100 - val job = - underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this) - repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED)) + keyguardTransitionRepository.sendTransitionStep(step(0.5f, TransitionState.CANCELED)) assertThat(values.last()).isEqualTo(0f) - - job.cancel() } @Test fun deviceEntryParentViewFadeIn() = - runTest(UnconfinedTestDispatcher()) { - val values = mutableListOf<Float>() - - val job = underTest.deviceEntryParentViewAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - // Should start running here... - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.4f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - // ...up to here - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) + testScope.runTest { + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.1f), + // Should start running here... + step(0.3f), + step(0.4f), + step(0.5f), + step(0.6f), + // ...up to here + step(0.8f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } - - job.cancel() } @Test fun deviceEntryBackgroundViewShows() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) - val values = mutableListOf<Float>() + val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) - val job = - underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.4f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + keyguardTransitionRepository.sendTransitionStep(step(0.1f)) + keyguardTransitionRepository.sendTransitionStep(step(0.3f)) + keyguardTransitionRepository.sendTransitionStep(step(0.4f)) + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + keyguardTransitionRepository.sendTransitionStep(step(0.6f)) + keyguardTransitionRepository.sendTransitionStep(step(0.8f)) + keyguardTransitionRepository.sendTransitionStep(step(1f)) values.forEach { assertThat(it).isEqualTo(1f) } - - job.cancel() } @Test fun deviceEntryBackgroundView_noUdfpsEnrolled_noUpdates() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { fingerprintPropertyRepository.supportsRearFps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) - val values = mutableListOf<Float>() + val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) - val job = - underTest.deviceEntryBackgroundViewAlpha.onEach { values.add(it) }.launchIn(this) - - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.4f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + keyguardTransitionRepository.sendTransitionStep(step(0.1f)) + keyguardTransitionRepository.sendTransitionStep(step(0.3f)) + keyguardTransitionRepository.sendTransitionStep(step(0.4f)) + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + keyguardTransitionRepository.sendTransitionStep(step(0.6f)) + keyguardTransitionRepository.sendTransitionStep(step(0.8f)) + keyguardTransitionRepository.sendTransitionStep(step(1f)) assertThat(values).isEmpty() // no updates - - job.cancel() } private fun step( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt index 6cab023d59b0..78d87a680c5b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -19,80 +19,61 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor +import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor import com.android.systemui.coroutines.collectValues -import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.sysuiStatusBarStateController +import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat -import dagger.Lazy -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var featureFlags: FakeFeatureFlags - @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController - @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor - @Mock private lateinit var bouncerToGoneFlows: BouncerToGoneFlows - @Mock - private lateinit var keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor> + val kosmos = + testKosmos().apply { + featureFlagsClassic.apply { + set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) + set(Flags.FULL_SCREEN_USER_SWITCHER, false) + } + } + val testScope = kosmos.testScope - private val shadeExpansionStateFlow = MutableStateFlow(0.1f) + val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + val primaryBouncerInteractor = kosmos.primaryBouncerInteractor + val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController + val underTest = kosmos.primaryBouncerToGoneTransitionViewModel @Before fun setUp() { - MockitoAnnotations.initMocks(this) - - repository = FakeKeyguardTransitionRepository() - val featureFlags = - FakeFeatureFlags().apply { set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) } - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = - PrimaryBouncerToGoneTransitionViewModel( - interactor, - statusBarStateController, - primaryBouncerInteractor, - keyguardDismissActionInteractor, - featureFlags, - bouncerToGoneFlows, - ) - whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false) - whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) + sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false) } @Test fun bouncerAlpha() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.bouncerAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.6f)) + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.6f), + ), + testScope, + ) assertThat(values.size).isEqualTo(3) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } @@ -100,14 +81,19 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { @Test fun bouncerAlpha_runDimissFromKeyguard() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.bouncerAlpha) whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.6f)) + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.6f), + ), + testScope, + ) assertThat(values.size).isEqualTo(3) values.forEach { assertThat(it).isEqualTo(0f) } @@ -115,11 +101,11 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenAlpha() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.lockscreenAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + keyguardTransitionRepository.sendTransitionStep(step(1f)) assertThat(values.size).isEqualTo(2) values.forEach { assertThat(it).isEqualTo(0f) } @@ -127,13 +113,13 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenAlpha_runDimissFromKeyguard() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.lockscreenAlpha) - whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true) + sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + keyguardTransitionRepository.sendTransitionStep(step(1f)) assertThat(values.size).isEqualTo(2) values.forEach { assertThat(it).isEqualTo(1f) } @@ -141,13 +127,13 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenAlpha_leaveShadeOpen() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.lockscreenAlpha) - whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true) + sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + keyguardTransitionRepository.sendTransitionStep(step(1f)) assertThat(values.size).isEqualTo(2) values.forEach { assertThat(it).isEqualTo(1f) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt new file mode 100644 index 000000000000..2b744ac8398a --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapperTest.kt @@ -0,0 +1,115 @@ +/* + * 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.qs.tiles.impl.alarm.domain + +import android.app.AlarmManager +import android.widget.Switch +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.kosmos.Kosmos +import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel +import com.android.systemui.qs.tiles.impl.alarm.qsAlarmTileConfig +import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.res.R +import java.time.Instant +import java.time.LocalDateTime +import java.util.TimeZone +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class AlarmTileMapperTest : SysuiTestCase() { + private val kosmos = Kosmos() + private val alarmTileConfig = kosmos.qsAlarmTileConfig + // Using lazy (versus =) to make sure we override the right context -- see b/311612168 + private val mapper by lazy { AlarmTileMapper(context.orCreateTestableResources.resources) } + + @Test + fun notAlarmSet() { + val inputModel = AlarmTileModel.NoAlarmSet + + val outputState = mapper.map(alarmTileConfig, inputModel) + + val expectedState = + createAlarmTileState( + QSTileState.ActivationState.INACTIVE, + context.getString(R.string.qs_alarm_tile_no_alarm) + ) + QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) + } + + @Test + fun nextAlarmSet24HourFormat() { + val triggerTime = 1L + val inputModel = + AlarmTileModel.NextAlarmSet(true, AlarmManager.AlarmClockInfo(triggerTime, null)) + + val outputState = mapper.map(alarmTileConfig, inputModel) + + val localDateTime = + LocalDateTime.ofInstant( + Instant.ofEpochMilli(triggerTime), + TimeZone.getDefault().toZoneId() + ) + val expectedSecondaryLabel = AlarmTileMapper.formatter24Hour.format(localDateTime) + val expectedState = + createAlarmTileState(QSTileState.ActivationState.ACTIVE, expectedSecondaryLabel) + QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) + } + + @Test + fun nextAlarmSet12HourFormat() { + val triggerTime = 1L + val inputModel = + AlarmTileModel.NextAlarmSet(false, AlarmManager.AlarmClockInfo(triggerTime, null)) + + val outputState = mapper.map(alarmTileConfig, inputModel) + + val localDateTime = + LocalDateTime.ofInstant( + Instant.ofEpochMilli(triggerTime), + TimeZone.getDefault().toZoneId() + ) + val expectedSecondaryLabel = AlarmTileMapper.formatter12Hour.format(localDateTime) + val expectedState = + createAlarmTileState(QSTileState.ActivationState.ACTIVE, expectedSecondaryLabel) + QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState) + } + + private fun createAlarmTileState( + activationState: QSTileState.ActivationState, + secondaryLabel: String + ): QSTileState { + val label = context.getString(R.string.status_bar_alarm) + return QSTileState( + { Icon.Resource(R.drawable.ic_alarm, null) }, + label, + activationState, + secondaryLabel, + setOf(QSTileState.UserAction.CLICK), + label, + null, + QSTileState.SideViewIcon.None, + QSTileState.EnabledState.ENABLED, + Switch::class.qualifiedName + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileDataInteractorTest.kt new file mode 100644 index 000000000000..990d74728052 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileDataInteractorTest.kt @@ -0,0 +1,131 @@ +/* + * 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.qs.tiles.impl.alarm.domain.interactor + +import android.app.AlarmManager +import android.app.PendingIntent +import android.os.UserHandle +import android.testing.LeakCheck +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues +import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger +import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.time.DateFormatUtil +import com.android.systemui.utils.leaks.FakeNextAlarmController +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.toCollection +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class AlarmTileDataInteractorTest : SysuiTestCase() { + private lateinit var dateFormatUtil: DateFormatUtil + + private val nextAlarmController = FakeNextAlarmController(LeakCheck()) + private lateinit var underTest: AlarmTileDataInteractor + + @Before + fun setup() { + dateFormatUtil = mock<DateFormatUtil>() + underTest = AlarmTileDataInteractor(nextAlarmController, dateFormatUtil) + } + + @Test + fun alarmTriggerTimeDataMatchesTheController() = runTest { + val expectedTriggerTime = 1L + val alarmInfo = AlarmManager.AlarmClockInfo(expectedTriggerTime, mock<PendingIntent>()) + val dataList: List<AlarmTileModel> by + collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest))) + + runCurrent() + nextAlarmController.setNextAlarm(alarmInfo) + runCurrent() + nextAlarmController.setNextAlarm(null) + runCurrent() + + assertThat(dataList).hasSize(3) + assertThat(dataList[0]).isInstanceOf(AlarmTileModel.NoAlarmSet::class.java) + assertThat(dataList[1]).isInstanceOf(AlarmTileModel.NextAlarmSet::class.java) + val actualAlarmClockInfo = (dataList[1] as AlarmTileModel.NextAlarmSet).alarmClockInfo + assertThat(actualAlarmClockInfo).isNotNull() + val actualTriggerTime = actualAlarmClockInfo.triggerTime + assertThat(actualTriggerTime).isEqualTo(expectedTriggerTime) + assertThat(dataList[2]).isInstanceOf(AlarmTileModel.NoAlarmSet::class.java) + } + + @Test + fun dateFormatUtil24HourDataMatchesController() = runTest { + val expectedValue = true + whenever(dateFormatUtil.is24HourFormat).thenReturn(expectedValue) + val alarmInfo = AlarmManager.AlarmClockInfo(1L, mock<PendingIntent>()) + nextAlarmController.setNextAlarm(alarmInfo) + + val model by + collectLastValue( + underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)) + ) + runCurrent() + + assertThat(model).isNotNull() + assertThat(model).isInstanceOf(AlarmTileModel.NextAlarmSet::class.java) + val actualValue = (model as AlarmTileModel.NextAlarmSet).is24HourFormat + assertThat(actualValue).isEqualTo(expectedValue) + } + + @Test + fun dateFormatUtil12HourDataMatchesController() = runTest { + val expectedValue = false + whenever(dateFormatUtil.is24HourFormat).thenReturn(expectedValue) + val alarmInfo = AlarmManager.AlarmClockInfo(1L, mock<PendingIntent>()) + nextAlarmController.setNextAlarm(alarmInfo) + + val model by + collectLastValue( + underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)) + ) + runCurrent() + + assertThat(model).isNotNull() + assertThat(model).isInstanceOf(AlarmTileModel.NextAlarmSet::class.java) + val actualValue = (model as AlarmTileModel.NextAlarmSet).is24HourFormat + assertThat(actualValue).isEqualTo(expectedValue) + } + + @Test + fun alwaysAvailable() = runTest { + val availability = underTest.availability(TEST_USER).toCollection(mutableListOf()) + + assertThat(availability).hasSize(1) + assertThat(availability.last()).isTrue() + } + + private companion object { + val TEST_USER = UserHandle.of(1)!! + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt new file mode 100644 index 000000000000..e44c8493244c --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt @@ -0,0 +1,82 @@ +/* + * 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.qs.tiles.impl.alarm.domain.interactor + +import android.app.AlarmManager.AlarmClockInfo +import android.app.PendingIntent +import android.content.Intent +import android.provider.AlarmClock +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click +import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel +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.nullable +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mockito.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +class AlarmTileUserActionInteractorTest : SysuiTestCase() { + private lateinit var activityStarter: ActivityStarter + private lateinit var intentCaptor: ArgumentCaptor<Intent> + private lateinit var pendingIntentCaptor: ArgumentCaptor<PendingIntent> + + lateinit var underTest: AlarmTileUserActionInteractor + + @Before + fun setup() { + activityStarter = mock<ActivityStarter>() + intentCaptor = ArgumentCaptor.forClass(Intent::class.java) + pendingIntentCaptor = ArgumentCaptor.forClass(PendingIntent::class.java) + underTest = AlarmTileUserActionInteractor(activityStarter) + } + + @Test + fun handleClickWithDefaultIntent() = runTest { + val alarmInfo = AlarmClockInfo(1L, null) + val inputModel = AlarmTileModel.NextAlarmSet(true, alarmInfo) + + underTest.handleInput(click(inputModel)) + + verify(activityStarter) + .postStartActivityDismissingKeyguard(capture(intentCaptor), eq(0), nullable()) + assertThat(intentCaptor.value.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS) + } + + @Test + fun handleClickWithPendingIntent() = runTest { + val expectedIntent: PendingIntent = mock<PendingIntent>() + val alarmInfo = AlarmClockInfo(1L, expectedIntent) + val inputModel = AlarmTileModel.NextAlarmSet(true, alarmInfo) + + underTest.handleInput(click(inputModel)) + + verify(activityStarter) + .postStartActivityDismissingKeyguard(capture(pendingIntentCaptor), nullable()) + assertThat(pendingIntentCaptor.value).isEqualTo(expectedIntent) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java index 0b922a844690..de767e39499a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java @@ -65,7 +65,7 @@ public class SystemUIDialogTest extends SysuiTestCase { @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock - private DialogDelegate<SystemUIDialog> mDelegate; + private SystemUIDialog.Delegate mDelegate; @Before public void setup() { diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/AlarmData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/AlarmData.kt new file mode 100644 index 000000000000..837857bfa3ed --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/AlarmData.kt @@ -0,0 +1,6 @@ +package com.android.systemui.plugins.clocks + +data class AlarmData( + val nextAlarmMillis: Long?, + val descriptionId: String?, +) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt index 63ded2ef0c56..1c5f221f2efb 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt @@ -11,7 +11,7 @@ * KIND, either express or implied. See the License for the specific language governing * permissions and limitations under the License. */ -package com.android.systemui.plugins +package com.android.systemui.plugins.clocks import android.content.res.Resources import android.graphics.Rect @@ -20,6 +20,7 @@ import android.view.View import androidx.constraintlayout.widget.ConstraintSet import com.android.internal.annotations.Keep import com.android.systemui.log.core.MessageBuffer +import com.android.systemui.plugins.Plugin import com.android.systemui.plugins.annotations.ProvidesInterface import java.io.PrintWriter import java.util.Locale @@ -145,6 +146,12 @@ interface ClockEvents { /** Call whenever the weather data should update */ fun onWeatherDataChanged(data: WeatherData) + + /** Call with alarm information */ + fun onAlarmDataChanged(data: AlarmData) + + /** Call with zen/dnd information */ + fun onZenDataChanged(data: ZenData) } /** Methods which trigger various clock animations */ diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/WeatherData.kt index affb76b79d2e..789a47304ecf 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/WeatherData.kt @@ -1,4 +1,4 @@ -package com.android.systemui.plugins +package com.android.systemui.plugins.clocks import android.os.Bundle import android.util.Log @@ -7,8 +7,7 @@ import androidx.annotation.VisibleForTesting typealias WeatherTouchAction = (View) -> Unit -class WeatherData -constructor( +data class WeatherData( val description: String, val state: WeatherStateIcon, val useCelsius: Boolean, diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ZenData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ZenData.kt new file mode 100644 index 000000000000..e927ec3c8575 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ZenData.kt @@ -0,0 +1,22 @@ +package com.android.systemui.plugins.clocks + +import android.provider.Settings.Global.ZEN_MODE_ALARMS +import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS +import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS +import android.provider.Settings.Global.ZEN_MODE_OFF + +data class ZenData( + val zenMode: ZenMode, + val descriptionId: String?, +) { + enum class ZenMode(val zenMode: Int) { + OFF(ZEN_MODE_OFF), + IMPORTANT_INTERRUPTIONS(ZEN_MODE_IMPORTANT_INTERRUPTIONS), + NO_INTERRUPTIONS(ZEN_MODE_NO_INTERRUPTIONS), + ALARMS(ZEN_MODE_ALARMS); + + companion object { + fun fromInt(zenMode: Int) = values().firstOrNull { it.zenMode == zenMode } + } + } +} diff --git a/packages/SystemUI/res/color/notification_overlay_color.xml b/packages/SystemUI/res/color/notification_overlay_color.xml index c24bff9c7271..a14a7ad9d2da 100644 --- a/packages/SystemUI/res/color/notification_overlay_color.xml +++ b/packages/SystemUI/res/color/notification_overlay_color.xml @@ -17,7 +17,9 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:state_pressed="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha="0.15" /> + <!-- Pressed state's alpha is set to 0.00 temporarily until this bug is resolved permanently + b/313920497 Design intended alpha is 0.15--> + <item android:state_pressed="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha="0.00" /> <item android:state_hovered="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha="0.11" /> <item android:color="@color/transparent" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 03960d522653..7db21b2be04d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -37,6 +37,7 @@ <!-- Used while animating the navbar during a long press. --> <dimen name="navigation_home_handle_additional_width_for_animation">20dp</dimen> <dimen name="navigation_home_handle_additional_height_for_animation">4dp</dimen> + <dimen name="navigation_home_handle_shrink_width_for_animation">16dp</dimen> <!-- Size of the nav bar edge panels, should be greater to the edge sensitivity + the drag threshold --> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index 090346364d6c..763930db1d55 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -38,6 +38,4 @@ protected. --> <bool name="flag_battery_shield_icon">false</bool> - <!-- Whether we want to stop pulsing while running the face scanning animation --> - <bool name="flag_stop_pulsing_face_scanning_animation">true</bool> </resources> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 26e785d9a704..46329148a659 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -149,10 +149,11 @@ interface ISystemUiProxy { * * @param isTouchDown {@code true} if the button is starting to be pressed ({@code false} if * released or canceled) + * @param shrink {@code true} if the handle should shrink, {@code false} if it should grow * @param durationMs how long the animation should take (for the {@code isTouchDown} case, this * should be the same as the amount of time to trigger a long-press) */ - oneway void animateNavBarLongPress(boolean isTouchDown, long durationMs) = 54; + oneway void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) = 54; // Next id = 55 } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index c02ffa788d48..76abad8ae863 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -33,8 +33,8 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener import androidx.annotation.VisibleForTesting import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle -import com.android.systemui.customization.R import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.customization.R import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.DisplaySpecific import com.android.systemui.dagger.qualifiers.Main @@ -49,14 +49,19 @@ import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel.DEBUG import com.android.systemui.log.dagger.KeyguardLargeClockLog import com.android.systemui.log.dagger.KeyguardSmallClockLog -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockFaceController -import com.android.systemui.plugins.ClockTickRate -import com.android.systemui.plugins.WeatherData +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockFaceController +import com.android.systemui.plugins.clocks.ClockTickRate +import com.android.systemui.plugins.clocks.AlarmData +import com.android.systemui.plugins.clocks.WeatherData +import com.android.systemui.plugins.clocks.ZenData +import com.android.systemui.plugins.clocks.ZenData.ZenMode +import com.android.systemui.res.R as SysuiR import com.android.systemui.shared.regionsampling.RegionSampler import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.util.concurrency.DelayableExecutor import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DisposableHandle @@ -88,7 +93,8 @@ constructor( @Background private val bgExecutor: Executor, @KeyguardSmallClockLog private val smallLogBuffer: LogBuffer?, @KeyguardLargeClockLog private val largeLogBuffer: LogBuffer?, - private val featureFlags: FeatureFlags + private val featureFlags: FeatureFlags, + private val zenModeController: ZenModeController, ) { var clock: ClockController? = null set(value) { @@ -137,12 +143,18 @@ constructor( } updateFontSizes() updateTimeListeners() - cachedWeatherData?.let { + weatherData?.let { if (WeatherData.DEBUG) { Log.i(TAG, "Pushing cached weather data to new clock: $it") } value.events.onWeatherDataChanged(it) } + zenData?.let { + value.events.onZenDataChanged(it) + } + alarmData?.let { + value.events.onAlarmDataChanged(it) + } smallClockOnAttachStateChangeListener = object : OnAttachStateChangeListener { @@ -260,7 +272,10 @@ constructor( var largeTimeListener: TimeListener? = null val shouldTimeListenerRun: Boolean get() = isKeyguardVisible && dozeAmount < DOZE_TICKRATE_THRESHOLD - private var cachedWeatherData: WeatherData? = null + + private var weatherData: WeatherData? = null + private var zenData: ZenData? = null + private var alarmData: AlarmData? = null private val configListener = object : ConfigurationController.ConfigurationListener { @@ -321,14 +336,43 @@ constructor( override fun onUserSwitchComplete(userId: Int) { clock?.run { events.onTimeFormatChanged(DateFormat.is24HourFormat(context)) } + zenModeCallback.onNextAlarmChanged() } override fun onWeatherDataChanged(data: WeatherData) { - cachedWeatherData = data + weatherData = data clock?.run { events.onWeatherDataChanged(data) } } } + private val zenModeCallback = object : ZenModeController.Callback { + override fun onZenChanged(zen: Int) { + var mode = ZenMode.fromInt(zen) + if (mode == null) { + Log.e(TAG, "Failed to get zen mode from int: $zen") + return + } + + zenData = ZenData( + mode, + if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name + else SysuiR.string::dnd_is_on.name + ).also { data -> + clock?.run { events.onZenDataChanged(data) } + } + } + + override fun onNextAlarmChanged() { + val nextAlarmMillis = zenModeController.getNextAlarm() + alarmData = AlarmData( + if (nextAlarmMillis > 0) nextAlarmMillis else null, + SysuiR.string::status_bar_alarm.name + ).also { data -> + clock?.run { events.onAlarmDataChanged(data) } + } + } + } + fun registerListeners(parent: View) { if (isRegistered) { return @@ -341,6 +385,7 @@ constructor( configurationController.addCallback(configListener) batteryController.addCallback(batteryCallback) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) + zenModeController.addCallback(zenModeCallback) disposableHandle = parent.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { @@ -355,6 +400,10 @@ constructor( } smallTimeListener?.update(shouldTimeListenerRun) largeTimeListener?.update(shouldTimeListenerRun) + + // Query ZenMode data + zenModeCallback.onZenChanged(zenModeController.zen) + zenModeCallback.onNextAlarmChanged() } fun unregisterListeners() { @@ -368,6 +417,7 @@ constructor( configurationController.removeCallback(configListener) batteryController.removeCallback(batteryCallback) keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback) + zenModeController.removeCallback(zenModeCallback) smallRegionSampler?.stopRegionSampler() largeRegionSampler?.stopRegionSampler() smallTimeListener?.stop() diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 39a59c49b379..a5a545af641a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -24,7 +24,7 @@ import com.android.app.animation.Interpolators; import com.android.keyguard.dagger.KeyguardStatusViewScope; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.core.LogLevel; -import com.android.systemui.plugins.ClockController; +import com.android.systemui.plugins.clocks.ClockController; import com.android.systemui.res.R; import com.android.systemui.shared.clocks.DefaultClockController; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 54cb501db002..85c9fffcffbc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -54,7 +54,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.core.LogLevel; import com.android.systemui.log.dagger.KeyguardClockLog; -import com.android.systemui.plugins.ClockController; +import com.android.systemui.plugins.clocks.ClockController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.res.R; import com.android.systemui.shared.clocks.ClockRegistry; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index b3094838452a..714fe64f1a8f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -26,6 +26,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodManager; +import com.android.internal.logging.UiEventLogger; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; @@ -210,6 +211,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> private final KeyguardViewController mKeyguardViewController; private final FeatureFlags mFeatureFlags; private final SelectedUserInteractor mSelectedUserInteractor; + private final UiEventLogger mUiEventLogger; @Inject public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor, @@ -222,7 +224,8 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> EmergencyButtonController.Factory emergencyButtonControllerFactory, DevicePostureController devicePostureController, KeyguardViewController keyguardViewController, - FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor) { + FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, + UiEventLogger uiEventLogger) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; @@ -238,6 +241,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> mKeyguardViewController = keyguardViewController; mFeatureFlags = featureFlags; mSelectedUserInteractor = selectedUserInteractor; + mUiEventLogger = uiEventLogger; } /** Create a new {@link KeyguardInputViewController}. */ @@ -265,7 +269,8 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, emergencyButtonController, mFalsingCollector, - mDevicePostureController, mFeatureFlags, mSelectedUserInteractor); + mDevicePostureController, mFeatureFlags, mSelectedUserInteractor, + mUiEventLogger); } else if (keyguardInputView instanceof KeyguardSimPinView) { return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java index 947d90f488d1..2aab1f189263 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -20,6 +20,8 @@ import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE; import android.view.View; +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; @@ -44,6 +46,7 @@ public class KeyguardPinViewController private View mOkButton = mView.findViewById(R.id.key_enter); private long mPinLength; + private final UiEventLogger mUiEventLogger; private boolean mDisabledAutoConfirmation; @@ -56,7 +59,8 @@ public class KeyguardPinViewController EmergencyButtonController emergencyButtonController, FalsingCollector falsingCollector, DevicePostureController postureController, - FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor) { + FeatureFlags featureFlags, SelectedUserInteractor selectedUserInteractor, + UiEventLogger uiEventLogger) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, emergencyButtonController, falsingCollector, featureFlags, selectedUserInteractor); @@ -67,6 +71,7 @@ public class KeyguardPinViewController view.setIsLockScreenLandscapeEnabled(mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)); mBackspaceKey = view.findViewById(R.id.delete_button); mPinLength = mLockPatternUtils.getPinLength(selectedUserInteractor.getSelectedUserId()); + mUiEventLogger = uiEventLogger; } @Override @@ -95,6 +100,7 @@ public class KeyguardPinViewController updateAutoConfirmationState(); if (mPasswordEntry.getText().length() == mPinLength && mOkButton.getVisibility() == View.INVISIBLE) { + mUiEventLogger.log(PinBouncerUiEvent.ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE); verifyPasswordAndUnlock(); } } @@ -184,4 +190,21 @@ public class KeyguardPinViewController mSelectedUserInteractor.getSelectedUserId()) && mPinLength != LockPatternUtils.PIN_LENGTH_UNAVAILABLE; } + + /** UI Events for the auto confirmation feature in*/ + enum PinBouncerUiEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "Attempting to unlock the device with the auto confirm feature.") + ATTEMPT_UNLOCK_WITH_AUTO_CONFIRM_FEATURE(1547); + + private final int mId; + + PinBouncerUiEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 4fbf077a8852..2a54a4eee657 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -56,7 +56,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl; import com.android.systemui.keyguard.shared.model.TransitionState; import com.android.systemui.keyguard.shared.model.TransitionStep; -import com.android.systemui.plugins.ClockController; +import com.android.systemui.plugins.clocks.ClockController; import com.android.systemui.power.domain.interactor.PowerInteractor; import com.android.systemui.power.shared.model.ScreenPowerState; import com.android.systemui.res.R; @@ -70,13 +70,13 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ViewController; +import kotlin.coroutines.CoroutineContext; +import kotlin.coroutines.EmptyCoroutineContext; + import java.io.PrintWriter; import javax.inject.Inject; -import kotlin.coroutines.CoroutineContext; -import kotlin.coroutines.EmptyCoroutineContext; - /** * Injectable controller for {@link KeyguardStatusView}. */ diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index c5bb0995f492..37bd9b287ebd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -131,7 +131,7 @@ import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus; import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus; import com.android.systemui.log.SessionTracker; -import com.android.systemui.plugins.WeatherData; +import com.android.systemui.plugins.clocks.WeatherData; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 247606771155..02dd3312c587 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -23,7 +23,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.settingslib.fuelgauge.BatteryStatus; -import com.android.systemui.plugins.WeatherData; +import com.android.systemui.plugins.clocks.WeatherData; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.util.annotations.WeaklyReferencedCallback; diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java index 9716d98cf5e0..ee35bb9dff84 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.view.LayoutInflater; -import com.android.systemui.res.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Background; @@ -30,6 +29,7 @@ import com.android.systemui.flags.Flags; import com.android.systemui.log.LogBuffer; import com.android.systemui.log.dagger.KeyguardClockLog; import com.android.systemui.plugins.PluginManager; +import com.android.systemui.res.R; import com.android.systemui.shared.clocks.ClockRegistry; import com.android.systemui.shared.clocks.DefaultClockProvider; @@ -67,7 +67,8 @@ public abstract class ClockRegistryModule { context, layoutInflater, resources, - featureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION)), + featureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION), + featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)), context.getString(R.string.lockscreen_clock_id_fallback), logBuffer, /* keepAllLoaded = */ false, diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardTransitionAnimationLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardTransitionAnimationLogger.kt new file mode 100644 index 000000000000..d9830b287be5 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardTransitionAnimationLogger.kt @@ -0,0 +1,74 @@ +/* + * 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.keyguard.logging + +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.LogLevel +import com.android.systemui.log.dagger.KeyguardTransitionAnimationLog +import javax.inject.Inject + +private const val TAG = "KeyguardTransitionAnimationLog" + +/** + * Generic logger for keyguard that's wrapping [LogBuffer]. This class should be used for adding + * temporary logs or logs for smaller classes when creating whole new [LogBuffer] wrapper might be + * an overkill. + */ +class KeyguardTransitionAnimationLogger +@Inject +constructor( + @KeyguardTransitionAnimationLog val buffer: LogBuffer, +) { + @JvmOverloads + fun logCreate( + name: String? = null, + start: Float, + ) { + if (name == null) return + + buffer.log( + TAG, + LogLevel.DEBUG, + { + str1 = name + str2 = "$start" + }, + { "[$str1] starts at: $str2" } + ) + } + + @JvmOverloads + fun logTransitionStep( + name: String? = null, + step: TransitionStep, + value: Float? = null, + ) { + if (name == null) return + + buffer.log( + TAG, + LogLevel.DEBUG, + { + str1 = "[$name][${step.transitionState}]" + str2 = "${step.value}" + str3 = "$value" + }, + { "$str1 transitionStep=$str2, animationValue=$str3" } + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt index c1871e09a791..71bac06dc842 100644 --- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt +++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt @@ -209,11 +209,11 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { return result } - open fun enableShowProtection(show: Boolean) { - if (showProtection == show) { + open fun enableShowProtection(isCameraActive: Boolean) { + if (showProtection == isCameraActive) { return } - showProtection = show + showProtection = isCameraActive updateProtectionBoundingPath() // Delay the relayout until the end of the animation when hiding the cutout, // otherwise we'd clip it. diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt index 95e2dba88b90..3abcb139ab5c 100644 --- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt @@ -28,16 +28,12 @@ import android.graphics.Matrix import android.graphics.Paint import android.graphics.Path import android.graphics.RectF -import android.hardware.biometrics.BiometricSourceType import android.view.View import androidx.core.graphics.ColorUtils import com.android.app.animation.Interpolators import com.android.keyguard.KeyguardUpdateMonitor -import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.settingslib.Utils import com.android.systemui.biometrics.AuthController -import com.android.systemui.flags.FeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.log.ScreenDecorationsLogger import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.util.asIndenting @@ -56,7 +52,6 @@ class FaceScanningOverlay( val mainExecutor: Executor, val logger: ScreenDecorationsLogger, val authController: AuthController, - val featureFlags: FeatureFlags, ) : ScreenDecorations.DisplayCutoutView(context, pos) { private var showScanningAnim = false private val rimPaint = Paint() @@ -69,26 +64,11 @@ class FaceScanningOverlay( com.android.internal.R.attr.materialColorPrimaryFixed) private var cameraProtectionAnimator: ValueAnimator? = null var hideOverlayRunnable: Runnable? = null - var faceAuthSucceeded = false init { visibility = View.INVISIBLE // only show this view when face scanning is happening } - override fun onAttachedToWindow() { - super.onAttachedToWindow() - mainExecutor.execute { - keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) - } - } - - override fun onDetachedFromWindow() { - super.onDetachedFromWindow() - mainExecutor.execute { - keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback) - } - } - override fun setColor(color: Int) { cameraProtectionColor = color invalidate() @@ -106,18 +86,22 @@ class FaceScanningOverlay( } } - override fun enableShowProtection(show: Boolean) { - val animationRequired = + override fun enableShowProtection(isCameraActive: Boolean) { + val scanningAnimationRequiredWhenCameraActive = keyguardUpdateMonitor.isFaceDetectionRunning || authController.isShowing - val showScanningAnimNow = animationRequired && show - if (showScanningAnimNow == showScanningAnim) { + val faceAuthSucceeded = keyguardUpdateMonitor.isFaceAuthenticated + val showScanningAnimationNow = scanningAnimationRequiredWhenCameraActive && isCameraActive + if (showScanningAnimationNow == showScanningAnim) { return } - logger.cameraProtectionShownOrHidden(keyguardUpdateMonitor.isFaceDetectionRunning, + logger.cameraProtectionShownOrHidden( + showScanningAnimationNow, + keyguardUpdateMonitor.isFaceDetectionRunning, authController.isShowing, - show, + faceAuthSucceeded, + isCameraActive, showScanningAnim) - showScanningAnim = showScanningAnimNow + showScanningAnim = showScanningAnimationNow updateProtectionBoundingPath() // Delay the relayout until the end of the animation when hiding, // otherwise we'd clip it. @@ -128,7 +112,7 @@ class FaceScanningOverlay( cameraProtectionAnimator?.cancel() cameraProtectionAnimator = ValueAnimator.ofFloat(cameraProtectionProgress, - if (showScanningAnimNow) SHOW_CAMERA_PROTECTION_SCALE + if (showScanningAnimationNow) SHOW_CAMERA_PROTECTION_SCALE else HIDDEN_CAMERA_PROTECTION_SCALE).apply { startDelay = if (showScanningAnim) 0 @@ -297,20 +281,10 @@ class FaceScanningOverlay( } private fun createFaceScanningRimAnimator(): AnimatorSet { - val dontPulse = featureFlags.isEnabled(Flags.STOP_PULSING_FACE_SCANNING_ANIMATION) - if (dontPulse) { - return AnimatorSet().apply { - playSequentially( - cameraProtectionAnimator, - createRimAppearAnimator(), - ) - } - } return AnimatorSet().apply { playSequentially( - cameraProtectionAnimator, - createRimAppearAnimator(), - createPulseAnimator() + cameraProtectionAnimator, + createRimAppearAnimator(), ) } } @@ -348,81 +322,16 @@ class FaceScanningOverlay( invalidate() } - private fun createPulseAnimator(): ValueAnimator { - return ValueAnimator.ofFloat( - PULSE_RADIUS_OUT, PULSE_RADIUS_IN).apply { - duration = HALF_PULSE_DURATION - interpolator = Interpolators.STANDARD - repeatCount = 11 // Pulse inwards and outwards, reversing direction, 6 times - repeatMode = ValueAnimator.REVERSE - addUpdateListener(this@FaceScanningOverlay::updateRimProgress) - } - } - - private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() { - override fun onBiometricAuthenticated( - userId: Int, - biometricSourceType: BiometricSourceType?, - isStrongBiometric: Boolean - ) { - if (biometricSourceType == BiometricSourceType.FACE) { - post { - faceAuthSucceeded = true - logger.biometricEvent("biometricAuthenticated") - enableShowProtection(true) - } - } - } - - override fun onBiometricAcquired( - biometricSourceType: BiometricSourceType?, - acquireInfo: Int - ) { - if (biometricSourceType == BiometricSourceType.FACE) { - post { - faceAuthSucceeded = false // reset - } - } - } - - override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) { - if (biometricSourceType == BiometricSourceType.FACE) { - post { - faceAuthSucceeded = false - logger.biometricEvent("biometricFailed") - enableShowProtection(false) - } - } - } - - override fun onBiometricError( - msgId: Int, - errString: String?, - biometricSourceType: BiometricSourceType? - ) { - if (biometricSourceType == BiometricSourceType.FACE) { - post { - faceAuthSucceeded = false - logger.biometricEvent("biometricError") - enableShowProtection(false) - } - } - } - } - companion object { private const val HIDDEN_RIM_SCALE = HIDDEN_CAMERA_PROTECTION_SCALE private const val SHOW_CAMERA_PROTECTION_SCALE = 1f - private const val PULSE_RADIUS_IN = 1.1f private const val PULSE_RADIUS_OUT = 1.125f private const val PULSE_RADIUS_SUCCESS = 1.25f private const val CAMERA_PROTECTION_APPEAR_DURATION = 250L private const val PULSE_APPEAR_DURATION = 250L // without start delay - private const val HALF_PULSE_DURATION = 500L - private const val PULSE_SUCCESS_DISAPPEAR_DURATION = 400L private const val CAMERA_PROTECTION_SUCCESS_DISAPPEAR_DURATION = 500L // without start delay diff --git a/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java index 494efb7d3f87..45cc71ecebb9 100644 --- a/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/GuestResetOrExitSessionReceiver.java @@ -36,7 +36,6 @@ import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.UserSwitcherController; -import dagger.Lazy; import dagger.assisted.Assisted; import dagger.assisted.AssistedFactory; import dagger.assisted.AssistedInject; @@ -141,23 +140,23 @@ public final class GuestResetOrExitSessionReceiver extends BroadcastReceiver { * reset and restart of guest user. */ public static final class ResetSessionDialogFactory { - private final Lazy<SystemUIDialog> mDialogLazy; + private final SystemUIDialog.Factory mDialogFactory; private final Resources mResources; private final ResetSessionDialogClickListener.Factory mClickListenerFactory; @Inject public ResetSessionDialogFactory( - Lazy<SystemUIDialog> dialogLazy, + SystemUIDialog.Factory dialogFactory, @Main Resources resources, ResetSessionDialogClickListener.Factory clickListenerFactory) { - mDialogLazy = dialogLazy; + mDialogFactory = dialogFactory; mResources = resources; mClickListenerFactory = clickListenerFactory; } /** Create a guest reset dialog instance */ public AlertDialog create(int userId) { - SystemUIDialog dialog = mDialogLazy.get(); + SystemUIDialog dialog = mDialogFactory.create(); ResetSessionDialogClickListener listener = mClickListenerFactory.create( userId, dialog); dialog.setTitle(com.android.settingslib.R.string.guest_reset_and_restart_dialog_title); @@ -216,22 +215,22 @@ public final class GuestResetOrExitSessionReceiver extends BroadcastReceiver { * exit of guest user. */ public static final class ExitSessionDialogFactory { - private final Lazy<SystemUIDialog> mDialogLazy; + private final SystemUIDialog.Factory mDialogFactory; private final ExitSessionDialogClickListener.Factory mClickListenerFactory; private final Resources mResources; @Inject public ExitSessionDialogFactory( - Lazy<SystemUIDialog> dialogLazy, + SystemUIDialog.Factory dialogFactory, ExitSessionDialogClickListener.Factory clickListenerFactory, @Main Resources resources) { - mDialogLazy = dialogLazy; + mDialogFactory = dialogFactory; mClickListenerFactory = clickListenerFactory; mResources = resources; } public AlertDialog create(boolean isEphemeral, int userId) { - SystemUIDialog dialog = mDialogLazy.get(); + SystemUIDialog dialog = mDialogFactory.create(); ExitSessionDialogClickListener clickListener = mClickListenerFactory.create( isEphemeral, userId, dialog); if (isEphemeral) { diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 7ccf70427327..685ea81fe40d 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -5,6 +5,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.SearchManager; import android.app.StatusBarManager; @@ -146,6 +147,7 @@ public class AssistManager { private final DisplayTracker mDisplayTracker; private final SecureSettings mSecureSettings; private final SelectedUserInteractor mSelectedUserInteractor; + private final ActivityManager mActivityManager; private final DeviceProvisionedController mDeviceProvisionedController; @@ -186,7 +188,8 @@ public class AssistManager { UserTracker userTracker, DisplayTracker displayTracker, SecureSettings secureSettings, - SelectedUserInteractor selectedUserInteractor) { + SelectedUserInteractor selectedUserInteractor, + ActivityManager activityManager) { mContext = context; mDeviceProvisionedController = controller; mCommandQueue = commandQueue; @@ -199,6 +202,7 @@ public class AssistManager { mDisplayTracker = displayTracker; mSecureSettings = secureSettings; mSelectedUserInteractor = selectedUserInteractor; + mActivityManager = activityManager; registerVoiceInteractionSessionListener(); registerVisualQueryRecognitionStatusListener(); @@ -270,6 +274,9 @@ public class AssistManager { } public void startAssist(Bundle args) { + if (mActivityManager.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED) { + return; + } if (shouldOverrideAssist(args)) { try { if (mOverviewProxyService.getProxy() == null) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 8fe42b536b1e..877afce7fe65 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -86,6 +86,8 @@ import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.Execution; +import dagger.Lazy; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; @@ -133,7 +135,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull private final Provider<PromptSelectorInteractor> mPromptSelectorInteractor; @NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider; @NonNull private final Provider<PromptViewModel> mPromptViewModelProvider; - @NonNull private final LogContextInteractor mLogContextInteractor; + @NonNull private final Lazy<LogContextInteractor> mLogContextInteractor; private final Display mDisplay; private float mScaleFactor = 1f; @@ -156,7 +158,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Nullable private UdfpsOverlayParams mUdfpsOverlayParams; @Nullable private IUdfpsRefreshRateRequestCallback mUdfpsRefreshRateRequestCallback; @Nullable private SideFpsController mSideFpsController; - @NonNull private UdfpsLogger mUdfpsLogger; + @NonNull private Lazy<UdfpsLogger> mUdfpsLogger; @VisibleForTesting IBiometricSysuiReceiver mReceiver; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps; @@ -309,7 +311,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, }); mUdfpsController.setAuthControllerUpdateUdfpsLocation(this::updateUdfpsLocation); mUdfpsController.setUdfpsDisplayMode(new UdfpsDisplayMode(mContext, mExecution, - this, mUdfpsLogger)); + this, mUdfpsLogger.get())); mUdfpsBounds = mUdfpsProps.get(0).getLocation().getRect(); } @@ -755,8 +757,8 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull AuthDialogPanelInteractionDetector panelInteractionDetector, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, - @NonNull UdfpsLogger udfpsLogger, - @NonNull LogContextInteractor logContextInteractor, + @NonNull Lazy<UdfpsLogger> udfpsLogger, + @NonNull Lazy<LogContextInteractor> logContextInteractor, @NonNull Provider<PromptCredentialInteractor> promptCredentialInteractorProvider, @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider, @NonNull Provider<CredentialViewModel> credentialViewModelProvider, @@ -903,7 +905,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Override public void setBiometricContextListener(IBiometricContextListener listener) { - mLogContextInteractor.addBiometricContextListener(listener); + mLogContextInteractor.get().addBiometricContextListener(listener); } /** @@ -932,14 +934,14 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, */ public void requestMaxRefreshRate(boolean request) throws RemoteException { if (mUdfpsRefreshRateRequestCallback == null) { - mUdfpsLogger.log( + mUdfpsLogger.get().log( "PreAuthRefreshRate", "skip request - refreshRateCallback is null", LogLevel.DEBUG ); return; } - mUdfpsLogger.requestMaxRefreshRate(request); + mUdfpsLogger.get().requestMaxRefreshRate(request); mUdfpsRefreshRateRequestCallback.onAuthenticationPossible(mContext.getDisplayId(), request); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java index c22a66b210cb..df27cbb070b6 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.hardware.biometrics.BiometricSourceType; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.statusbar.phone.SystemUIDialog; import javax.inject.Inject; @@ -41,7 +40,8 @@ public class BiometricNotificationBroadcastReceiver extends BroadcastReceiver { private final Context mContext; private final BiometricNotificationDialogFactory mNotificationDialogFactory; @Inject - BiometricNotificationBroadcastReceiver(Context context, + BiometricNotificationBroadcastReceiver( + Context context, BiometricNotificationDialogFactory notificationDialogFactory) { mContext = context; mNotificationDialogFactory = notificationDialogFactory; @@ -53,15 +53,16 @@ public class BiometricNotificationBroadcastReceiver extends BroadcastReceiver { switch (action) { case ACTION_SHOW_FACE_REENROLL_DIALOG: - mNotificationDialogFactory.createReenrollDialog(mContext, - new SystemUIDialog(mContext), + mNotificationDialogFactory.createReenrollDialog( + mContext.getUserId(), + mContext::startActivity, BiometricSourceType.FACE) .show(); break; case ACTION_SHOW_FINGERPRINT_REENROLL_DIALOG: mNotificationDialogFactory.createReenrollDialog( - mContext, - new SystemUIDialog(mContext), + mContext.getUserId(), + mContext::startActivity, BiometricSourceType.FINGERPRINT) .show(); break; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java index 2962be8e55a2..fd0feef7689b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java @@ -16,9 +16,11 @@ package com.android.systemui.biometrics; +import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.app.Dialog; -import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.hardware.biometrics.BiometricSourceType; import android.hardware.face.Face; import android.hardware.face.FaceManager; @@ -29,9 +31,11 @@ import android.util.Log; import com.android.systemui.res.R; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.phone.SystemUIDialog; import javax.inject.Inject; +import javax.inject.Provider; /** * Manages the creation of dialogs to be shown for biometric re enroll notifications. @@ -39,44 +43,56 @@ import javax.inject.Inject; @SysUISingleton public class BiometricNotificationDialogFactory { private static final String TAG = "BiometricNotificationDialogFactory"; + private final Resources mResources; + private final SystemUIDialog.Factory mSystemUIDialogFactory; + @Nullable private final FingerprintManager mFingerprintManager; + @Nullable private final FaceManager mFaceManager; @Inject - BiometricNotificationDialogFactory() {} + BiometricNotificationDialogFactory( + @Main Resources resources, + SystemUIDialog.Factory systemUIDialogFactory, + @Nullable FingerprintManager fingerprintManager, + @Nullable FaceManager faceManager) { + mResources = resources; + mSystemUIDialogFactory = systemUIDialogFactory; + mFingerprintManager = fingerprintManager; + mFaceManager = faceManager; + } - Dialog createReenrollDialog(final Context context, final SystemUIDialog sysuiDialog, - BiometricSourceType biometricSourceType) { + Dialog createReenrollDialog( + int userId, ActivityStarter activityStarter, BiometricSourceType biometricSourceType) { + SystemUIDialog sysuiDialog = mSystemUIDialogFactory.create(); if (biometricSourceType == BiometricSourceType.FACE) { - sysuiDialog.setTitle(context.getString(R.string.face_re_enroll_dialog_title)); - sysuiDialog.setMessage(context.getString(R.string.face_re_enroll_dialog_content)); + sysuiDialog.setTitle(mResources.getString(R.string.face_re_enroll_dialog_title)); + sysuiDialog.setMessage(mResources.getString(R.string.face_re_enroll_dialog_content)); } else if (biometricSourceType == BiometricSourceType.FINGERPRINT) { - FingerprintManager fingerprintManager = context.getSystemService( - FingerprintManager.class); - sysuiDialog.setTitle(context.getString(R.string.fingerprint_re_enroll_dialog_title)); - if (fingerprintManager.getEnrolledFingerprints().size() == 1) { - sysuiDialog.setMessage(context.getString( + sysuiDialog.setTitle(mResources.getString(R.string.fingerprint_re_enroll_dialog_title)); + if (mFingerprintManager.getEnrolledFingerprints().size() == 1) { + sysuiDialog.setMessage(mResources.getString( R.string.fingerprint_re_enroll_dialog_content_singular)); } else { - sysuiDialog.setMessage(context.getString( + sysuiDialog.setMessage(mResources.getString( R.string.fingerprint_re_enroll_dialog_content)); } } sysuiDialog.setPositiveButton(R.string.biometric_re_enroll_dialog_confirm, - (dialog, which) -> onReenrollDialogConfirm(context, biometricSourceType)); + (dialog, which) -> onReenrollDialogConfirm( + userId, biometricSourceType, activityStarter)); sysuiDialog.setNegativeButton(R.string.biometric_re_enroll_dialog_cancel, (dialog, which) -> {}); return sysuiDialog; } - private static Dialog createReenrollFailureDialog(Context context, - BiometricSourceType biometricType) { - final SystemUIDialog sysuiDialog = new SystemUIDialog(context); + private Dialog createReenrollFailureDialog(BiometricSourceType biometricType) { + final SystemUIDialog sysuiDialog = mSystemUIDialogFactory.create(); if (biometricType == BiometricSourceType.FACE) { - sysuiDialog.setMessage(context.getString( + sysuiDialog.setMessage(mResources.getString( R.string.face_reenroll_failure_dialog_content)); } else if (biometricType == BiometricSourceType.FINGERPRINT) { - sysuiDialog.setMessage(context.getString( + sysuiDialog.setMessage(mResources.getString( R.string.fingerprint_reenroll_failure_dialog_content)); } @@ -84,41 +100,41 @@ public class BiometricNotificationDialogFactory { return sysuiDialog; } - private static void onReenrollDialogConfirm(final Context context, - BiometricSourceType biometricType) { + private void onReenrollDialogConfirm( + int userId, BiometricSourceType biometricType, ActivityStarter activityStarter) { if (biometricType == BiometricSourceType.FACE) { - reenrollFace(context); + reenrollFace(userId, activityStarter); } else if (biometricType == BiometricSourceType.FINGERPRINT) { - reenrollFingerprint(context); + reenrollFingerprint(userId, activityStarter); } } - private static void reenrollFingerprint(Context context) { - FingerprintManager fingerprintManager = context.getSystemService(FingerprintManager.class); - if (fingerprintManager == null) { + @SuppressLint("MissingPermission") + private void reenrollFingerprint(int userId, ActivityStarter activityStarter) { + if (mFingerprintManager == null) { Log.e(TAG, "Not launching enrollment. Fingerprint manager was null!"); - createReenrollFailureDialog(context, BiometricSourceType.FINGERPRINT).show(); + createReenrollFailureDialog(BiometricSourceType.FINGERPRINT).show(); return; } - if (!fingerprintManager.hasEnrolledTemplates(context.getUserId())) { - createReenrollFailureDialog(context, BiometricSourceType.FINGERPRINT).show(); + if (!mFingerprintManager.hasEnrolledTemplates(userId)) { + createReenrollFailureDialog(BiometricSourceType.FINGERPRINT).show(); return; } // Remove all enrolled fingerprint. Launch enrollment if successful. - fingerprintManager.removeAll(context.getUserId(), + mFingerprintManager.removeAll(userId, new FingerprintManager.RemovalCallback() { boolean mDidShowFailureDialog; @Override - public void onRemovalError(Fingerprint fingerprint, int errMsgId, - CharSequence errString) { + public void onRemovalError( + Fingerprint fingerprint, int errMsgId, CharSequence errString) { Log.e(TAG, "Not launching enrollment." + "Failed to remove existing face(s)."); if (!mDidShowFailureDialog) { mDidShowFailureDialog = true; - createReenrollFailureDialog(context, BiometricSourceType.FINGERPRINT) + createReenrollFailureDialog(BiometricSourceType.FINGERPRINT) .show(); } } @@ -129,27 +145,27 @@ public class BiometricNotificationDialogFactory { Intent intent = new Intent(Settings.ACTION_FINGERPRINT_ENROLL); intent.setPackage("com.android.settings"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + activityStarter.startActivity(intent); } } }); } - private static void reenrollFace(Context context) { - FaceManager faceManager = context.getSystemService(FaceManager.class); - if (faceManager == null) { + @SuppressLint("MissingPermission") + private void reenrollFace(int userId, ActivityStarter activityStarter) { + if (mFaceManager == null) { Log.e(TAG, "Not launching enrollment. Face manager was null!"); - createReenrollFailureDialog(context, BiometricSourceType.FACE).show(); + createReenrollFailureDialog(BiometricSourceType.FACE).show(); return; } - if (!faceManager.hasEnrolledTemplates(context.getUserId())) { - createReenrollFailureDialog(context, BiometricSourceType.FACE).show(); + if (!mFaceManager.hasEnrolledTemplates(userId)) { + createReenrollFailureDialog(BiometricSourceType.FACE).show(); return; } // Remove all enrolled faces. Launch enrollment if successful. - faceManager.removeAll(context.getUserId(), + mFaceManager.removeAll(userId, new FaceManager.RemovalCallback() { boolean mDidShowFailureDialog; @@ -159,7 +175,7 @@ public class BiometricNotificationDialogFactory { + "Failed to remove existing face(s)."); if (!mDidShowFailureDialog) { mDidShowFailureDialog = true; - createReenrollFailureDialog(context, BiometricSourceType.FACE).show(); + createReenrollFailureDialog(BiometricSourceType.FACE).show(); } } @@ -169,9 +185,13 @@ public class BiometricNotificationDialogFactory { Intent intent = new Intent("android.settings.FACE_ENROLL"); intent.setPackage("com.android.settings"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + activityStarter.startActivity(intent); } } }); } + + interface ActivityStarter { + void startActivity(Intent intent); + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt index 6954eb66cfa6..a2ac66f6d831 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt @@ -26,11 +26,13 @@ import com.android.app.animation.Interpolators import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.animation.ActivityLaunchAnimator -import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATION_UNLOCKED_SCREEN_OFF +import com.android.systemui.biometrics.UdfpsKeyguardViewLegacy.ANIMATE_APPEAR_ON_SCREEN_OFF import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -49,7 +51,7 @@ import java.io.PrintWriter import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch /** Class that coordinates non-HBM animations during keyguard authentication. */ @@ -191,39 +193,84 @@ open class UdfpsKeyguardViewControllerLegacy( repeatOnLifecycle(Lifecycle.State.CREATED) { listenForBouncerExpansion(this) listenForAlternateBouncerVisibility(this) + listenForOccludedToAodTransition(this) listenForGoneToAodTransition(this) listenForLockscreenAodTransitions(this) + listenForAodToOccludedTransitions(this) } } } @VisibleForTesting - suspend fun listenForGoneToAodTransition(scope: CoroutineScope): Job { + suspend fun listenForAodToOccludedTransitions(scope: CoroutineScope): Job { return scope.launch { - transitionInteractor.goneToAodTransition.collect { transitionStep -> + transitionInteractor.transition(KeyguardState.AOD, KeyguardState.OCCLUDED).collect { + transitionStep -> + view.onDozeAmountChanged( + 1f - transitionStep.value, + 1f - transitionStep.value, + UdfpsKeyguardViewLegacy.ANIMATION_NONE, + ) + } + } + } + + @VisibleForTesting + suspend fun listenForOccludedToAodTransition(scope: CoroutineScope): Job { + return scope.launch { + transitionInteractor.transition(KeyguardState.OCCLUDED, KeyguardState.AOD).collect { + transitionStep -> view.onDozeAmountChanged( transitionStep.value, transitionStep.value, - ANIMATION_UNLOCKED_SCREEN_OFF, + ANIMATE_APPEAR_ON_SCREEN_OFF, ) } } } @VisibleForTesting - suspend fun listenForLockscreenAodTransitions(scope: CoroutineScope): Job { + suspend fun listenForGoneToAodTransition(scope: CoroutineScope): Job { return scope.launch { - transitionInteractor.dozeAmountTransition.collect { transitionStep -> + transitionInteractor.goneToAodTransition.collect { transitionStep -> view.onDozeAmountChanged( transitionStep.value, transitionStep.value, - UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, + ANIMATE_APPEAR_ON_SCREEN_OFF, ) } } } @VisibleForTesting + suspend fun listenForLockscreenAodTransitions(scope: CoroutineScope): Job { + return scope.launch { + transitionInteractor.dozeAmountTransition.collect { transitionStep -> + if (transitionStep.transitionState == TransitionState.CANCELED) { + if ( + transitionInteractor.startedKeyguardTransitionStep.first().to != + KeyguardState.AOD + ) { + // If the next started transition isn't transitioning back to AOD, force + // doze amount to be 0f (as if the transition to the lockscreen completed). + view.onDozeAmountChanged( + 0f, + 0f, + UdfpsKeyguardViewLegacy.ANIMATION_NONE, + ) + } + } else { + view.onDozeAmountChanged( + transitionStep.value, + transitionStep.value, + UdfpsKeyguardViewLegacy.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, + ) + } + } + } + } + + @VisibleForTesting override suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job { return scope.launch { primaryBouncerInteractor.bouncerExpansion.collect { bouncerExpansion: Float -> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java index f4ed8cef7bb8..6d4eea852d26 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacy.java @@ -133,7 +133,7 @@ public class UdfpsKeyguardViewLegacy extends UdfpsAnimationView { // if we're animating from screen off, we can immediately place the icon in the // AoD-burn in location, else we need to translate the icon from LS => AoD. - final float darkAmountForAnimation = mAnimationType == ANIMATION_UNLOCKED_SCREEN_OFF + final float darkAmountForAnimation = mAnimationType == ANIMATE_APPEAR_ON_SCREEN_OFF ? 1f : mInterpolatedDarkAmount; final float burnInOffsetX = MathUtils.lerp(0f, getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */) @@ -171,7 +171,7 @@ public class UdfpsKeyguardViewLegacy extends UdfpsAnimationView { mAnimationType == ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN && (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f); final boolean doneAnimatingUnlockedScreenOff = - mAnimationType == ANIMATION_UNLOCKED_SCREEN_OFF + mAnimationType == ANIMATE_APPEAR_ON_SCREEN_OFF && (mInterpolatedDarkAmount == 1f); if (doneAnimatingBetweenAodAndLS || doneAnimatingUnlockedScreenOff) { mAnimationType = ANIMATION_NONE; @@ -243,10 +243,10 @@ public class UdfpsKeyguardViewLegacy extends UdfpsAnimationView { static final int ANIMATION_NONE = 0; static final int ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN = 1; - static final int ANIMATION_UNLOCKED_SCREEN_OFF = 2; + static final int ANIMATE_APPEAR_ON_SCREEN_OFF = 2; @Retention(RetentionPolicy.SOURCE) - @IntDef({ANIMATION_NONE, ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, ANIMATION_UNLOCKED_SCREEN_OFF}) + @IntDef({ANIMATION_NONE, ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, ANIMATE_APPEAR_ON_SCREEN_OFF}) private @interface AnimationType {} void onDozeAmountChanged(float linear, float eased, @AnimationType int animationType) { diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java index 17bf1a716944..b78b1f128376 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java @@ -16,16 +16,11 @@ package com.android.systemui.bluetooth; -import android.annotation.Nullable; -import android.content.Context; import android.view.View; -import com.android.internal.logging.UiEventLogger; -import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.animation.DialogLaunchAnimator; -import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.media.dialog.MediaOutputDialogFactory; +import com.android.systemui.statusbar.phone.SystemUIDialog; import javax.inject.Inject; @@ -35,25 +30,15 @@ import javax.inject.Inject; @SysUISingleton public class BroadcastDialogController { - private Context mContext; - private UiEventLogger mUiEventLogger; - private DialogLaunchAnimator mDialogLaunchAnimator; - private MediaOutputDialogFactory mMediaOutputDialogFactory; - private final LocalBluetoothManager mLocalBluetoothManager; - private BroadcastSender mBroadcastSender; + private final DialogLaunchAnimator mDialogLaunchAnimator; + private final BroadcastDialogDelegate.Factory mBroadcastDialogFactory; @Inject - public BroadcastDialogController(Context context, UiEventLogger uiEventLogger, + public BroadcastDialogController( DialogLaunchAnimator dialogLaunchAnimator, - MediaOutputDialogFactory mediaOutputDialogFactory, - @Nullable LocalBluetoothManager localBluetoothManager, - BroadcastSender broadcastSender) { - mContext = context; - mUiEventLogger = uiEventLogger; + BroadcastDialogDelegate.Factory broadcastDialogFactory) { mDialogLaunchAnimator = dialogLaunchAnimator; - mMediaOutputDialogFactory = mediaOutputDialogFactory; - mLocalBluetoothManager = localBluetoothManager; - mBroadcastSender = broadcastSender; + mBroadcastDialogFactory = broadcastDialogFactory; } /** Creates a [BroadcastDialog] for the user to switch broadcast or change the output device @@ -61,11 +46,10 @@ public class BroadcastDialogController { * @param currentBroadcastAppName Indicates the APP name currently broadcasting * @param outputPkgName Indicates the output media package name to be switched */ - public void createBroadcastDialog(String currentBroadcastAppName, String outputPkgName, - boolean aboveStatusBar, View view) { - BroadcastDialog broadcastDialog = new BroadcastDialog(mContext, mMediaOutputDialogFactory, - mLocalBluetoothManager, currentBroadcastAppName, outputPkgName, mUiEventLogger, - mBroadcastSender); + public void createBroadcastDialog( + String currentBroadcastAppName, String outputPkgName, View view) { + SystemUIDialog broadcastDialog = mBroadcastDialogFactory.create( + currentBroadcastAppName, outputPkgName).createDialog(); if (view != null) { mDialogLaunchAnimator.showFromView(broadcastDialog, view); } else { diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java index 00e952718436..00bbb20ed4f9 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -18,6 +18,8 @@ package com.android.systemui.bluetooth; import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Dialog; import android.bluetooth.BluetoothLeBroadcast; import android.bluetooth.BluetoothLeBroadcastMetadata; import android.content.Context; @@ -26,7 +28,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; -import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.widget.Button; @@ -38,39 +39,47 @@ import com.android.internal.logging.UiEventLogger; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.MediaOutputConstants; -import com.android.systemui.res.R; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.media.controls.util.MediaDataUtils; import com.android.systemui.media.dialog.MediaOutputDialogFactory; +import com.android.systemui.res.R; import com.android.systemui.statusbar.phone.SystemUIDialog; +import dagger.assisted.Assisted; +import dagger.assisted.AssistedFactory; +import dagger.assisted.AssistedInject; + +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; /** * Dialog for showing le audio broadcasting dialog. */ -public class BroadcastDialog extends SystemUIDialog { +public class BroadcastDialogDelegate implements SystemUIDialog.Delegate { private static final String TAG = "BroadcastDialog"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final int HANDLE_BROADCAST_FAILED_DELAY = 3000; + private static final String CURRENT_BROADCAST_APP = "current_broadcast_app"; + private static final String OUTPUT_PKG_NAME = "output_pkg_name"; private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); - private Context mContext; - private UiEventLogger mUiEventLogger; - @VisibleForTesting - protected View mDialogView; - private MediaOutputDialogFactory mMediaOutputDialogFactory; - private LocalBluetoothManager mLocalBluetoothManager; - private BroadcastSender mBroadcastSender; - private String mCurrentBroadcastApp; - private String mOutputPackageName; - private Executor mExecutor; + private final Context mContext; + private final UiEventLogger mUiEventLogger; + private final MediaOutputDialogFactory mMediaOutputDialogFactory; + private final LocalBluetoothManager mLocalBluetoothManager; + private final BroadcastSender mBroadcastSender; + private final SystemUIDialog.Factory mSystemUIDialogFactory; + private final String mCurrentBroadcastApp; + private final String mOutputPackageName; + private final Executor mExecutor; private boolean mShouldLaunchLeBroadcastDialog; private Button mSwitchBroadcast; + private final Set<SystemUIDialog> mDialogs = new HashSet<>(); + private final BluetoothLeBroadcast.Callback mBroadcastCallback = new BluetoothLeBroadcast.Callback() { @Override @@ -136,43 +145,64 @@ public class BroadcastDialog extends SystemUIDialog { } }; - public BroadcastDialog(Context context, MediaOutputDialogFactory mediaOutputDialogFactory, - LocalBluetoothManager localBluetoothManager, String currentBroadcastApp, - String outputPkgName, UiEventLogger uiEventLogger, BroadcastSender broadcastSender) { - super(context); - if (DEBUG) { - Log.d(TAG, "Init BroadcastDialog"); - } + @AssistedFactory + public interface Factory { + BroadcastDialogDelegate create( + @Assisted(CURRENT_BROADCAST_APP) String currentBroadcastApp, + @Assisted(OUTPUT_PKG_NAME) String outputPkgName + ); + } - mContext = getContext(); + @AssistedInject + BroadcastDialogDelegate( + Context context, + MediaOutputDialogFactory mediaOutputDialogFactory, + @Nullable LocalBluetoothManager localBluetoothManager, + UiEventLogger uiEventLogger, + Executor executor, + BroadcastSender broadcastSender, + SystemUIDialog.Factory systemUIDialogFactory, + @Assisted(CURRENT_BROADCAST_APP) String currentBroadcastApp, + @Assisted(OUTPUT_PKG_NAME) String outputPkgName) { + mContext = context; mMediaOutputDialogFactory = mediaOutputDialogFactory; mLocalBluetoothManager = localBluetoothManager; + mSystemUIDialogFactory = systemUIDialogFactory; mCurrentBroadcastApp = currentBroadcastApp; mOutputPackageName = outputPkgName; mUiEventLogger = uiEventLogger; - mExecutor = Executors.newSingleThreadExecutor(); + mExecutor = executor; mBroadcastSender = broadcastSender; + + if (DEBUG) { + Log.d(TAG, "Init BroadcastDialog"); + } + } + + @Override + public SystemUIDialog createDialog() { + return mSystemUIDialogFactory.create(this); } @Override - public void start() { + public void onStart(SystemUIDialog dialog) { + mDialogs.add(dialog); registerBroadcastCallBack(mExecutor, mBroadcastCallback); } @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + public void onCreate(SystemUIDialog dialog, Bundle savedInstanceState) { if (DEBUG) { Log.d(TAG, "onCreate"); } mUiEventLogger.log(BroadcastDialogEvent.BROADCAST_DIALOG_SHOW); - mDialogView = LayoutInflater.from(mContext).inflate(R.layout.broadcast_dialog, null); - final Window window = getWindow(); - window.setContentView(mDialogView); + View dialogView = dialog.getLayoutInflater().inflate(R.layout.broadcast_dialog, null); + final Window window = dialog.getWindow(); + window.setContentView(dialogView); - TextView title = mDialogView.requireViewById(R.id.dialog_title); - TextView subTitle = mDialogView.requireViewById(R.id.dialog_subtitle); + TextView title = dialogView.requireViewById(R.id.dialog_title); + TextView subTitle = dialogView.requireViewById(R.id.dialog_subtitle); title.setText(mContext.getString( R.string.bt_le_audio_broadcast_dialog_title, mCurrentBroadcastApp)); String switchBroadcastApp = MediaDataUtils.getAppLabel(mContext, mOutputPackageName, @@ -180,27 +210,28 @@ public class BroadcastDialog extends SystemUIDialog { subTitle.setText(mContext.getString( R.string.bt_le_audio_broadcast_dialog_sub_title, switchBroadcastApp)); - mSwitchBroadcast = mDialogView.requireViewById(R.id.switch_broadcast); - Button changeOutput = mDialogView.requireViewById(R.id.change_output); - Button cancelBtn = mDialogView.requireViewById(R.id.cancel); + mSwitchBroadcast = dialogView.requireViewById(R.id.switch_broadcast); + Button changeOutput = dialogView.requireViewById(R.id.change_output); + Button cancelBtn = dialogView.requireViewById(R.id.cancel); mSwitchBroadcast.setText(mContext.getString( R.string.bt_le_audio_broadcast_dialog_switch_app, switchBroadcastApp), null); mSwitchBroadcast.setOnClickListener((view) -> startSwitchBroadcast()); changeOutput.setOnClickListener((view) -> { mMediaOutputDialogFactory.create(mOutputPackageName, true, null); - dismiss(); + dialog.dismiss(); }); cancelBtn.setOnClickListener((view) -> { if (DEBUG) { Log.d(TAG, "BroadcastDialog dismiss."); } - dismiss(); + dialog.dismiss(); }); } @Override - public void stop() { + public void onStop(SystemUIDialog dialog) { unregisterBroadcastCallBack(mBroadcastCallback); + mDialogs.remove(dialog); } void refreshSwitchBroadcastButton() { @@ -271,10 +302,9 @@ public class BroadcastDialog extends SystemUIDialog { } @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - if (!hasFocus && isShowing()) { - dismiss(); + public void onWindowFocusChanged(SystemUIDialog dialog, boolean hasFocus) { + if (!hasFocus && dialog.isShowing()) { + dialog.dismiss(); } } @@ -333,6 +363,6 @@ public class BroadcastDialog extends SystemUIDialog { .setPackage(mContext.getPackageName()) .setAction(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG) .putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, mOutputPackageName)); - dismiss(); + mDialogs.forEach(Dialog::dismiss); } } diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java index 63b4288ce055..e0ce3db39403 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java @@ -27,7 +27,7 @@ import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_S import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.os.SystemProperties; +import android.os.Build; import android.provider.Settings; import android.util.Log; @@ -87,7 +87,7 @@ public class ClipboardListener implements String clipSource = mClipboardManager.getPrimaryClipSource(); ClipData clipData = mClipboardManager.getPrimaryClip(); - if (shouldSuppressOverlay(clipData, clipSource, isEmulator())) { + if (shouldSuppressOverlay(clipData, clipSource, Build.IS_EMULATOR)) { Log.i(TAG, "Clipboard overlay suppressed."); return; } @@ -141,10 +141,6 @@ public class ClipboardListener implements return true; } - private static boolean isEmulator() { - return SystemProperties.getBoolean("ro.boot.qemu", false); - } - private boolean isUserSetupComplete() { return Settings.Secure.getInt(mContext.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1; diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index 70736ae3fcc1..bfc80a78120d 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -61,12 +61,12 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; -import com.android.systemui.res.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule.OverlayWindowContext; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.res.R; import com.android.systemui.screenshot.TimeoutHandler; import java.util.Optional; @@ -297,6 +297,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED); mIsMinimized = true; mView.setMinimized(true); + animateIn(); } else { mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED); setExpandedView(this::animateIn); @@ -318,8 +319,8 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv } else { mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_SHOWN_EXPANDED); setExpandedView(); - animateIn(); } + animateIn(); mView.announceForAccessibility( getAccessibilityAnnouncement(mClipboardModel.getType())); } else if (!mIsMinimized) { diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt b/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt new file mode 100644 index 000000000000..3648f3b2c3b9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt @@ -0,0 +1,46 @@ +/* + * 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 + */ +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.common.ui.domain.interactor + +import com.android.systemui.common.ui.data.repository.ConfigurationRepository +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.onStart + +/** Business logic related to configuration changes. */ +@SysUISingleton +class ConfigurationInteractor @Inject constructor(private val repository: ConfigurationRepository) { + /** Given [resourceId], emit the dimension pixel size on config change */ + fun dimensionPixelSize(resourceId: Int): Flow<Int> { + return onAnyConfigurationChange.mapLatest { repository.getDimensionPixelSize(resourceId) } + } + + /** Given a set of [resourceId]s, emit Map<ResourceId, DimensionPixelSize> on config change */ + fun dimensionPixelSize(resourceIds: Set<Int>): Flow<Map<Int, Int>> { + return onAnyConfigurationChange.mapLatest { + resourceIds.associateWith { repository.getDimensionPixelSize(it) } + } + } + + /** Emit an event on any config change */ + val onAnyConfigurationChange: Flow<Unit> = + repository.onAnyConfigurationChange.onStart { emit(Unit) } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt index ad02f6280a64..4219d6d6f397 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalHubSection.kt @@ -2,63 +2,16 @@ package com.android.systemui.communal.ui.view.layout.sections import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet -import com.android.systemui.communal.ui.viewmodel.CommunalViewModel -import com.android.systemui.compose.ComposeFacade import com.android.systemui.keyguard.shared.model.KeyguardSection -import com.android.systemui.keyguard.ui.view.layout.sections.removeView -import com.android.systemui.res.R import javax.inject.Inject /** A keyguard section that hosts the communal hub. */ -class DefaultCommunalHubSection -@Inject -constructor( - private val viewModel: CommunalViewModel, -) : KeyguardSection() { - private val communalHubViewId = R.id.communal_hub - - override fun addViews(constraintLayout: ConstraintLayout) { - constraintLayout.addView( - ComposeFacade.createCommunalView( - context = constraintLayout.context, - viewModel = viewModel, - ) - .apply { id = communalHubViewId }, - ) - } +class DefaultCommunalHubSection @Inject constructor() : KeyguardSection() { + override fun addViews(constraintLayout: ConstraintLayout) {} override fun bindData(constraintLayout: ConstraintLayout) {} - override fun applyConstraints(constraintSet: ConstraintSet) { - constraintSet.apply { - connect( - communalHubViewId, - ConstraintSet.START, - ConstraintSet.PARENT_ID, - ConstraintSet.START, - ) - connect( - communalHubViewId, - ConstraintSet.TOP, - ConstraintSet.PARENT_ID, - ConstraintSet.TOP, - ) - connect( - communalHubViewId, - ConstraintSet.END, - ConstraintSet.PARENT_ID, - ConstraintSet.END, - ) - connect( - communalHubViewId, - ConstraintSet.BOTTOM, - ConstraintSet.PARENT_ID, - ConstraintSet.BOTTOM, - ) - } - } + override fun applyConstraints(constraintSet: ConstraintSet) {} - override fun removeViews(constraintLayout: ConstraintLayout) { - constraintLayout.removeView(communalHubViewId) - } + override fun removeViews(constraintLayout: ConstraintLayout) {} } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt index 4d8e893cb747..bed42833a1d4 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt @@ -16,16 +16,22 @@ package com.android.systemui.communal.ui.viewmodel +import android.os.PowerManager +import android.os.SystemClock +import android.view.MotionEvent import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.media.controls.ui.MediaHost +import com.android.systemui.shade.ShadeViewController import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow /** The base view model for the communal hub. */ abstract class BaseCommunalViewModel( private val communalInteractor: CommunalInteractor, + private val shadeViewController: ShadeViewController, + private val powerManager: PowerManager, val mediaHost: MediaHost, ) { val isKeyguardVisible: Flow<Boolean> = communalInteractor.isKeyguardVisible @@ -36,6 +42,26 @@ abstract class BaseCommunalViewModel( communalInteractor.onSceneChanged(scene) } + // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block + // touches anymore. + /** Called when a touch is received outside the edge swipe area when hub mode is closed. */ + fun onOuterTouch(motionEvent: MotionEvent) { + // Forward the touch to the shade so that basic gestures like swipe up/down for + // shade/bouncer work. + shadeViewController.handleExternalTouch(motionEvent) + } + + // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block + // touches anymore. + /** Called to refresh the screen timeout when a user touch is received. */ + fun onUserActivity() { + powerManager.userActivity( + SystemClock.uptimeMillis(), + PowerManager.USER_ACTIVITY_EVENT_TOUCH, + 0 + ) + } + /** A list of all the communal content to be displayed in the communal hub. */ abstract val communalContent: Flow<List<CommunalContentModel>> diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt index 111f8b4ca48f..b6843c529180 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt @@ -16,11 +16,13 @@ package com.android.systemui.communal.ui.viewmodel +import android.os.PowerManager import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.media.controls.ui.MediaHost import com.android.systemui.media.dagger.MediaModule +import com.android.systemui.shade.ShadeViewController import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.flow.Flow @@ -31,8 +33,10 @@ class CommunalEditModeViewModel @Inject constructor( private val communalInteractor: CommunalInteractor, + shadeViewController: ShadeViewController, + powerManager: PowerManager, @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, -) : BaseCommunalViewModel(communalInteractor, mediaHost) { +) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) { override val isEditMode = true diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 11bde6bd7af0..d7dcdb9ea4f0 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -16,12 +16,14 @@ package com.android.systemui.communal.ui.viewmodel +import android.os.PowerManager import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.media.controls.ui.MediaHost import com.android.systemui.media.dagger.MediaModule +import com.android.systemui.shade.ShadeViewController import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -37,8 +39,10 @@ class CommunalViewModel constructor( private val communalInteractor: CommunalInteractor, tutorialInteractor: CommunalTutorialInteractor, + shadeViewController: ShadeViewController, + powerManager: PowerManager, @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, -) : BaseCommunalViewModel(communalInteractor, mediaHost) { +) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) { @OptIn(ExperimentalCoroutinesApi::class) override val communalContent: Flow<List<CommunalContentModel>> = tutorialInteractor.isTutorialAvailable.flatMapLatest { isTutorialMode -> diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt index 70d713845f00..4e40042a49b0 100644 --- a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt @@ -16,31 +16,19 @@ package com.android.systemui.contrast import android.app.Activity -import android.app.UiModeManager -import android.content.Context import android.os.Bundle -import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.settings.UserTracker -import com.android.systemui.util.settings.SecureSettings -import java.util.concurrent.Executor import javax.inject.Inject -/** Trampoline activity responsible for creating a [ContrastDialog] */ +/** Trampoline activity responsible for creating a [ContrastDialogDelegate] */ class ContrastDialogActivity @Inject constructor( - private val context: Context, - @Main private val mainExecutor: Executor, - private val uiModeManager: UiModeManager, - private val userTracker: UserTracker, - private val secureSettings: SecureSettings + private val contrastDialogDelegate : ContrastDialogDelegate ) : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val contrastDialog = - ContrastDialog(context, mainExecutor, uiModeManager, userTracker, secureSettings) - contrastDialog.show() + contrastDialogDelegate.createDialog().show() finish() } } diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt index e9b59306c552..63b01edb01fa 100644 --- a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogDelegate.kt @@ -21,54 +21,58 @@ import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_MEDIUM import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_STANDARD import android.app.UiModeManager.ContrastUtils.fromContrastLevel import android.app.UiModeManager.ContrastUtils.toContrastLevel -import android.content.Context import android.os.Bundle import android.provider.Settings -import android.view.LayoutInflater import android.view.View import android.widget.FrameLayout import com.android.internal.annotations.VisibleForTesting -import com.android.systemui.res.R import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.settings.SecureSettings import java.util.concurrent.Executor +import javax.inject.Inject /** Dialog to select contrast options */ -class ContrastDialog( - context: Context?, +class ContrastDialogDelegate @Inject constructor( + private val sysuiDialogFactory : SystemUIDialog.Factory, @Main private val mainExecutor: Executor, private val uiModeManager: UiModeManager, private val userTracker: UserTracker, private val secureSettings: SecureSettings, -) : SystemUIDialog(context), UiModeManager.ContrastChangeListener { +) : SystemUIDialog.Delegate, UiModeManager.ContrastChangeListener { + + override fun createDialog(): SystemUIDialog { + return sysuiDialogFactory.create(this) + } @VisibleForTesting lateinit var contrastButtons: Map<Int, FrameLayout> lateinit var dialogView: View @VisibleForTesting var initialContrast: Float = fromContrastLevel(CONTRAST_LEVEL_STANDARD) - public override fun onCreate(savedInstanceState: Bundle?) { - dialogView = LayoutInflater.from(context).inflate(R.layout.contrast_dialog, null) - setView(dialogView) + override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { + dialogView = dialog.layoutInflater.inflate(R.layout.contrast_dialog, null) + with(dialog) { + setView(dialogView) - setTitle(R.string.quick_settings_contrast_label) - setNeutralButton(R.string.cancel) { _, _ -> - secureSettings.putFloatForUser( - Settings.Secure.CONTRAST_LEVEL, - initialContrast, - userTracker.userId - ) - dismiss() + setTitle(R.string.quick_settings_contrast_label) + setNeutralButton(R.string.cancel) { _, _ -> + secureSettings.putFloatForUser( + Settings.Secure.CONTRAST_LEVEL, + initialContrast, + userTracker.userId + ) + dialog.dismiss() + } + setPositiveButton(com.android.settingslib.R.string.done) { _, _ -> dialog.dismiss() } } - setPositiveButton(com.android.settingslib.R.string.done) { _, _ -> dismiss() } - super.onCreate(savedInstanceState) - contrastButtons = mapOf( - CONTRAST_LEVEL_STANDARD to requireViewById(R.id.contrast_button_standard), - CONTRAST_LEVEL_MEDIUM to requireViewById(R.id.contrast_button_medium), - CONTRAST_LEVEL_HIGH to requireViewById(R.id.contrast_button_high) + CONTRAST_LEVEL_STANDARD to dialogView.requireViewById( + R.id.contrast_button_standard), + CONTRAST_LEVEL_MEDIUM to dialogView.requireViewById(R.id.contrast_button_medium), + CONTRAST_LEVEL_HIGH to dialogView.requireViewById(R.id.contrast_button_high) ) contrastButtons.forEach { (contrastLevel, contrastButton) -> @@ -86,11 +90,11 @@ class ContrastDialog( highlightContrast(toContrastLevel(initialContrast)) } - override fun start() { + override fun onStart(dialog: SystemUIDialog) { uiModeManager.addContrastChangeListener(mainExecutor, this) } - override fun stop() { + override fun onStop(dialog: SystemUIDialog) { uiModeManager.removeContrastChangeListener(this) } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index e7b87730f94b..9672facb8610 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -36,8 +36,6 @@ import com.android.systemui.unfold.FoldStateLogger; import com.android.systemui.unfold.FoldStateLoggingProvider; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; -import com.android.systemui.unfold.dagger.UnfoldBg; -import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.desktopmode.DesktopMode; @@ -139,26 +137,19 @@ public interface SysUIComponent { c.getUnfoldHapticsPlayer(); c.getNaturalRotationUnfoldProgressProvider().init(); c.getUnfoldLatencyTracker().init(); + c.getFoldStateLoggingProvider() + .ifPresent(FoldStateLoggingProvider::init); + c.getFoldStateLogger().ifPresent(FoldStateLogger::init); + final UnfoldTransitionProgressProvider progressProvider = + Flags.unfoldAnimationBackgroundProgress() + ? c.getBgUnfoldTransitionProgressProvider() + : c.getUnfoldTransitionProgressProvider(); + progressProvider.addCallback(c.getUnfoldTransitionProgressForwarder()); }); // No init method needed, just needs to be gotten so that it's created. getMediaMuteAwaitConnectionCli(); getNearbyMediaDevicesManager(); getConnectingDisplayViewModel().init(); - getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init); - getFoldStateLogger().ifPresent(FoldStateLogger::init); - - Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider; - - if (Flags.unfoldAnimationBackgroundProgress()) { - unfoldTransitionProgressProvider = getBgUnfoldTransitionProgressProvider(); - } else { - unfoldTransitionProgressProvider = getUnfoldTransitionProgressProvider(); - } - unfoldTransitionProgressProvider - .ifPresent( - (progressProvider) -> - getUnfoldTransitionProgressForwarder() - .ifPresent(progressProvider::addCallback)); } /** @@ -180,37 +171,6 @@ public interface SysUIComponent { ContextComponentHelper getContextComponentHelper(); /** - * Creates a UnfoldTransitionProgressProvider that calculates progress in the background. - */ - @SysUISingleton - @UnfoldBg - Optional<UnfoldTransitionProgressProvider> getBgUnfoldTransitionProgressProvider(); - - /** - * Creates a UnfoldTransitionProgressProvider that calculates progress in the main thread. - */ - @SysUISingleton - Optional<UnfoldTransitionProgressProvider> getUnfoldTransitionProgressProvider(); - - /** - * Creates a UnfoldTransitionProgressForwarder. - */ - @SysUISingleton - Optional<UnfoldTransitionProgressForwarder> getUnfoldTransitionProgressForwarder(); - - /** - * Creates a FoldStateLoggingProvider. - */ - @SysUISingleton - Optional<FoldStateLoggingProvider> getFoldStateLoggingProvider(); - - /** - * Creates a FoldStateLogger. - */ - @SysUISingleton - Optional<FoldStateLogger> getFoldStateLogger(); - - /** * Main dependency providing module. */ @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt index 4bfc9484f733..615b503b9fae 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt @@ -34,7 +34,6 @@ import com.android.systemui.FaceScanningOverlay import com.android.systemui.biometrics.AuthController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.flags.FeatureFlags import com.android.systemui.log.ScreenDecorationsLogger import com.android.systemui.plugins.statusbar.StatusBarStateController import java.util.concurrent.Executor @@ -48,7 +47,6 @@ class FaceScanningProviderFactory @Inject constructor( private val keyguardUpdateMonitor: KeyguardUpdateMonitor, @Main private val mainExecutor: Executor, private val logger: ScreenDecorationsLogger, - private val featureFlags: FeatureFlags, ) : DecorProviderFactory() { private val display = context.display private val displayInfo = DisplayInfo() @@ -88,7 +86,6 @@ class FaceScanningProviderFactory @Inject constructor( keyguardUpdateMonitor, mainExecutor, logger, - featureFlags, ) ) } @@ -113,7 +110,6 @@ class FaceScanningOverlayProviderImpl( private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val mainExecutor: Executor, private val logger: ScreenDecorationsLogger, - private val featureFlags: FeatureFlags, ) : BoundDecorProvider() { override val viewId: Int = com.android.systemui.res.R.id.face_scanning_anim @@ -148,7 +144,6 @@ class FaceScanningOverlayProviderImpl( mainExecutor, logger, authController, - featureFlags ) view.id = viewId view.setColor(tintColor) diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index ff65b312f48b..7cb2c6e1fcff 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -253,12 +253,6 @@ object Flags { val KEYGUARD_WM_STATE_REFACTOR: UnreleasedFlag = unreleasedFlag("keyguard_wm_state_refactor") - /** Flag to disable the face scanning animation pulsing. */ - // TODO(b/295245791): Tracking bug. - @JvmField val STOP_PULSING_FACE_SCANNING_ANIMATION = resourceBooleanFlag( - R.bool.flag_stop_pulsing_face_scanning_animation, - "stop_pulsing_face_scanning_animation") - // 300 - power menu // TODO(b/254512600): Tracking Bug @JvmField val POWER_MENU_LITE = releasedFlag("power_menu_lite") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index c8c06ae65d45..01ba0d214a97 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -41,6 +41,7 @@ import com.android.keyguard.KeyguardViewController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.Flags.fastUnlockTransition import com.android.systemui.plugins.BcSmartspaceDataPlugin import com.android.systemui.shared.recents.utilities.Utilities import com.android.systemui.shared.system.ActivityManagerWrapper @@ -98,7 +99,8 @@ const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.3f * from a tap on the unlock icon, or from the bouncer. This is not relevant if the lockscreen is * swiped away via a touch gesture, or when it's flinging expanded/collapsed after a swipe. */ -const val UNLOCK_ANIMATION_DURATION_MS = 200L +const val LEGACY_UNLOCK_ANIMATION_DURATION_MS = 200L +const val UNLOCK_ANIMATION_DURATION_MS = 167L /** * How long the in-window launcher icon animation takes. This is used if the launcher is underneath @@ -112,19 +114,22 @@ const val LAUNCHER_ICONS_ANIMATION_DURATION_MS = 633L /** * How long to wait for the shade to get out of the way before starting the canned unlock animation. */ -const val CANNED_UNLOCK_START_DELAY = 100L +const val LEGACY_CANNED_UNLOCK_START_DELAY = 100L +const val CANNED_UNLOCK_START_DELAY = 67L /** * Duration for the alpha animation on the surface behind. This plays to fade in the surface during * a swipe to unlock (and to fade it back out if the swipe is cancelled). */ -const val SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 175L +const val LEGACY_SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 175L +const val SURFACE_BEHIND_FADE_OUT_DURATION_MS = 83L /** * Start delay for the surface behind animation, used so that the lockscreen can get out of the way * before the surface begins appearing. */ -const val UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 75L +const val LEGACY_UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS = 75L +const val SURFACE_BEHIND_FADE_OUT_START_DELAY_MS = 0L /** * Initiates, controls, and ends the keyguard unlock animation. @@ -327,7 +332,7 @@ class KeyguardUnlockAnimationController @Inject constructor( init { with(surfaceBehindAlphaAnimator) { - duration = SURFACE_BEHIND_SWIPE_FADE_DURATION_MS + duration = surfaceBehindFadeOutDurationMs() interpolator = Interpolators.LINEAR addUpdateListener { valueAnimator: ValueAnimator -> surfaceBehindAlpha = valueAnimator.animatedValue as Float @@ -355,8 +360,10 @@ class KeyguardUnlockAnimationController @Inject constructor( } with(wallpaperCannedUnlockAnimator) { - duration = LAUNCHER_ICONS_ANIMATION_DURATION_MS - interpolator = Interpolators.ALPHA_OUT + duration = if (fastUnlockTransition()) UNLOCK_ANIMATION_DURATION_MS + else LAUNCHER_ICONS_ANIMATION_DURATION_MS + interpolator = if (fastUnlockTransition()) Interpolators.LINEAR + else Interpolators.ALPHA_OUT addUpdateListener { valueAnimator: ValueAnimator -> setWallpaperAppearAmount(valueAnimator.animatedValue as Float) } @@ -370,8 +377,8 @@ class KeyguardUnlockAnimationController @Inject constructor( } with(surfaceBehindEntryAnimator) { - duration = UNLOCK_ANIMATION_DURATION_MS - startDelay = UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS + duration = unlockAnimationDurationMs() + startDelay = surfaceBehindFadeOutStartDelayMs() interpolator = Interpolators.TOUCH_RESPONSE addUpdateListener { valueAnimator: ValueAnimator -> surfaceBehindAlpha = valueAnimator.animatedValue as Float @@ -573,7 +580,7 @@ class KeyguardUnlockAnimationController @Inject constructor( try { launcherUnlockController?.playUnlockAnimation( true, - UNLOCK_ANIMATION_DURATION_MS + CANNED_UNLOCK_START_DELAY, + unlockAnimationDurationMs() + cannedUnlockStartDelayMs(), 0 /* startDelay */) } catch (e: DeadObjectException) { // Hello! If you are here investigating a bug where Launcher is blank (no icons) @@ -602,12 +609,15 @@ class KeyguardUnlockAnimationController @Inject constructor( // Notify if waking from AOD only val isWakeAndUnlockNotFromDream = biometricUnlockControllerLazy.get().isWakeAndUnlock && biometricUnlockControllerLazy.get().mode != MODE_WAKE_AND_UNLOCK_FROM_DREAM + + val duration = if (fastUnlockTransition()) UNLOCK_ANIMATION_DURATION_MS + else LAUNCHER_ICONS_ANIMATION_DURATION_MS listeners.forEach { it.onUnlockAnimationStarted( playingCannedUnlockAnimation /* playingCannedAnimation */, isWakeAndUnlockNotFromDream /* isWakeAndUnlockNotFromDream */, - CANNED_UNLOCK_START_DELAY /* unlockStartDelay */, - LAUNCHER_ICONS_ANIMATION_DURATION_MS /* unlockAnimationDuration */) } + cannedUnlockStartDelayMs() /* unlockStartDelay */, + duration /* unlockAnimationDuration */) } // Finish the keyguard remote animation if the dismiss amount has crossed the threshold. // Check it here in case there is no more change to the dismiss amount after the last change @@ -675,7 +685,7 @@ class KeyguardUnlockAnimationController @Inject constructor( launcherUnlockController?.playUnlockAnimation( true /* unlocked */, LAUNCHER_ICONS_ANIMATION_DURATION_MS /* duration */, - CANNED_UNLOCK_START_DELAY /* startDelay */) + cannedUnlockStartDelayMs() /* startDelay */) } catch (e: DeadObjectException) { // Hello! If you are here investigating a bug where Launcher is blank (no icons) // then the below assumption about Launcher's destruction was incorrect. This @@ -696,9 +706,10 @@ class KeyguardUnlockAnimationController @Inject constructor( lockscreenSmartspace?.visibility = View.INVISIBLE } - // As soon as the shade has animated out of the way, start the canned unlock animation, + // As soon as the shade starts animating out of the way, start the canned unlock animation, // which will finish keyguard exit when it completes. The in-window animations in the // Launcher window will end on their own. + if (fastUnlockTransition()) hideKeyguardViewAfterRemoteAnimation() handler.postDelayed({ if (keyguardViewMediator.get().isShowingAndNotOccluded && !keyguardStateController.isKeyguardGoingAway) { @@ -709,12 +720,12 @@ class KeyguardUnlockAnimationController @Inject constructor( if ((wallpaperTargets?.isNotEmpty() == true)) { fadeInWallpaper() - hideKeyguardViewAfterRemoteAnimation() + if (!fastUnlockTransition()) hideKeyguardViewAfterRemoteAnimation() } else { keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( false /* cancelled */) } - }, CANNED_UNLOCK_START_DELAY) + }, cannedUnlockStartDelayMs()) } /** @@ -1130,6 +1141,43 @@ class KeyguardUnlockAnimationController @Inject constructor( ?: false } + /** + * Temporary method for b/298186160 + * TODO (b/298186160) replace references with the constant itself when flag is removed + */ + private fun cannedUnlockStartDelayMs(): Long { + return if (fastUnlockTransition()) CANNED_UNLOCK_START_DELAY + else LEGACY_CANNED_UNLOCK_START_DELAY + } + + /** + * Temporary method for b/298186160 + * TODO (b/298186160) replace references with the constant itself when flag is removed + */ + private fun unlockAnimationDurationMs(): Long { + return if (fastUnlockTransition()) UNLOCK_ANIMATION_DURATION_MS + else LEGACY_UNLOCK_ANIMATION_DURATION_MS + } + + /** + * Temporary method for b/298186160 + * TODO (b/298186160) replace references with the constant itself when flag is removed + */ + private fun surfaceBehindFadeOutDurationMs(): Long { + return if (fastUnlockTransition()) SURFACE_BEHIND_FADE_OUT_DURATION_MS + else LEGACY_SURFACE_BEHIND_SWIPE_FADE_DURATION_MS + } + + /** + * Temporary method for b/298186160 + * TODO (b/298186160) replace references with the constant itself when flag is removed + */ + private fun surfaceBehindFadeOutStartDelayMs(): Long { + return if (fastUnlockTransition()) SURFACE_BEHIND_FADE_OUT_START_DELAY_MS + else LEGACY_UNLOCK_ANIMATION_SURFACE_BEHIND_START_DELAY_MS + } + + companion object { fun isFoldable(context: Context): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index 36412e31e7c0..e47c44863980 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -187,8 +187,7 @@ constructor( faceManager?.sensorPropertiesInternal?.firstOrNull()?.supportsFaceDetection ?: false private val _isAuthRunning = MutableStateFlow(false) - override val isAuthRunning: StateFlow<Boolean> - get() = _isAuthRunning + override val isAuthRunning: StateFlow<Boolean> = _isAuthRunning private val keyguardSessionId: InstanceId? get() = sessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD) @@ -254,6 +253,13 @@ constructor( ) .andAllFlows("canFaceAuthRun", faceAuthLog) .flowOn(backgroundDispatcher) + .onEach { + faceAuthLogger.canFaceAuthRunChanged(it) + if (!it) { + // Cancel currently running auth if any of the gating checks are false. + cancel() + } + } .stateIn(applicationScope, SharingStarted.Eagerly, false) // Face detection can run only when lockscreen bypass is enabled @@ -281,9 +287,12 @@ constructor( ) .andAllFlows("canFaceDetectRun", faceDetectLog) .flowOn(backgroundDispatcher) + .onEach { + if (!it) { + cancelDetection() + } + } .stateIn(applicationScope, SharingStarted.Eagerly, false) - observeFaceAuthGatingChecks() - observeFaceDetectGatingChecks() observeFaceAuthResettingConditions() listenForSchedulingWatchdog() processPendingAuthRequests() @@ -317,6 +326,7 @@ constructor( it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS }, ) + .flowOn(backgroundDispatcher) .onEach { anyOfThemIsTrue -> if (anyOfThemIsTrue) { clearPendingAuthRequest("Resetting auth status") @@ -337,17 +347,6 @@ constructor( pendingAuthenticateRequest.value = null } - private fun observeFaceDetectGatingChecks() { - canRunDetection - .onEach { - if (!it) { - cancelDetection() - } - } - .flowOn(mainDispatcher) - .launchIn(applicationScope) - } - private fun isUdfps() = deviceEntryFingerprintAuthRepository.availableFpSensorType.map { it == BiometricType.UNDER_DISPLAY_FINGERPRINT @@ -406,20 +405,6 @@ constructor( ) } - private fun observeFaceAuthGatingChecks() { - canRunFaceAuth - .onEach { - faceAuthLogger.canFaceAuthRunChanged(it) - if (!it) { - // Cancel currently running auth if any of the gating checks are false. - faceAuthLogger.cancellingFaceAuth() - cancel() - } - } - .flowOn(mainDispatcher) - .launchIn(applicationScope) - } - private val faceAuthCallback = object : FaceManager.AuthenticationCallback() { override fun onAuthenticationFailed() { @@ -554,7 +539,7 @@ constructor( authenticate(it.uiEvent, it.fallbackToDetection) } } - .flowOn(mainDispatcher) + .flowOn(backgroundDispatcher) .launchIn(applicationScope) } @@ -650,6 +635,7 @@ constructor( override fun cancel() { if (authCancellationSignal == null) return + faceAuthLogger.cancellingFaceAuth() authCancellationSignal?.cancel() cancelNotReceivedHandlerJob?.cancel() cancelNotReceivedHandlerJob = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt index d1c62188d3fc..5e3779a1a59d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt @@ -19,34 +19,71 @@ package com.android.systemui.keyguard.data.repository import android.os.UserHandle import android.provider.Settings import androidx.annotation.VisibleForTesting -import com.android.keyguard.KeyguardClockSwitch.SMALL +import com.android.keyguard.ClockEventController +import com.android.keyguard.KeyguardClockSwitch.ClockSize +import com.android.keyguard.KeyguardClockSwitch.LARGE import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.shared.model.SettingsClockSize -import com.android.systemui.plugins.ClockId +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockId import com.android.systemui.shared.clocks.ClockRegistry import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext +interface KeyguardClockRepository { + /** clock size determined by notificationPanelViewController, LARGE or SMALL */ + val clockSize: StateFlow<Int> + + /** clock size selected in picker, DYNAMIC or SMALL */ + val selectedClockSize: Flow<SettingsClockSize> + + /** clock id, selected from clock carousel in wallpaper picker */ + val currentClockId: Flow<ClockId> + + val currentClock: StateFlow<ClockController?> + + val clockEventController: ClockEventController + fun setClockSize(@ClockSize size: Int) +} + @SysUISingleton -class KeyguardClockRepository +class KeyguardClockRepositoryImpl @Inject constructor( private val secureSettings: SecureSettings, private val clockRegistry: ClockRegistry, + override val clockEventController: ClockEventController, @Background private val backgroundDispatcher: CoroutineDispatcher, -) { + @Application private val applicationScope: CoroutineScope, +) : KeyguardClockRepository { + + /** Receive SMALL or LARGE clock should be displayed on keyguard. */ + private val _clockSize: MutableStateFlow<Int> = MutableStateFlow(LARGE) + override val clockSize: StateFlow<Int> = _clockSize.asStateFlow() - val selectedClockSize: Flow<SettingsClockSize> = + override fun setClockSize(size: Int) { + _clockSize.value = size + } + + override val selectedClockSize: Flow<SettingsClockSize> = secureSettings .observerFlow( names = arrayOf(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK), @@ -55,7 +92,7 @@ constructor( .onStart { emit(Unit) } // Forces an initial update. .map { getClockSize() } - val currentClockId: Flow<ClockId> = + override val currentClockId: Flow<ClockId> = callbackFlow { fun send() { trySend(clockRegistry.currentClockId) @@ -72,8 +109,16 @@ constructor( awaitClose { clockRegistry.unregisterClockChangeListener(listener) } } .mapNotNull { it } + .distinctUntilChanged() - val currentClock = currentClockId.map { clockRegistry.createCurrentClock() } + override val currentClock: StateFlow<ClockController?> = + currentClockId + .map { clockRegistry.createCurrentClock() } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = clockRegistry.createCurrentClock() + ) @VisibleForTesting suspend fun getClockSize(): SettingsClockSize { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index 6ff446edca38..2d6c0e1c13b2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -18,8 +18,6 @@ package com.android.systemui.keyguard.data.repository import android.graphics.Point import android.hardware.biometrics.BiometricSourceType -import com.android.keyguard.KeyguardClockSwitch.ClockSize -import com.android.keyguard.KeyguardClockSwitch.LARGE import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.biometrics.AuthController @@ -39,7 +37,6 @@ import com.android.systemui.keyguard.shared.model.DismissAction import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.KeyguardDone -import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.policy.KeyguardStateController @@ -180,9 +177,6 @@ interface KeyguardRepository { /** Whether quick settings or quick-quick settings is visible. */ val isQuickSettingsVisible: Flow<Boolean> - /** Represents the current state of the KeyguardRootView visibility */ - val keyguardRootViewVisibility: Flow<KeyguardRootViewVisibilityState> - /** Receive an event for doze time tick */ val dozeTimeTick: Flow<Long> @@ -192,9 +186,6 @@ interface KeyguardRepository { /** Observable updated when keyguardDone should be called either now or soon. */ val keyguardDone: Flow<KeyguardDone> - /** Receive SMALL or LARGE clock should be displayed on keyguard. */ - val clockSize: Flow<Int> - /** Receive whether clock should be centered on lockscreen. */ val clockShouldBeCentered: Flow<Boolean> @@ -216,12 +207,6 @@ interface KeyguardRepository { /** Sets the current amount of alpha that should be used for rendering the keyguard. */ fun setKeyguardAlpha(alpha: Float) - fun setKeyguardVisibility( - statusBarState: Int, - goingToFullShade: Boolean, - occlusionTransitionRunning: Boolean - ) - /** * Sets the relative offset of the lock-screen clock from its natural position on the screen. */ @@ -247,8 +232,6 @@ interface KeyguardRepository { suspend fun setKeyguardDone(keyguardDoneType: KeyguardDone) - fun setClockSize(@ClockSize size: Int) - fun setClockShouldBeCentered(shouldBeCentered: Boolean) } @@ -293,9 +276,6 @@ constructor( private val _clockPosition = MutableStateFlow(Position(0, 0)) override val clockPosition = _clockPosition.asStateFlow() - private val _clockSize = MutableStateFlow(LARGE) - override val clockSize: Flow<Int> = _clockSize.asStateFlow() - private val _clockShouldBeCentered = MutableStateFlow(true) override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered.asStateFlow() @@ -631,17 +611,6 @@ constructor( private val _isActiveDreamLockscreenHosted = MutableStateFlow(false) override val isActiveDreamLockscreenHosted = _isActiveDreamLockscreenHosted.asStateFlow() - private val _keyguardRootViewVisibility = - MutableStateFlow( - KeyguardRootViewVisibilityState( - com.android.systemui.statusbar.StatusBarState.SHADE, - goingToFullShade = false, - occlusionTransitionRunning = false, - ) - ) - override val keyguardRootViewVisibility: Flow<KeyguardRootViewVisibilityState> = - _keyguardRootViewVisibility.asStateFlow() - override fun setAnimateDozingTransitions(animate: Boolean) { _animateBottomAreaDozingTransitions.value = animate } @@ -654,19 +623,6 @@ constructor( _keyguardAlpha.value = alpha } - override fun setKeyguardVisibility( - statusBarState: Int, - goingToFullShade: Boolean, - occlusionTransitionRunning: Boolean - ) { - _keyguardRootViewVisibility.value = - KeyguardRootViewVisibilityState( - statusBarState, - goingToFullShade, - occlusionTransitionRunning - ) - } - override fun setClockPosition(x: Int, y: Int) { _clockPosition.value = Position(x, y) } @@ -681,10 +637,6 @@ constructor( _isActiveDreamLockscreenHosted.value = isLockscreenHosted } - override fun setClockSize(@ClockSize size: Int) { - _clockSize.value = size - } - override fun setClockShouldBeCentered(shouldBeCentered: Boolean) { _clockShouldBeCentered.value = shouldBeCentered } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt index 565962394db1..6138330c2e76 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt @@ -74,4 +74,6 @@ interface KeyguardRepositoryModule { fun bind(impl: BouncerMessageAuditLogger): CoreStartable @Binds fun trustRepository(impl: TrustRepositoryImpl): TrustRepository + + @Binds fun keyguardClockRepository(impl: KeyguardClockRepositoryImpl): KeyguardClockRepository } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt index 5c76be80f1ad..0e487d297b40 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt @@ -103,7 +103,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio private val _transitions = MutableSharedFlow<TransitionStep>( replay = 2, - extraBufferCapacity = 10, + extraBufferCapacity = 20, onBufferOverflow = BufferOverflow.DROP_OLDEST, ) override val transitions = _transitions.asSharedFlow().distinctUntilChanged() @@ -227,10 +227,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio private fun emitTransition(nextStep: TransitionStep, isManual: Boolean = false) { logAndTrace(nextStep, isManual) - val emitted = _transitions.tryEmit(nextStep) - if (!emitted) { - Log.w(TAG, "Failed to emit next value without suspending") - } + _transitions.tryEmit(nextStep) lastStep = nextStep } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt index 2f103f612563..356c4085ab48 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt @@ -18,13 +18,15 @@ package com.android.systemui.keyguard.domain.interactor import com.android.keyguard.ClockEventController +import com.android.keyguard.KeyguardClockSwitch.ClockSize import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.KeyguardClockRepository import com.android.systemui.keyguard.shared.model.SettingsClockSize -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockId +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockId import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow private val TAG = KeyguardClockInteractor::class.simpleName /** Manages keyguard clock for the lockscreen root view. */ @@ -33,7 +35,6 @@ private val TAG = KeyguardClockInteractor::class.simpleName class KeyguardClockInteractor @Inject constructor( - val eventController: ClockEventController, private val keyguardClockRepository: KeyguardClockRepository, ) { @@ -41,11 +42,17 @@ constructor( val currentClockId: Flow<ClockId> = keyguardClockRepository.currentClockId - val currentClock: Flow<ClockController> = keyguardClockRepository.currentClock + val currentClock: StateFlow<ClockController?> = keyguardClockRepository.currentClock - var clock: ClockController? - get() = eventController.clock - set(value) { - eventController.clock = value + var clock: ClockController? by keyguardClockRepository.clockEventController::clock + + val clockSize: StateFlow<Int> = keyguardClockRepository.clockSize + fun setClockSize(@ClockSize size: Int) { + keyguardClockRepository.setClockSize(size) + } + + val clockEventController: ClockEventController + get() { + return keyguardClockRepository.clockEventController } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index e58d7710877b..b8c392591494 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -23,13 +23,12 @@ import android.app.StatusBarManager import android.graphics.Point import android.util.MathUtils import com.android.app.animation.Interpolators -import com.android.keyguard.KeyguardClockSwitch.ClockSize import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.shared.model.NotificationContainerBounds import com.android.systemui.common.shared.model.Position -import com.android.systemui.common.ui.data.repository.ConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.shared.model.BiometricUnlockModel @@ -77,7 +76,7 @@ constructor( powerInteractor: PowerInteractor, sceneContainerFlags: SceneContainerFlags, bouncerRepository: KeyguardBouncerRepository, - configurationRepository: ConfigurationRepository, + configurationInteractor: ConfigurationInteractor, shadeRepository: ShadeRepository, sceneInteractorProvider: Provider<SceneInteractor>, ) { @@ -213,37 +212,29 @@ constructor( /** The approximate location on the screen of the face unlock sensor, if one is available. */ val faceSensorLocation: Flow<Point?> = repository.faceSensorLocation - /** Notifies when a new configuration is set */ - val configurationChange: Flow<Unit> = - configurationRepository.onAnyConfigurationChange.onStart { emit(Unit) } - /** The position of the keyguard clock. */ val clockPosition: Flow<Position> = repository.clockPosition val keyguardAlpha: Flow<Float> = repository.keyguardAlpha val keyguardTranslationY: Flow<Float> = - configurationChange.flatMapLatest { - val translationDistance = - configurationRepository.getDimensionPixelSize( - R.dimen.keyguard_translate_distance_on_swipe_up - ) - shadeRepository.shadeModel.map { - if (it.expansionAmount == 0f) { - // Reset the translation value - 0f - } else { - // On swipe up, translate the keyguard to reveal the bouncer - MathUtils.lerp( - translationDistance, - 0, - Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(it.expansionAmount) - ) + configurationInteractor + .dimensionPixelSize(R.dimen.keyguard_translate_distance_on_swipe_up) + .flatMapLatest { translationDistance -> + shadeRepository.shadeModel.map { + if (it.expansionAmount == 0f) { + // Reset the translation value + 0f + } else { + // On swipe up, translate the keyguard to reveal the bouncer + MathUtils.lerp( + translationDistance, + 0, + Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(it.expansionAmount) + ) + } } } - } - - val clockSize: Flow<Int> = repository.clockSize.distinctUntilChanged() val clockShouldBeCentered: Flow<Boolean> = repository.clockShouldBeCentered @@ -297,18 +288,6 @@ constructor( repository.setQuickSettingsVisible(isVisible) } - fun setKeyguardRootVisibility( - statusBarState: Int, - goingToFullShade: Boolean, - isOcclusionTransitionRunning: Boolean - ) { - repository.setKeyguardVisibility( - statusBarState, - goingToFullShade, - isOcclusionTransitionRunning - ) - } - fun setClockPosition(x: Int, y: Int) { repository.setClockPosition(x, y) } @@ -321,10 +300,6 @@ constructor( repository.setAnimateDozingTransitions(animate) } - fun setClockSize(@ClockSize size: Int) { - repository.setClockSize(size) - } - fun setClockShouldBeCentered(shouldBeCentered: Boolean) { repository.setClockShouldBeCentered(shouldBeCentered) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt index ae356cd94350..532df4afebf7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt @@ -29,6 +29,7 @@ import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository @@ -69,6 +70,7 @@ constructor( private val context: Context, @Application private val applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, + @Background private val backgroundDispatcher: CoroutineDispatcher, private val repository: DeviceEntryFaceAuthRepository, private val primaryBouncerInteractor: Lazy<PrimaryBouncerInteractor>, private val alternateBouncerInteractor: AlternateBouncerInteractor, @@ -104,6 +106,7 @@ constructor( fallbackToDetect = false ) } + .flowOn(backgroundDispatcher) .launchIn(applicationScope) alternateBouncerInteractor.isVisible @@ -115,6 +118,7 @@ constructor( fallbackToDetect = false ) } + .flowOn(backgroundDispatcher) .launchIn(applicationScope) merge( @@ -143,6 +147,7 @@ constructor( fallbackToDetect = true ) } + .flowOn(backgroundDispatcher) .launchIn(applicationScope) deviceEntryFingerprintAuthRepository.isLockedOut @@ -155,6 +160,7 @@ constructor( } } } + .flowOn(backgroundDispatcher) .launchIn(applicationScope) // User switching should stop face auth and then when it is complete we should trigger face @@ -178,6 +184,7 @@ constructor( ) } } + .flowOn(backgroundDispatcher) .launchIn(applicationScope) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt index d5ad7ab0d0d1..64ff3b0c238a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt @@ -17,97 +17,134 @@ package com.android.systemui.keyguard.ui import android.view.animation.Interpolator import com.android.app.animation.Interpolators.LINEAR +import com.android.keyguard.logging.KeyguardTransitionAnimationLogger +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING import com.android.systemui.keyguard.shared.model.TransitionState.STARTED import com.android.systemui.keyguard.shared.model.TransitionStep +import javax.inject.Inject import kotlin.math.max import kotlin.math.min import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.shareIn /** - * For the given transition params, construct a flow using [createFlow] for the specified portion of - * the overall transition. + * Assists in creating sub-flows for a KeyguardTransition. Call [setup] once for a transition, and + * then [sharedFlow] for each sub animation that should be trigged when the overall transition runs. */ -class KeyguardTransitionAnimationFlow( - private val transitionDuration: Duration, - private val transitionFlow: Flow<TransitionStep>, +@SysUISingleton +class KeyguardTransitionAnimationFlow +@Inject +constructor( + @Application private val scope: CoroutineScope, + private val logger: KeyguardTransitionAnimationLogger, ) { + /** - * Transitions will occur over a [transitionDuration] with [TransitionStep]s being emitted in - * the range of [0, 1]. View animations should begin and end within a subset of this range. This - * function maps the [startTime] and [duration] into [0, 1], when this subset is valid. + * Invoke once per transition between FROM->TO states to get access to + * [SharedFlowBuilder#sharedFlow]. */ - fun createFlow( + fun setup( duration: Duration, - onStep: (Float) -> Float, - startTime: Duration = 0.milliseconds, - onStart: (() -> Unit)? = null, - onCancel: (() -> Float)? = null, - onFinish: (() -> Float)? = null, - interpolator: Interpolator = LINEAR, - ): Flow<Float> { - if (!duration.isPositive()) { - throw IllegalArgumentException("duration must be a positive number: $duration") - } - if ((startTime + duration).compareTo(transitionDuration) > 0) { - throw IllegalArgumentException( - "startTime($startTime) + duration($duration) must be" + - " <= transitionDuration($transitionDuration)" - ) - } + stepFlow: Flow<TransitionStep>, + ) = SharedFlowBuilder(duration, stepFlow) - val start = (startTime / transitionDuration).toFloat() - val chunks = (transitionDuration / duration).toFloat() - var isComplete = true + inner class SharedFlowBuilder( + private val transitionDuration: Duration, + private val stepFlow: Flow<TransitionStep>, + ) { + /** + * Transitions will occur over a [transitionDuration] with [TransitionStep]s being emitted + * in the range of [0, 1]. View animations should begin and end within a subset of this + * range. This function maps the [startTime] and [duration] into [0, 1], when this subset is + * valid. + * + * Will produce a [SharedFlow], so that identical animations can use the same value. + */ + fun sharedFlow( + duration: Duration, + onStep: (Float) -> Float, + startTime: Duration = 0.milliseconds, + onStart: (() -> Unit)? = null, + onCancel: (() -> Float)? = null, + onFinish: (() -> Float)? = null, + interpolator: Interpolator = LINEAR, + name: String? = null + ): SharedFlow<Float> { + if (!duration.isPositive()) { + throw IllegalArgumentException("duration must be a positive number: $duration") + } + if ((startTime + duration).compareTo(transitionDuration) > 0) { + throw IllegalArgumentException( + "startTime($startTime) + duration($duration) must be" + + " <= transitionDuration($transitionDuration)" + ) + } - fun stepToValue(step: TransitionStep): Float? { - val value = (step.value - start) * chunks - return when (step.transitionState) { - // When starting, make sure to always emit. If a transition is started from the - // middle, it is possible this animation is being skipped but we need to inform - // the ViewModels of the last update - STARTED -> { - isComplete = false - onStart?.invoke() - max(0f, min(1f, value)) - } - // Always send a final value of 1. Because of rounding, [value] may never be - // exactly 1. - RUNNING -> - if (isComplete) { - null - } else if (value >= 1f) { - isComplete = true - 1f - } else if (value >= 0f) { - value - } else { - null + val start = (startTime / transitionDuration).toFloat() + val chunks = (transitionDuration / duration).toFloat() + logger.logCreate(name, start) + var isComplete = true + + fun stepToValue(step: TransitionStep): Float? { + val value = (step.value - start) * chunks + return when (step.transitionState) { + // When starting, make sure to always emit. If a transition is started from the + // middle, it is possible this animation is being skipped but we need to inform + // the ViewModels of the last update + STARTED -> { + isComplete = false + onStart?.invoke() + max(0f, min(1f, value)) } - else -> null - }?.let { onStep(interpolator.getInterpolation(it)) } - } + // Always send a final value of 1. Because of rounding, [value] may never be + // exactly 1. + RUNNING -> + if (isComplete) { + null + } else if (value >= 1f) { + isComplete = true + 1f + } else if (value >= 0f) { + value + } else { + null + } + else -> null + }?.let { onStep(interpolator.getInterpolation(it)) } + } - return transitionFlow - .map { step -> - when (step.transitionState) { - STARTED -> stepToValue(step) - RUNNING -> stepToValue(step) - CANCELED -> onCancel?.invoke() - FINISHED -> onFinish?.invoke() + return stepFlow + .map { step -> + val value = + when (step.transitionState) { + STARTED -> stepToValue(step) + RUNNING -> stepToValue(step) + CANCELED -> onCancel?.invoke() + FINISHED -> onFinish?.invoke() + } + logger.logTransitionStep(name, step, value) + value } - } - .filterNotNull() - } + .filterNotNull() + .shareIn(scope, SharingStarted.WhileSubscribed()) + } - /** Immediately (after 1ms) emits the given value for every step of the KeyguardTransition. */ - fun immediatelyTransitionTo(value: Float): Flow<Float> { - return createFlow(duration = 1.milliseconds, onStep = { value }, onFinish = { value }) + /** + * Immediately (after 1ms) emits the given value for every step of the KeyguardTransition. + */ + fun immediatelyTransitionTo(value: Float): Flow<Float> { + return sharedFlow(duration = 1.milliseconds, onStep = { value }, onFinish = { value }) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt index c688cfff2bf9..b1c40b533503 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt @@ -17,18 +17,19 @@ package com.android.systemui.keyguard.ui.binder import android.transition.TransitionManager +import androidx.annotation.VisibleForTesting +import androidx.constraintlayout.helper.widget.Layer import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor -import com.android.systemui.keyguard.ui.view.layout.items.ClockSection +import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.lifecycle.repeatWhenAttached -import com.android.systemui.plugins.ClockController +import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.res.R import kotlinx.coroutines.launch @@ -40,13 +41,12 @@ object KeyguardClockViewBinder { clockSection: ClockSection, keyguardRootView: ConstraintLayout, viewModel: KeyguardClockViewModel, - keyguardBlueprintInteractor: KeyguardBlueprintInteractor, keyguardClockInteractor: KeyguardClockInteractor, featureFlags: FeatureFlagsClassic, ) { keyguardRootView.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { - keyguardClockInteractor.eventController.registerListeners(keyguardRootView) + keyguardClockInteractor.clockEventController.registerListeners(keyguardRootView) } } keyguardRootView.repeatWhenAttached { @@ -54,10 +54,11 @@ object KeyguardClockViewBinder { launch { if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) return@launch viewModel.currentClock.collect { currentClock -> - viewModel.clock?.let { clock -> cleanupClockViews(clock, keyguardRootView) } + cleanupClockViews(viewModel.clock, keyguardRootView, viewModel.burnInLayer) viewModel.clock = currentClock - addClockViews(currentClock, keyguardRootView) - keyguardBlueprintInteractor.refreshBlueprint() + addClockViews(currentClock, keyguardRootView, viewModel.burnInLayer) + viewModel.burnInLayer?.updatePostLayout(keyguardRootView) + applyConstraints(clockSection, keyguardRootView, true) } } // TODO: Weather clock dozing animation @@ -71,13 +72,61 @@ object KeyguardClockViewBinder { } launch { if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) return@launch - viewModel.clockShouldBeCentered.collect { shouldBeCentered -> - clockSection.setClockShouldBeCentered( - viewModel.useLargeClock && shouldBeCentered - ) + viewModel.clockShouldBeCentered.collect { applyConstraints(clockSection, keyguardRootView, true) } } + launch { + if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) return@launch + viewModel.hasCustomWeatherDataDisplay.collect { + applyConstraints(clockSection, keyguardRootView, true) + } + } + } + } + } + + private fun cleanupClockViews( + clockController: ClockController?, + rootView: ConstraintLayout, + burnInLayer: Layer? + ) { + clockController?.let { clock -> + clock.smallClock.layout.views.forEach { + burnInLayer?.removeView(it) + rootView.removeView(it) + } + // add large clock to burn in layer only when it will have same transition with other + // components in AOD + // otherwise, it will have a separate scale transition while other components only have + // translate transition + if (clock.config.useAlternateSmartspaceAODTransition) { + clock.largeClock.layout.views.forEach { burnInLayer?.removeView(it) } + } + clock.largeClock.layout.views.forEach { rootView.removeView(it) } + } + } + + @VisibleForTesting + fun addClockViews( + clockController: ClockController?, + rootView: ConstraintLayout, + burnInLayer: Layer? + ) { + clockController?.let { clock -> + clock.smallClock.layout.views[0].id = R.id.lockscreen_clock_view + if (clock.largeClock.layout.views.size == 1) { + clock.largeClock.layout.views[0].id = R.id.lockscreen_clock_view_large + } + // small clock should either be a single view or container with id + // `lockscreen_clock_view` + clock.smallClock.layout.views.forEach { + rootView.addView(it) + burnInLayer?.addView(it) + } + clock.largeClock.layout.views.forEach { rootView.addView(it) } + if (clock.config.useAlternateSmartspaceAODTransition) { + clock.largeClock.layout.views.forEach { burnInLayer?.addView(it) } } } } @@ -92,22 +141,6 @@ object KeyguardClockViewBinder { if (animated) { TransitionManager.beginDelayedTransition(rootView) } - constraintSet.applyTo(rootView) } - - private fun cleanupClockViews(clock: ClockController, rootView: ConstraintLayout) { - clock.smallClock.layout.views.forEach { rootView.removeView(it) } - clock.largeClock.layout.views.forEach { rootView.removeView(it) } - } - - private fun addClockViews(clock: ClockController, rootView: ConstraintLayout) { - clock.smallClock.layout.views[0].id = R.id.lockscreen_clock_view - if (clock.largeClock.layout.views.size == 1) { - clock.largeClock.layout.views[0].id = R.id.lockscreen_clock_view_large - } - // small clock should either be a single view or container with id `lockscreen_clock_view` - clock.smallClock.layout.views.forEach { rootView.addView(it) } - clock.largeClock.layout.views.forEach { rootView.addView(it) } - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt index 1a8f62597037..4efd9ef5f21c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt @@ -23,10 +23,10 @@ import android.widget.TextView import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.Flags.keyguardBottomAreaRefactor -import com.android.systemui.res.R import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.res.R import com.android.systemui.statusbar.KeyguardIndicationController import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index c0d3d336719e..ebc9c5b79739 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -41,12 +41,13 @@ import com.android.systemui.common.shared.model.TintedIcon import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.lifecycle.repeatWhenAttached -import com.android.systemui.plugins.ClockController +import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.CrossFadeHelper @@ -88,7 +89,7 @@ object KeyguardRootViewBinder { vibratorHelper: VibratorHelper?, ): DisposableHandle { var onLayoutChangeListener: OnLayoutChange? = null - val childViews = mutableMapOf<Int, View?>() + val childViews = mutableMapOf<Int, View>() val statusViewId = R.id.keyguard_status_view val burnInLayerId = R.id.burn_in_layer val aodNotificationIconContainerId = R.id.aod_notification_icon_container @@ -113,7 +114,12 @@ object KeyguardRootViewBinder { } if (keyguardBottomAreaRefactor()) { - launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } } + launch { + viewModel.alpha.collect { alpha -> + view.alpha = alpha + childViews[statusViewId]?.alpha = alpha + } + } } if (KeyguardShadeMigrationNssl.isEnabled) { @@ -140,25 +146,35 @@ object KeyguardRootViewBinder { } launch { + // When translation happens in burnInLayer, it won't be weather clock + // large clock isn't added to burnInLayer due to its scale transition + // so we also need to add translation to it here + // same as translationX viewModel.translationY.collect { y -> childViews[burnInLayerId]?.translationY = y + childViews[largeClockId]?.translationY = y } } launch { viewModel.translationX.collect { x -> childViews[burnInLayerId]?.translationX = x + childViews[largeClockId]?.translationX = x } } launch { viewModel.scale.collect { (scale, scaleClockOnly) -> if (scaleClockOnly) { + // For clocks except weather clock, we have scale transition + // besides translate childViews[largeClockId]?.let { it.scaleX = scale it.scaleY = scale } } else { + // For weather clock, large clock should have only scale + // transition with other parts in burnInLayer childViews[burnInLayerId]?.scaleX = scale childViews[burnInLayerId]?.scaleY = scale } @@ -247,7 +263,10 @@ object KeyguardRootViewBinder { } } } - viewModel.clockControllerProvider = clockControllerProvider + + if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { + viewModel.clockControllerProvider = clockControllerProvider + } onLayoutChangeListener = OnLayoutChange(viewModel) view.addOnLayoutChangeListener(onLayoutChangeListener) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt index 41a2e509b5d0..954d2cf6ed8a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt @@ -1,3 +1,19 @@ +/* + * 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.ui.binder import androidx.constraintlayout.widget.ConstraintLayout diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index 59c798bfca1e..4eecfdefa663 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -27,6 +27,8 @@ import android.hardware.display.DisplayManager import android.os.Bundle import android.os.Handler import android.os.IBinder +import android.provider.Settings +import android.util.Log import android.view.ContextThemeWrapper import android.view.Display import android.view.Display.DEFAULT_DISPLAY @@ -47,6 +49,7 @@ import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl @@ -64,8 +67,9 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombin import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.monet.ColorScheme -import com.android.systemui.plugins.ClockController +import com.android.systemui.monet.Style import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shared.clocks.ClockRegistry @@ -79,13 +83,21 @@ import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import com.android.systemui.statusbar.phone.KeyguardBottomAreaView import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator +import com.android.systemui.util.settings.SecureSettings import dagger.assisted.Assisted import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.json.JSONException +import org.json.JSONObject /** Renders the preview of the lock screen. */ class KeyguardPreviewRenderer @@ -93,8 +105,10 @@ class KeyguardPreviewRenderer @AssistedInject constructor( @Application private val context: Context, + @Application applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, @Main private val mainHandler: Handler, + @Background private val backgroundDispatcher: CoroutineDispatcher, private val clockViewModel: KeyguardPreviewClockViewModel, private val smartspaceViewModel: KeyguardPreviewSmartspaceViewModel, private val bottomAreaViewModel: KeyguardBottomAreaViewModel, @@ -118,8 +132,8 @@ constructor( private val chipbarCoordinator: ChipbarCoordinator, private val screenOffAnimationController: ScreenOffAnimationController, private val shadeInteractor: ShadeInteractor, + private val secureSettings: SecureSettings, ) { - val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN) private val width: Int = bundle.getInt(KEY_VIEW_WIDTH) private val height: Int = bundle.getInt(KEY_VIEW_HEIGHT) @@ -157,7 +171,13 @@ constructor( private val shortcutsBindings = mutableSetOf<KeyguardQuickAffordanceViewBinder.Binding>() + private val coroutineScope: CoroutineScope + private var themeStyle: Style? = null + init { + coroutineScope = CoroutineScope(applicationScope.coroutineContext + Job()) + disposables.add(DisposableHandle { coroutineScope.cancel() }) + if (keyguardBottomAreaRefactor()) { quickAffordancesCombinedViewModel.enablePreviewMode( initiallySelectedSlotId = @@ -554,29 +574,54 @@ constructor( } private fun onClockChanged() { - val clock = clockRegistry.createCurrentClock() - clockController.clock = clock - - if (clockRegistry.seedColor == null) { - // Seed color null means users do override any color on the clock. The default color - // will need to use wallpaper's extracted color and consider if the wallpaper's color - // is dark or a light. - // TODO(b/277832214) we can potentially simplify this code by checking for - // wallpaperColors being null in the if clause above and removing the many ?. - val wallpaperColorScheme = wallpaperColors?.let { ColorScheme(it, darkTheme = false) } - val lightClockColor = wallpaperColorScheme?.accent1?.s100 - val darkClockColor = wallpaperColorScheme?.accent2?.s600 - - // Note that when [wallpaperColors] is null, isWallpaperDark is true. - val isWallpaperDark: Boolean = - (wallpaperColors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) == 0 - clock.events.onSeedColorChanged( - if (isWallpaperDark) lightClockColor else darkClockColor - ) + coroutineScope.launch { + val clock = clockRegistry.createCurrentClock() + clockController.clock = clock + + val colors = wallpaperColors + if (clockRegistry.seedColor == null && colors != null) { + // Seed color null means users do not override any color on the clock. The default + // color will need to use wallpaper's extracted color and consider if the + // wallpaper's color is dark or light. + val style = themeStyle ?: fetchThemeStyleFromSetting().also { themeStyle = it } + val wallpaperColorScheme = ColorScheme(colors, darkTheme = false, style) + val lightClockColor = wallpaperColorScheme.accent1.s100 + val darkClockColor = wallpaperColorScheme.accent2.s600 + + // Note that when [wallpaperColors] is null, isWallpaperDark is true. + val isWallpaperDark: Boolean = + (colors.colorHints.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) == 0 + clock.events.onSeedColorChanged( + if (isWallpaperDark) lightClockColor else darkClockColor + ) + } + + updateLargeClock(clock) + updateSmallClock(clock) } + } - updateLargeClock(clock) - updateSmallClock(clock) + private suspend fun fetchThemeStyleFromSetting(): Style { + val overlayPackageJson = + withContext(backgroundDispatcher) { + secureSettings.getString( + Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, + ) + } + return if (!overlayPackageJson.isNullOrEmpty()) { + try { + val jsonObject = JSONObject(overlayPackageJson) + Style.valueOf(jsonObject.getString(OVERLAY_CATEGORY_THEME_STYLE)) + } catch (e: (JSONException)) { + Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e) + Style.TONAL_SPOT + } catch (e: IllegalArgumentException) { + Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e) + Style.TONAL_SPOT + } + } else { + Style.TONAL_SPOT + } } private fun updateLargeClock(clock: ClockController) { @@ -602,6 +647,8 @@ constructor( } companion object { + private const val TAG = "KeyguardPreviewRenderer" + private const val OVERLAY_CATEGORY_THEME_STYLE = "android.theme.customization.theme_style" private const val KEY_HOST_TOKEN = "host_token" private const val KEY_VIEW_WIDTH = "width" private const val KEY_VIEW_HEIGHT = "height" diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt index fa27442707a3..1c6a2abdcbe7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt @@ -21,9 +21,9 @@ import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialInd import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.KeyguardBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection -import com.android.systemui.keyguard.ui.view.layout.items.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection +import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection @@ -75,10 +75,10 @@ constructor( defaultStatusBarSection, defaultNotificationStackScrollLayoutSection, aodNotificationIconsSection, + smartspaceSection, aodBurnInSection, communalTutorialIndicatorSection, clockSection, - smartspaceSection, defaultDeviceEntrySection, // Add LAST: Intentionally has z-order above other views. ) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt index 484d351a362e..df9ae41ed970 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodBurnInSection.kt @@ -22,8 +22,12 @@ import android.view.View import androidx.constraintlayout.helper.widget.Layer import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.keyguard.shared.model.KeyguardSection +import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel +import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R import javax.inject.Inject @@ -32,21 +36,31 @@ class AodBurnInSection @Inject constructor( private val context: Context, + private val clockViewModel: KeyguardClockViewModel, + private val smartspaceViewModel: KeyguardSmartspaceViewModel, + private val featureFlags: FeatureFlagsClassic, ) : KeyguardSection() { + lateinit var burnInLayer: Layer override fun addViews(constraintLayout: ConstraintLayout) { if (!KeyguardShadeMigrationNssl.isEnabled) { return } - val statusView = constraintLayout.requireViewById<View>(R.id.keyguard_status_view) val nic = constraintLayout.requireViewById<View>(R.id.aod_notification_icon_container) - val burnInLayer = + burnInLayer = Layer(context).apply { id = R.id.burn_in_layer addView(nic) - addView(statusView) + if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { + val statusView = + constraintLayout.requireViewById<View>(R.id.keyguard_status_view) + addView(statusView) + } } + if (featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { + addSmartspaceViews(constraintLayout) + } constraintLayout.addView(burnInLayer) } @@ -54,6 +68,9 @@ constructor( if (!KeyguardShadeMigrationNssl.isEnabled) { return } + if (featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { + clockViewModel.burnInLayer = burnInLayer + } } override fun applyConstraints(constraintSet: ConstraintSet) { @@ -65,4 +82,22 @@ constructor( override fun removeViews(constraintLayout: ConstraintLayout) { constraintLayout.removeView(R.id.burn_in_layer) } + + private fun addSmartspaceViews(constraintLayout: ConstraintLayout) { + burnInLayer.apply { + if (smartspaceViewModel.isSmartspaceEnabled) { + val smartspaceView = + constraintLayout.requireViewById<View>(smartspaceViewModel.smartspaceViewId) + addView(smartspaceView) + if (smartspaceViewModel.isDateWeatherDecoupled) { + val dateView = + constraintLayout.requireViewById<View>(smartspaceViewModel.dateId) + val weatherView = + constraintLayout.requireViewById<View>(smartspaceViewModel.weatherId) + addView(weatherView) + addView(dateView) + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index 941c295ab86a..c8b2d3995a65 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -15,7 +15,7 @@ * */ -package com.android.systemui.keyguard.ui.view.layout.items +package com.android.systemui.keyguard.ui.view.layout.sections import android.content.Context import android.view.View @@ -28,18 +28,16 @@ import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockFaceLayout +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockFaceLayout import com.android.systemui.res.R import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.Utils -import dagger.Lazy import javax.inject.Inject internal fun ConstraintSet.setVisibility( @@ -60,7 +58,6 @@ constructor( val smartspaceViewModel: KeyguardSmartspaceViewModel, private val context: Context, private val splitShadeStateController: SplitShadeStateController, - private val keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>, private val featureFlags: FeatureFlagsClassic, ) : KeyguardSection() { override fun addViews(constraintLayout: ConstraintLayout) {} @@ -70,7 +67,6 @@ constructor( this, constraintLayout, keyguardClockViewModel, - keyguardBlueprintInteractor.get(), clockInteractor, featureFlags ) @@ -109,15 +105,15 @@ constructor( return previousValue != largeClockEndGuideline } - fun getTargetClockFace(clock: ClockController): ClockFaceLayout = + private fun getTargetClockFace(clock: ClockController): ClockFaceLayout = if (keyguardClockViewModel.useLargeClock) getLargeClockFace(clock) else getSmallClockFace(clock) - fun getNonTargetClockFace(clock: ClockController): ClockFaceLayout = + private fun getNonTargetClockFace(clock: ClockController): ClockFaceLayout = if (keyguardClockViewModel.useLargeClock) getSmallClockFace(clock) else getLargeClockFace(clock) - fun getLargeClockFace(clock: ClockController): ClockFaceLayout = clock.largeClock.layout - fun getSmallClockFace(clock: ClockController): ClockFaceLayout = clock.smallClock.layout + private fun getLargeClockFace(clock: ClockController): ClockFaceLayout = clock.largeClock.layout + private fun getSmallClockFace(clock: ClockController): ClockFaceLayout = clock.smallClock.layout fun applyDefaultConstraints(constraints: ConstraintSet) { constraints.apply { connect(R.id.lockscreen_clock_view_large, START, PARENT_ID, START) @@ -138,6 +134,7 @@ constructor( ) } connect(R.id.lockscreen_clock_view_large, TOP, PARENT_ID, TOP, largeClockTopMargin) + constrainHeight(R.id.lockscreen_clock_view_large, WRAP_CONTENT) constrainWidth(R.id.lockscreen_clock_view_large, WRAP_CONTENT) constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT) constrainHeight( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt index 8aef7c23b45d..56f717d7e4ef 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt @@ -22,12 +22,12 @@ import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import com.android.systemui.Flags.keyguardBottomAreaRefactor -import com.android.systemui.res.R import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel +import com.android.systemui.res.R import com.android.systemui.statusbar.KeyguardIndicationController import javax.inject.Inject import kotlinx.coroutines.DisposableHandle diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt index 4abcca9d1151..851a45f31705 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt @@ -53,7 +53,7 @@ constructor( private val keyguardViewConfigurator: Lazy<KeyguardViewConfigurator>, private val notificationPanelViewController: Lazy<NotificationPanelViewController>, private val keyguardMediaController: KeyguardMediaController, - private val splitShadeStateController: SplitShadeStateController + private val splitShadeStateController: SplitShadeStateController, ) : KeyguardSection() { private val statusViewId = R.id.keyguard_status_view @@ -76,6 +76,9 @@ constructor( keyguardStatusView.findViewById<View>(R.id.left_aligned_notification_icon_container)?.let { it.setVisibility(View.GONE) } + // Should keep this even if flag, migrating clocks to blueprint, is on + // cause some events in clockEventController rely on keyguardStatusViewController + // TODO(b/313499340): clean up constraintLayout.addView(keyguardStatusView) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt index 25931a654cd2..a005692c6dbf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt @@ -47,9 +47,9 @@ constructor( val keyguardUnlockAnimationController: KeyguardUnlockAnimationController, val featureFlags: FeatureFlagsClassic, ) : KeyguardSection() { - var smartspaceView: View? = null - var weatherView: View? = null - var dateView: View? = null + private var smartspaceView: View? = null + private var weatherView: View? = null + private var dateView: View? = null override fun addViews(constraintLayout: ConstraintLayout) { if (!featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { @@ -65,16 +65,11 @@ constructor( constraintLayout.addView(dateView) } } - keyguardUnlockAnimationController.lockscreenSmartspace = smartspaceView } override fun bindData(constraintLayout: ConstraintLayout) { - KeyguardSmartspaceViewBinder.bind( - this, - constraintLayout, - keyguardClockViewModel, - ) + KeyguardSmartspaceViewBinder.bind(this, constraintLayout, keyguardClockViewModel) } override fun applyConstraints(constraintSet: ConstraintSet) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt index bb7bcd99ffb6..8e729f76e096 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt @@ -38,15 +38,17 @@ class AlternateBouncerViewModel constructor( private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, transitionInteractor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { // When we're fully transitioned to the AlternateBouncer, the alpha of the scrim should be: private val alternateBouncerScrimAlpha = .66f private val toAlternateBouncerTransition = - KeyguardTransitionAnimationFlow( - transitionDuration = TRANSITION_DURATION_MS, - transitionFlow = transitionInteractor.anyStateToAlternateBouncerTransition, + animationFlow + .setup( + duration = TRANSITION_DURATION_MS, + stepFlow = transitionInteractor.anyStateToAlternateBouncerTransition, ) - .createFlow( + .sharedFlow( duration = TRANSITION_DURATION_MS, onStep = { it }, onFinish = { 1f }, @@ -55,11 +57,12 @@ constructor( interpolator = Interpolators.FAST_OUT_SLOW_IN, ) private val fromAlternateBouncerTransition = - KeyguardTransitionAnimationFlow( - transitionDuration = TRANSITION_DURATION_MS, - transitionFlow = transitionInteractor.transitionStepsFromState(ALTERNATE_BOUNCER), + animationFlow + .setup( + TRANSITION_DURATION_MS, + transitionInteractor.transitionStepsFromState(ALTERNATE_BOUNCER), ) - .createFlow( + .sharedFlow( duration = TRANSITION_DURATION_MS, onStep = { 1f - it }, // Reset on cancel diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt index 4d2af0c7bd4d..2b145216cb80 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt @@ -32,12 +32,13 @@ class AodToGoneTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromAodTransitionInteractor.TO_GONE_DURATION, - transitionFlow = interactor.transition(KeyguardState.AOD, KeyguardState.GONE), + animationFlow.setup( + duration = FromAodTransitionInteractor.TO_GONE_DURATION, + stepFlow = interactor.transition(KeyguardState.AOD, KeyguardState.GONE), ) override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt index 1864437a7d11..5e552e1fe00f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt @@ -39,24 +39,25 @@ class AodToLockscreenTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_LOCKSCREEN_DURATION, - transitionFlow = interactor.aodToLockscreenTransition, + animationFlow.setup( + duration = TO_LOCKSCREEN_DURATION, + stepFlow = interactor.aodToLockscreenTransition, ) /** Ensure alpha is set to be visible */ val lockscreenAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 500.milliseconds, onStart = { 1f }, onStep = { 1f }, ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 167.milliseconds, startTime = 67.milliseconds, onStep = { it }, @@ -67,7 +68,7 @@ constructor( deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { isUdfps -> if (isUdfps) { // fade in - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { it }, onFinish = { 1f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt index 06661d0a466b..d283af359b06 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt @@ -30,11 +30,12 @@ class AodToOccludedTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromAodTransitionInteractor.TO_OCCLUDED_DURATION, - transitionFlow = interactor.transition(KeyguardState.AOD, KeyguardState.OCCLUDED), + animationFlow.setup( + duration = FromAodTransitionInteractor.TO_OCCLUDED_DURATION, + stepFlow = interactor.transition(KeyguardState.AOD, KeyguardState.OCCLUDED), ) override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt index da74f2fa061e..41dc15778b0c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt @@ -47,6 +47,7 @@ constructor( private val keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>, private val featureFlags: FeatureFlagsClassic, private val shadeInteractor: ShadeInteractor, + private val animationFlow: KeyguardTransitionAnimationFlow, ) { /** Common fade for scrim alpha values during *BOUNCER->GONE */ fun scrimAlpha(duration: Duration, fromState: KeyguardState): Flow<ScrimAlpha> { @@ -73,14 +74,14 @@ constructor( var leaveShadeOpen: Boolean = false var willRunDismissFromKeyguard: Boolean = false val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = duration, - transitionFlow = interactor.transition(fromState, GONE) + animationFlow.setup( + duration = duration, + stepFlow = interactor.transition(fromState, GONE) ) return shadeInteractor.shadeExpansion.flatMapLatest { shadeExpansion -> transitionAnimation - .createFlow( + .sharedFlow( duration = duration, interpolator = EMPHASIZED_ACCELERATE, onStart = { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt index 5b5a10380a5b..bd6aae8f2dcb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt @@ -57,7 +57,6 @@ constructor( private val sceneContainerFlags: SceneContainerFlags, private val keyguardViewController: Lazy<KeyguardViewController>, private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor, - udfpsInteractor: DeviceEntryUdfpsInteractor, private val deviceEntryInteractor: DeviceEntryInteractor, ) { private val intEvaluator = IntEvaluator() @@ -149,7 +148,7 @@ constructor( } val iconType: Flow<DeviceEntryIconView.IconType> = combine( - udfpsInteractor.isListeningForUdfps, + deviceEntryUdfpsInteractor.isListeningForUdfps, deviceEntryInteractor.isUnlocked, ) { isListeningForUdfps, isUnlocked -> if (isUnlocked) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt index a728a2810916..0b34326bc83d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt @@ -35,15 +35,16 @@ class DozingToLockscreenTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { - private val transitionAnimation: KeyguardTransitionAnimationFlow = - KeyguardTransitionAnimationFlow( - transitionDuration = FromDozingTransitionInteractor.TO_LOCKSCREEN_DURATION, - transitionFlow = interactor.dozingToLockscreenTransition, + private val transitionAnimation = + animationFlow.setup( + duration = FromDozingTransitionInteractor.TO_LOCKSCREEN_DURATION, + stepFlow = interactor.dozingToLockscreenTransition, ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 150.milliseconds, onStep = { it }, onCancel = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt index 58235ae02abe..8bcf3f8a76d9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt @@ -29,16 +29,17 @@ class DreamingHostedToLockscreenTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_LOCKSCREEN_DURATION, - transitionFlow = interactor.dreamingLockscreenHostedToLockscreenTransition + animationFlow.setup( + duration = TO_LOCKSCREEN_DURATION, + stepFlow = interactor.dreamingLockscreenHostedToLockscreenTransition, ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { it }, onCancel = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt index f943bdfa7550..5f620afe2dea 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt @@ -45,13 +45,14 @@ constructor( keyguardTransitionInteractor: KeyguardTransitionInteractor, private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor, private val deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition() private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_LOCKSCREEN_DURATION, - transitionFlow = keyguardTransitionInteractor.dreamingToLockscreenTransition, + animationFlow.setup( + duration = TO_LOCKSCREEN_DURATION, + stepFlow = keyguardTransitionInteractor.dreamingToLockscreenTransition, ) val transitionEnded = @@ -62,7 +63,7 @@ constructor( /** Dream overlay y-translation on exit */ fun dreamOverlayTranslationY(translatePx: Int): Flow<Float> { - return transitionAnimation.createFlow( + return transitionAnimation.sharedFlow( duration = TO_LOCKSCREEN_DURATION, onStep = { it * translatePx }, interpolator = EMPHASIZED, @@ -71,14 +72,14 @@ constructor( /** Dream overlay views alpha - fade out */ val dreamOverlayAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1f - it }, ) /** Lockscreen views y-translation */ fun lockscreenTranslationY(translatePx: Int): Flow<Float> { - return transitionAnimation.createFlow( + return transitionAnimation.sharedFlow( duration = TO_LOCKSCREEN_DURATION, onStep = { value -> -translatePx + value * translatePx }, // Reset on cancel or finish @@ -90,14 +91,14 @@ constructor( /** Lockscreen views alpha */ val lockscreenAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( startTime = 233.milliseconds, duration = 250.milliseconds, onStep = { it }, ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( startTime = 233.milliseconds, duration = 250.milliseconds, onStep = { it }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt index 62b2281ae473..3f27eb0c73e3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt @@ -38,17 +38,18 @@ class GoneToAodTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_AOD_DURATION, - transitionFlow = interactor.goneToAodTransition, + animationFlow.setup( + duration = TO_AOD_DURATION, + stepFlow = interactor.goneToAodTransition, ) /** y-translation from the top of the screen for AOD */ fun enterFromTopTranslationY(translatePx: Int): Flow<Float> { - return transitionAnimation.createFlow( + return transitionAnimation.sharedFlow( startTime = 600.milliseconds, duration = 500.milliseconds, onStart = { translatePx }, @@ -61,7 +62,7 @@ constructor( /** alpha animation upon entering AOD */ val enterFromTopAnimationAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( startTime = 600.milliseconds, duration = 500.milliseconds, onStart = { 0f }, @@ -74,7 +75,7 @@ constructor( if (udfpsEnrolled) { // fade in at the end of the transition to give time for FP to start running // and avoid a flicker of the unlocked icon - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( startTime = 1100.milliseconds, duration = 200.milliseconds, onStep = { it }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt index 113f01c0b122..bba790abe807 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt @@ -33,17 +33,18 @@ class GoneToDreamingLockscreenHostedTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_DREAMING_DURATION, - transitionFlow = interactor.goneToDreamingLockscreenHostedTransition, + animationFlow.setup( + duration = TO_DREAMING_DURATION, + stepFlow = interactor.goneToDreamingLockscreenHostedTransition, ) /** Lockscreen views alpha - hide immediately */ val lockscreenAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 1.milliseconds, onStep = { 0f }, ) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt index c1357863f3a5..6762ba6298a5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt @@ -31,17 +31,18 @@ class GoneToDreamingTransitionViewModel @Inject constructor( private val interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_DREAMING_DURATION, - transitionFlow = interactor.goneToDreamingTransition, + animationFlow.setup( + duration = TO_DREAMING_DURATION, + stepFlow = interactor.goneToDreamingTransition, ) /** Lockscreen views y-translation */ fun lockscreenTranslationY(translatePx: Int): Flow<Float> { - return transitionAnimation.createFlow( + return transitionAnimation.sharedFlow( duration = 500.milliseconds, onStep = { it * translatePx }, // Reset on cancel or finish @@ -53,7 +54,7 @@ constructor( /** Lockscreen views alpha */ val lockscreenAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1f - it }, ) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt index 5804a205445c..adae8abfb9c3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt @@ -29,16 +29,17 @@ class GoneToLockscreenTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_LOCKSCREEN_DURATION, - transitionFlow = interactor.goneToLockscreenTransition + animationFlow.setup( + duration = TO_LOCKSCREEN_DURATION, + stepFlow = interactor.goneToLockscreenTransition ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { it }, onCancel = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt index c54f47b48745..3aeff61c15e7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import androidx.constraintlayout.helper.widget.Layer import com.android.keyguard.KeyguardClockSwitch.LARGE import com.android.keyguard.KeyguardClockSwitch.SMALL import com.android.systemui.dagger.SysUISingleton @@ -23,13 +24,12 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.shared.model.SettingsClockSize -import com.android.systemui.plugins.ClockController +import com.android.systemui.plugins.clocks.ClockController import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.stateIn @SysUISingleton @@ -40,19 +40,14 @@ constructor( val keyguardClockInteractor: KeyguardClockInteractor, @Application private val applicationScope: CoroutineScope, ) { + var burnInLayer: Layer? = null val useLargeClock: Boolean get() = clockSize.value == LARGE - var clock: ClockController? - set(value) { - keyguardClockInteractor.clock = value - } - get() { - return keyguardClockInteractor.clock - } + var clock: ClockController? by keyguardClockInteractor::clock val clockSize = - combine(keyguardClockInteractor.selectedClockSize, keyguardInteractor.clockSize) { + combine(keyguardClockInteractor.selectedClockSize, keyguardClockInteractor.clockSize) { selectedSize, clockSize -> if (selectedSize == SettingsClockSize.SMALL) { @@ -61,7 +56,6 @@ constructor( clockSize } } - .distinctUntilChanged() .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), @@ -72,16 +66,23 @@ constructor( val hasCustomWeatherDataDisplay = combine(clockSize, currentClock) { size, clock -> - (if (size == LARGE) clock.largeClock.config.hasCustomWeatherDataDisplay - else clock.smallClock.config.hasCustomWeatherDataDisplay) + clock?.let { + (if (size == LARGE) clock.largeClock.config.hasCustomWeatherDataDisplay + else clock.smallClock.config.hasCustomWeatherDataDisplay) + } + ?: false } - .distinctUntilChanged() .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = false + initialValue = currentClock.value?.largeClock?.config?.hasCustomWeatherDataDisplay + ?: false ) val clockShouldBeCentered: Flow<Boolean> = - keyguardInteractor.clockShouldBeCentered.distinctUntilChanged() + keyguardInteractor.clockShouldBeCentered.stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = true + ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt index 2327c028970b..6458edaecd9e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.Flags.keyguardBottomAreaRefactor +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.doze.util.BurnInHelperWrapper import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -35,10 +36,11 @@ constructor( keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel, private val burnInHelperWrapper: BurnInHelperWrapper, private val shortcutsCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel, + configurationInteractor: ConfigurationInteractor, ) { /** Notifies when a new configuration is set */ - val configurationChange: Flow<Unit> = keyguardInteractor.configurationChange + val configurationChange: Flow<Unit> = configurationInteractor.onAnyConfigurationChange /** An observable for the alpha level for the entire bottom area. */ val alpha: Flow<Float> = keyguardBottomAreaViewModel.alpha @@ -47,17 +49,18 @@ constructor( val isIndicationAreaPadded: Flow<Boolean> = if (keyguardBottomAreaRefactor()) { combine(shortcutsCombinedViewModel.startButton, shortcutsCombinedViewModel.endButton) { - startButtonModel, - endButtonModel -> - startButtonModel.isVisible || endButtonModel.isVisible - } + startButtonModel, + endButtonModel -> + startButtonModel.isVisible || endButtonModel.isVisible + } .distinctUntilChanged() } else { - combine(keyguardBottomAreaViewModel.startButton, keyguardBottomAreaViewModel.endButton) { - startButtonModel, - endButtonModel -> - startButtonModel.isVisible || endButtonModel.isVisible - } + combine( + keyguardBottomAreaViewModel.startButton, + keyguardBottomAreaViewModel.endButton + ) { startButtonModel, endButtonModel -> + startButtonModel.isVisible || endButtonModel.isVisible + } .distinctUntilChanged() } /** An observable for the x-offset by which the indication area should be translated. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index f63afebb60ab..d250c1ba1865 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -17,22 +17,26 @@ package com.android.systemui.keyguard.ui.viewmodel -import android.content.Context import android.util.MathUtils import android.view.View.VISIBLE import com.android.app.animation.Interpolators +import com.android.keyguard.KeyguardClockSwitch.LARGE import com.android.systemui.Flags.newAodTransition import com.android.systemui.common.shared.model.NotificationContainerBounds +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.BurnInModel import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.AOD +import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN -import com.android.systemui.plugins.ClockController +import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.res.R import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor import com.android.systemui.statusbar.phone.DozeParameters @@ -61,18 +65,29 @@ import kotlinx.coroutines.flow.onStart class KeyguardRootViewModel @Inject constructor( - private val context: Context, + configurationInteractor: ConfigurationInteractor, private val deviceEntryInteractor: DeviceEntryInteractor, private val dozeParameters: DozeParameters, private val keyguardInteractor: KeyguardInteractor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, private val burnInInteractor: BurnInInteractor, + private val keyguardClockViewModel: KeyguardClockViewModel, private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel, private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, + private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, screenOffAnimationController: ScreenOffAnimationController, + // TODO(b/310989341): remove after changing migrate_clocks_to_blueprint to aconfig + private val featureFlags: FeatureFlagsClassic, ) { var clockControllerProvider: Provider<ClockController>? = null + get() { + if (featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { + return Provider { keyguardClockViewModel.clock } + } else { + return field + } + } /** System insets that keyguard needs to stay out of */ var topInset: Int = 0 @@ -84,14 +99,18 @@ constructor( .filter { it == AOD || it == LOCKSCREEN } .map { VISIBLE } - val goneToAodTransition = keyguardTransitionInteractor.goneToAodTransition + val goneToAodTransition = keyguardTransitionInteractor.transition(from = GONE, to = AOD) /** the shared notification container bounds *on the lockscreen* */ val notificationBounds: StateFlow<NotificationContainerBounds> = keyguardInteractor.notificationContainerBounds /** An observable for the alpha level for the entire keyguard root view. */ - val alpha: Flow<Float> = keyguardInteractor.keyguardAlpha.distinctUntilChanged() + val alpha: Flow<Float> = + merge( + keyguardInteractor.keyguardAlpha.distinctUntilChanged(), + occludedToLockscreenTransitionViewModel.lockscreenAlpha, + ) private fun burnIn(): Flow<BurnInModel> { val dozingAmount: Flow<Float> = @@ -103,7 +122,8 @@ constructor( return combine(dozingAmount, burnInInteractor.keyguardBurnIn) { dozeAmount, burnIn -> val interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(dozeAmount) val useScaleOnly = - clockControllerProvider?.get()?.config?.useAlternateSmartspaceAODTransition ?: false + (clockControllerProvider?.get()?.config?.useAlternateSmartspaceAODTransition + ?: false) && keyguardClockViewModel.clockSize.value == LARGE if (useScaleOnly) { BurnInModel( translationX = 0, @@ -113,7 +133,12 @@ constructor( } else { // Ensure the desired translation doesn't encroach on the top inset val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolation).toInt() - val translationY = -(statusViewTop - Math.max(topInset, statusViewTop + burnInY)) + val translationY = + if (featureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { + burnInY + } else { + -(statusViewTop - Math.max(topInset, statusViewTop + burnInY)) + } BurnInModel( translationX = MathUtils.lerp(0, burnIn.translationX, interpolation).toInt(), translationY = translationY, @@ -131,22 +156,28 @@ constructor( val burnInLayerAlpha: Flow<Float> = goneToAodTransitionViewModel.enterFromTopAnimationAlpha val translationY: Flow<Float> = - keyguardInteractor.configurationChange.flatMapLatest { _ -> - val enterFromTopAmount = - context.resources.getDimensionPixelSize( - R.dimen.keyguard_enter_from_top_translation_y - ) - combine( - keyguardInteractor.keyguardTranslationY.onStart { emit(0f) }, - burnIn().map { it.translationY.toFloat() }.onStart { emit(0f) }, - goneToAodTransitionViewModel.enterFromTopTranslationY(enterFromTopAmount).onStart { - emit(0f) - }, - ) { keyguardTransitionY, burnInTranslationY, goneToAodTransitionTranslationY -> - // All 3 values need to be combined for a smooth translation - keyguardTransitionY + burnInTranslationY + goneToAodTransitionTranslationY + configurationInteractor + .dimensionPixelSize(R.dimen.keyguard_enter_from_top_translation_y) + .flatMapLatest { enterFromTopAmount -> + combine( + keyguardInteractor.keyguardTranslationY.onStart { emit(0f) }, + burnIn().map { it.translationY.toFloat() }.onStart { emit(0f) }, + goneToAodTransitionViewModel + .enterFromTopTranslationY(enterFromTopAmount) + .onStart { emit(0f) }, + occludedToLockscreenTransitionViewModel.lockscreenTranslationY, + ) { + keyguardTransitionY, + burnInTranslationY, + goneToAodTransitionTranslationY, + occludedToLockscreenTransitionTranslationY -> + // All values need to be combined for a smooth translation + keyguardTransitionY + + burnInTranslationY + + goneToAodTransitionTranslationY + + occludedToLockscreenTransitionTranslationY + } } - } val translationX: Flow<Float> = burnIn().map { it.translationX.toFloat() } @@ -194,7 +225,6 @@ constructor( .distinctUntilChanged() fun onNotificationContainerBoundsChanged(top: Float, bottom: Float) { - keyguardInteractor.setNotificationContainerBounds(NotificationContainerBounds(top, bottom)) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt index 8e33651ced6a..4541458892bb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt @@ -30,16 +30,21 @@ constructor(val context: Context, smartspaceController: LockscreenSmartspaceCont val isWeatherEnabled: Boolean = smartspaceController.isWeatherEnabled() val isDateWeatherDecoupled: Boolean = smartspaceController.isDateWeatherDecoupled() val smartspaceViewId: Int - get() { - return context.resources - .getIdentifier("bc_smartspace_view", "id", context.packageName) - .also { - if (it == 0) { - Log.d(TAG, "Cannot resolve id bc_smartspace_view") - } - } - } + get() = getId("bc_smartspace_view") + + val dateId: Int + get() = getId("date_smartspace_view") + + val weatherId: Int + get() = getId("weather_smartspace_view") + private fun getId(name: String): Int { + return context.resources.getIdentifier(name, "id", context.packageName).also { + if (it == 0) { + Log.d(TAG, "Cannot resolve id $name") + } + } + } fun getDimen(name: String): Int { val res = context.packageManager.getResourcesForApplication(context.packageName) val id = res.getIdentifier(name, "dimen", context.packageName) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt index 8e8fd75cc1c0..65614f47b120 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt @@ -39,19 +39,20 @@ constructor( interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, shadeDependentFlows: ShadeDependentFlows, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromLockscreenTransitionInteractor.TO_AOD_DURATION, - transitionFlow = interactor.lockscreenToAodTransition, + animationFlow.setup( + duration = FromLockscreenTransitionInteractor.TO_AOD_DURATION, + stepFlow = interactor.lockscreenToAodTransition, ) val deviceEntryBackgroundViewAlpha: Flow<Float> = shadeDependentFlows.transitionFlow( flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f), flowWhenShadeIsNotExpanded = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 300.milliseconds, onStep = { 1 - it }, onFinish = { 0f }, @@ -59,7 +60,7 @@ constructor( ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1 - it }, onFinish = { 0f }, @@ -72,7 +73,7 @@ constructor( if (isUdfpsEnrolledAndEnabled) { shadeDependentFlows.transitionFlow( flowWhenShadeIsExpanded = // fade in - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 300.milliseconds, onStep = { it }, onFinish = { 1f }, @@ -83,7 +84,7 @@ constructor( shadeDependentFlows.transitionFlow( flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f), flowWhenShadeIsNotExpanded = // fade out - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 200.milliseconds, onStep = { 1f - it }, onFinish = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt index 263ed11503ba..accb20c91f98 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt @@ -29,16 +29,17 @@ class LockscreenToDozingTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_DOZING_DURATION, - transitionFlow = interactor.lockscreenToDozingTransition + animationFlow.setup( + duration = TO_DOZING_DURATION, + stepFlow = interactor.lockscreenToDozingTransition ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1 - it }, onFinish = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt index 17015056bda0..c649b12b71e4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt @@ -29,16 +29,17 @@ class LockscreenToDreamingHostedTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_DREAMING_HOSTED_DURATION, - transitionFlow = interactor.lockscreenToDreamingLockscreenHostedTransition + animationFlow.setup( + duration = TO_DREAMING_HOSTED_DURATION, + stepFlow = interactor.lockscreenToDreamingLockscreenHostedTransition ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1 - it }, onFinish = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt index 401c0ff76c29..7f75b547d717 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt @@ -36,16 +36,17 @@ class LockscreenToDreamingTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, shadeDependentFlows: ShadeDependentFlows, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_DREAMING_DURATION, - transitionFlow = interactor.lockscreenToDreamingTransition, + animationFlow.setup( + duration = TO_DREAMING_DURATION, + stepFlow = interactor.lockscreenToDreamingTransition, ) /** Lockscreen views y-translation */ fun lockscreenTranslationY(translatePx: Int): Flow<Float> { - return transitionAnimation.createFlow( + return transitionAnimation.sharedFlow( duration = 500.milliseconds, onStep = { it * translatePx }, // Reset on cancel or finish @@ -57,13 +58,13 @@ constructor( /** Lockscreen views alpha */ val lockscreenAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1f - it }, ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1 - it }, onFinish = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt index cfb4bf59c8a8..9e197138d0b2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt @@ -36,16 +36,17 @@ class LockscreenToGoneTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromLockscreenTransitionInteractor.TO_GONE_DURATION, - transitionFlow = interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.GONE), + animationFlow.setup( + duration = FromLockscreenTransitionInteractor.TO_GONE_DURATION, + stepFlow = interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.GONE), ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1 - it }, onFinish = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt index a6136f95d0f6..9db0b775cd40 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt @@ -17,14 +17,17 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.res.R import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest /** * Breaks down LOCKSCREEN->OCCLUDED transition into discrete steps for corresponding views to @@ -36,22 +39,26 @@ class LockscreenToOccludedTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, shadeDependentFlows: ShadeDependentFlows, + configurationInteractor: ConfigurationInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { + private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_OCCLUDED_DURATION, - transitionFlow = interactor.lockscreenToOccludedTransition, + animationFlow.setup( + duration = TO_OCCLUDED_DURATION, + stepFlow = interactor.lockscreenToOccludedTransition, ) /** Lockscreen views alpha */ val lockscreenAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1f - it }, + name = "LOCKSCREEN->OCCLUDED: lockscreenAlpha", ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1 - it }, onFinish = { 0f }, @@ -59,16 +66,19 @@ constructor( ) /** Lockscreen views y-translation */ - fun lockscreenTranslationY(translatePx: Int): Flow<Float> { - return transitionAnimation.createFlow( - duration = TO_OCCLUDED_DURATION, - onStep = { value -> value * translatePx }, - // Reset on cancel or finish - onFinish = { 0f }, - onCancel = { 0f }, - interpolator = EMPHASIZED_ACCELERATE, - ) - } + val lockscreenTranslationY: Flow<Float> = + configurationInteractor + .dimensionPixelSize(R.dimen.lockscreen_to_occluded_transition_lockscreen_translation_y) + .flatMapLatest { translatePx -> + transitionAnimation.sharedFlow( + duration = TO_OCCLUDED_DURATION, + onStep = { value -> value * translatePx }, + // Reset on cancel or finish + onFinish = { 0f }, + onCancel = { 0f }, + interpolator = EMPHASIZED_ACCELERATE, + ) + } override val deviceEntryParentViewAlpha: Flow<Float> = shadeDependentFlows.transitionFlow( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt index 07dd4ef49c5d..52e3257f8e18 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt @@ -39,11 +39,12 @@ class LockscreenToPrimaryBouncerTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, shadeDependentFlows: ShadeDependentFlows, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromLockscreenTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION, - transitionFlow = + animationFlow.setup( + duration = FromLockscreenTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION, + stepFlow = interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER), ) @@ -55,7 +56,7 @@ constructor( override val deviceEntryParentViewAlpha: Flow<Float> = shadeDependentFlows.transitionFlow( flowWhenShadeIsNotExpanded = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { 1f - it }, onFinish = { 0f } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt index f7cff9b28542..ed5e83c44640 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt @@ -37,11 +37,12 @@ class OccludedToAodTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromOccludedTransitionInteractor.TO_AOD_DURATION, - transitionFlow = interactor.transition(KeyguardState.OCCLUDED, KeyguardState.AOD), + animationFlow.setup( + duration = FromOccludedTransitionInteractor.TO_AOD_DURATION, + stepFlow = interactor.transition(KeyguardState.OCCLUDED, KeyguardState.AOD), ) val deviceEntryBackgroundViewAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt index 58be0934beca..4c24f83200b2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt @@ -17,12 +17,14 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.res.R import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -40,26 +42,32 @@ class OccludedToLockscreenTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, - deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor + deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + configurationInteractor: ConfigurationInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { + private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_LOCKSCREEN_DURATION, - transitionFlow = interactor.occludedToLockscreenTransition, + animationFlow.setup( + duration = TO_LOCKSCREEN_DURATION, + stepFlow = interactor.occludedToLockscreenTransition, ) /** Lockscreen views y-translation */ - fun lockscreenTranslationY(translatePx: Int): Flow<Float> { - return transitionAnimation.createFlow( - duration = TO_LOCKSCREEN_DURATION, - onStep = { value -> -translatePx + value * translatePx }, - interpolator = EMPHASIZED_DECELERATE, - onCancel = { 0f }, - ) - } + val lockscreenTranslationY: Flow<Float> = + configurationInteractor + .dimensionPixelSize(R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y) + .flatMapLatest { translatePx -> + transitionAnimation.sharedFlow( + duration = TO_LOCKSCREEN_DURATION, + onStep = { value -> -translatePx + value * translatePx }, + interpolator = EMPHASIZED_DECELERATE, + onCancel = { 0f }, + ) + } val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { it }, onCancel = { 0f }, @@ -67,10 +75,12 @@ constructor( /** Lockscreen views alpha */ val lockscreenAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( startTime = 233.milliseconds, duration = 250.milliseconds, onStep = { it }, + onStart = { 0f }, + name = "OCCLUDED->LOCKSCREEN: lockscreenAlpha", ) val deviceEntryBackgroundViewAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt index c3bc799435a8..93482ea162bb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt @@ -28,16 +28,17 @@ class OffToLockscreenTransitionViewModel @Inject constructor( interactor: KeyguardTransitionInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = 250.milliseconds, - transitionFlow = interactor.offToLockscreenTransition + animationFlow.setup( + duration = 250.milliseconds, + stepFlow = interactor.offToLockscreenTransition ) val shortcutsAlpha: Flow<Float> = - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 250.milliseconds, onStep = { it }, onCancel = { 0f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt index 05a6d5810be3..b0e2aa2d4765 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt @@ -41,12 +41,12 @@ class PrimaryBouncerToAodTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromPrimaryBouncerTransitionInteractor.TO_AOD_DURATION, - transitionFlow = - interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.AOD), + animationFlow.setup( + duration = FromPrimaryBouncerTransitionInteractor.TO_AOD_DURATION, + stepFlow = interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.AOD), ) val deviceEntryBackgroundViewAlpha: Flow<Float> = @@ -62,7 +62,7 @@ constructor( deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { isUdfpsEnrolledAndEnabled -> if (isUdfpsEnrolledAndEnabled) { - transitionAnimation.createFlow( + transitionAnimation.sharedFlow( duration = 300.milliseconds, onStep = { it }, onFinish = { 1f }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt index 0e95be20d059..9dbe97fd1c20 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt @@ -50,11 +50,12 @@ constructor( keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>, featureFlags: FeatureFlagsClassic, bouncerToGoneFlows: BouncerToGoneFlows, + animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = TO_GONE_DURATION, - transitionFlow = interactor.transition(PRIMARY_BOUNCER, GONE) + animationFlow.setup( + duration = TO_GONE_DURATION, + stepFlow = interactor.transition(PRIMARY_BOUNCER, GONE) ) private var leaveShadeOpen: Boolean = false @@ -71,7 +72,7 @@ constructor( createBouncerAlphaFlow(primaryBouncerInteractor::willRunDismissFromKeyguard) } private fun createBouncerAlphaFlow(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> { - return transitionAnimation.createFlow( + return transitionAnimation.sharedFlow( duration = 200.milliseconds, onStart = { willRunDismissFromKeyguard = willRunAnimationOnKeyguard() }, onStep = { @@ -95,7 +96,7 @@ constructor( createLockscreenAlpha(primaryBouncerInteractor::willRunDismissFromKeyguard) } private fun createLockscreenAlpha(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> { - return transitionAnimation.createFlow( + return transitionAnimation.sharedFlow( duration = 50.milliseconds, onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt index 7ef8374023fb..b2eed60e0a9e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt @@ -41,11 +41,12 @@ class PrimaryBouncerToLockscreenTransitionViewModel constructor( interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = - KeyguardTransitionAnimationFlow( - transitionDuration = FromPrimaryBouncerTransitionInteractor.TO_LOCKSCREEN_DURATION, - transitionFlow = + animationFlow.setup( + duration = FromPrimaryBouncerTransitionInteractor.TO_LOCKSCREEN_DURATION, + stepFlow = interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.LOCKSCREEN), ) diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt index 702a23ea5ebc..e1c6f41033cc 100644 --- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt @@ -35,7 +35,7 @@ private const val TAG = "ScreenDecorationsLog" * * To enable logcat echoing for an entire buffer: * ``` - * adb shell settings put global systemui/buffer/ScreenDecorationsLog <logLevel> + * adb shell cmd statusbar echo -b ScreenDecorationsLog:<logLevel> * * ``` */ @@ -134,33 +134,35 @@ constructor( } fun cameraProtectionShownOrHidden( + showAnimationNow: Boolean, faceDetectionRunning: Boolean, biometricPromptShown: Boolean, - requestedState: Boolean, + faceAuthenticated: Boolean, + isCameraActive: Boolean, currentlyShowing: Boolean ) { logBuffer.log( TAG, DEBUG, { + str1 = "$showAnimationNow" bool1 = faceDetectionRunning bool2 = biometricPromptShown - bool3 = requestedState + str2 = "$faceAuthenticated" + bool3 = isCameraActive bool4 = currentlyShowing }, { - "isFaceDetectionRunning: $bool1, " + + "cameraProtectionShownOrHidden showAnimationNow: $str1, " + + "isFaceDetectionRunning: $bool1, " + "isBiometricPromptShowing: $bool2, " + - "requestedState: $bool3, " + + "faceAuthenticated: $str2, " + + "isCameraActive: $bool3, " + "currentState: $bool4" } ) } - fun biometricEvent(@CompileTimeConstant info: String) { - logBuffer.log(TAG, DEBUG, info) - } - fun cameraProtectionEvent(@CompileTimeConstant cameraProtectionEvent: String) { logBuffer.log(TAG, DEBUG, cameraProtectionEvent) } diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardTransitionAnimationLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardTransitionAnimationLog.kt new file mode 100644 index 000000000000..ef0658867801 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardTransitionAnimationLog.kt @@ -0,0 +1,28 @@ +/* + * 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.log.dagger + +import javax.inject.Qualifier + +/** + * A [com.android.systemui.log.LogBuffer] for keyguard transition animations. Should be used mostly + * for adding temporary logs or logging from smaller classes when creating new separate log class + * might be an overkill. + */ +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class KeyguardTransitionAnimationLog diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 0b3bbb5c3d08..dc55179f53f8 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -525,6 +525,16 @@ public class LogModule { } /** + * Provides a {@link LogBuffer} for keyguard transition animation logs. + */ + @Provides + @SysUISingleton + @KeyguardTransitionAnimationLog + public static LogBuffer provideKeyguardTransitionAnimationLogBuffer(LogBufferFactory factory) { + return factory.create("KeyguardTransitionAnimationLog", 250); + } + + /** * Provides a {@link LogBuffer} for Scrims like LightRevealScrim. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index 04883c368b78..2551da8e7795 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -676,7 +676,7 @@ public class MediaControlPanel { mLogger.logOpenBroadcastDialog(mUid, mPackageName, mInstanceId); mCurrentBroadcastApp = device.getName().toString(); mBroadcastDialogController.createBroadcastDialog(mCurrentBroadcastApp, - mPackageName, true, mMediaViewHolder.getSeamlessButton()); + mPackageName, mMediaViewHolder.getSeamlessButton()); } else { mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId); mMediaOutputDialogFactory.create(mPackageName, true, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt index 35456d5ee472..0385aeba32b7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt @@ -461,6 +461,15 @@ constructor( // the // location of the previous state to still be up to date when the animation // starts + if ( + newState == StatusBarState.SHADE_LOCKED && + oldState == StatusBarState.KEYGUARD && + fullShadeTransitionProgress < 1.0f + ) { + // Since the new state is SHADE_LOCKED, we need to set the transition amount + // to maximum if the progress is not 1f. + setTransitionToFullShadeAmount(distanceForFullShadeTransition.toFloat()) + } statusbarState = newState updateDesiredLocation() } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index e2e94dae900a..0a72a2f15e95 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -400,8 +400,8 @@ public class NavigationBar extends ViewController<NavigationBarView> implements } @Override - public void animateNavBarLongPress(boolean isTouchDown, long durationMs) { - mView.getHomeHandle().animateLongPress(isTouchDown, durationMs); + public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) { + mView.getHomeHandle().animateLongPress(isTouchDown, shrink, durationMs); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java index 5fe830e6e442..5739abcae7eb 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java @@ -247,10 +247,10 @@ public class ButtonDispatcher { } } - public void animateLongPress(boolean isTouchDown, long durationMs) { + public void animateLongPress(boolean isTouchDown, boolean shrink, long durationMs) { for (int i = 0; i < mViews.size(); i++) { if (mViews.get(i) instanceof ButtonInterface) { - ((ButtonInterface) mViews.get(i)).animateLongPress(isTouchDown, durationMs); + ((ButtonInterface) mViews.get(i)).animateLongPress(isTouchDown, shrink, durationMs); } } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonInterface.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonInterface.java index 356b2f7c7cb8..5f8fafd4ae4c 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonInterface.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonInterface.java @@ -35,9 +35,10 @@ public interface ButtonInterface { * Animate the button being long-pressed. * * @param isTouchDown {@code true} if the button is starting to be pressed ({@code false} if - * released or canceled) - * @param durationMs how long the animation should take (for the {@code isTouchDown} case, this - * should be the same as the amount of time to trigger a long-press) + * released or canceled) + * @param shrink {@code true} if the handle should shrink, {@code false} if it should grow + * @param durationMs how long the animation should take (for the {@code isTouchDown} case, this + * should be the same as the amount of time to trigger a long-press) */ - default void animateLongPress(boolean isTouchDown, long durationMs) {} + default void animateLongPress(boolean isTouchDown, boolean shrink, long durationMs) {} } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java index 039d0e00070e..d1ce1f613044 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java @@ -44,7 +44,9 @@ public class NavigationHandle extends View implements ButtonInterface { protected final float mBottom; private final float mAdditionalWidthForAnimation; private final float mAdditionalHeightForAnimation; + private final float mShrinkWidthForAnimation; private boolean mRequiresInvalidate; + private boolean mShrink; private ObjectAnimator mPulseAnimator = null; private float mPulseAnimationProgress; @@ -75,6 +77,8 @@ public class NavigationHandle extends View implements ButtonInterface { res.getDimension(R.dimen.navigation_home_handle_additional_width_for_animation); mAdditionalHeightForAnimation = res.getDimension(R.dimen.navigation_home_handle_additional_height_for_animation); + mShrinkWidthForAnimation = + res.getDimension(R.dimen.navigation_home_handle_shrink_width_for_animation); final int dualToneDarkTheme = Utils.getThemeAttr(context, R.attr.darkIconTheme); final int dualToneLightTheme = Utils.getThemeAttr(context, R.attr.lightIconTheme); @@ -101,9 +105,17 @@ public class NavigationHandle extends View implements ButtonInterface { // Draw that bar int navHeight = getHeight(); - float additionalHeight = mAdditionalHeightForAnimation * mPulseAnimationProgress; + float additionalHeight; + float additionalWidth; + if (mShrink) { + additionalHeight = 0; + additionalWidth = -mShrinkWidthForAnimation * mPulseAnimationProgress; + } else { + additionalHeight = mAdditionalHeightForAnimation * mPulseAnimationProgress; + additionalWidth = mAdditionalWidthForAnimation * mPulseAnimationProgress; + } + float height = mRadius * 2 + additionalHeight; - float additionalWidth = mAdditionalWidthForAnimation * mPulseAnimationProgress; float width = getWidth() + additionalWidth; float x = -additionalWidth; float y = navHeight - mBottom - height + (additionalHeight / 2); @@ -138,26 +150,32 @@ public class NavigationHandle extends View implements ButtonInterface { public void setDelayTouchFeedback(boolean shouldDelay) {} @Override - public void animateLongPress(boolean isTouchDown, long durationMs) { + public void animateLongPress(boolean isTouchDown, boolean shrink, long durationMs) { if (mPulseAnimator != null) { mPulseAnimator.cancel(); } + mShrink = shrink; Interpolator interpolator; - if (isTouchDown) { - // For now we animate the navbar expanding and contracting so that the navbar is the - // original size by the end of {@code duration}. This is because a screenshot is taken - // at that point and we don't want to capture the larger navbar. - // TODO(b/306400785): Determine a way to exclude navbar from the screenshot. - - // Fraction of the touch down animation to expand; remaining is used to contract again. - float expandFraction = 0.9f; - interpolator = t -> t <= expandFraction + if (shrink) { + interpolator = Interpolators.LEGACY_DECELERATE; + } else { + if (isTouchDown) { + // For now we animate the navbar expanding and contracting so that the navbar is + // the original size by the end of {@code duration}. This is because a screenshot + // is taken at that point and we don't want to capture the larger navbar. + // TODO(b/306400785): Determine a way to exclude navbar from the screenshot. + + // Fraction of the touch down animation to expand; remaining is used to contract + // again. + float expandFraction = 0.9f; + interpolator = t -> t <= expandFraction ? Interpolators.clampToProgress(Interpolators.LEGACY, t, 0, expandFraction) : 1 - Interpolators.clampToProgress( Interpolators.LINEAR, t, expandFraction, 1); - } else { - interpolator = Interpolators.LEGACY_DECELERATE; + } else { + interpolator = Interpolators.LEGACY_DECELERATE; + } } mPulseAnimator = diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt index 5e19439cd643..9fe316f99136 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles.base.viewmodel import android.os.UserHandle +import com.android.systemui.Dumpable import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger @@ -34,6 +35,7 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.throttle import com.android.systemui.util.time.SystemClock +import java.io.PrintWriter import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -81,7 +83,7 @@ class QSTileViewModelImpl<DATA_TYPE>( private val systemClock: SystemClock, private val backgroundDispatcher: CoroutineDispatcher, private val tileScope: CoroutineScope = CoroutineScope(SupervisorJob()), -) : QSTileViewModel { +) : QSTileViewModel, Dumpable { private val users: MutableStateFlow<UserHandle> = MutableStateFlow(userRepository.getSelectedUserInfo().userHandle) @@ -137,6 +139,13 @@ class QSTileViewModelImpl<DATA_TYPE>( tileScope.cancel() } + override fun dump(pw: PrintWriter, args: Array<out String>) = + with(pw) { + println("${config.tileSpec.spec}:") + print(" ") + println(state.replayCache.lastOrNull().toString()) + } + private fun createTileDataFlow(): SharedFlow<DATA_TYPE> = users .flatMapLatest { user -> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt new file mode 100644 index 000000000000..63865777e14f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt @@ -0,0 +1,63 @@ +/* + * 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.qs.tiles.impl.alarm.domain + +import android.content.res.Resources +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper +import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel +import com.android.systemui.qs.tiles.viewmodel.QSTileConfig +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.res.R +import java.time.Instant +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.util.TimeZone +import javax.inject.Inject + +/** Maps [AlarmTileModel] to [QSTileState]. */ +class AlarmTileMapper @Inject constructor(@Main private val resources: Resources) : + QSTileDataToStateMapper<AlarmTileModel> { + companion object { + val formatter12Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E hh:mm a") + val formatter24Hour: DateTimeFormatter = DateTimeFormatter.ofPattern("E HH:mm") + } + override fun map(config: QSTileConfig, data: AlarmTileModel): QSTileState = + QSTileState.build(resources, config.uiConfig) { + when (data) { + is AlarmTileModel.NextAlarmSet -> { + activationState = QSTileState.ActivationState.ACTIVE + + val localDateTime = + LocalDateTime.ofInstant( + Instant.ofEpochMilli(data.alarmClockInfo.triggerTime), + TimeZone.getDefault().toZoneId() + ) + secondaryLabel = + if (data.is24HourFormat) formatter24Hour.format(localDateTime) + else formatter12Hour.format(localDateTime) + } + is AlarmTileModel.NoAlarmSet -> { + activationState = QSTileState.ActivationState.INACTIVE + secondaryLabel = resources.getString(R.string.qs_alarm_tile_no_alarm) + } + } + + contentDescription = label + supportedActions = setOf(QSTileState.UserAction.CLICK) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileDataInteractor.kt new file mode 100644 index 000000000000..51cd501c0c80 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileDataInteractor.kt @@ -0,0 +1,57 @@ +/* + * 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.qs.tiles.impl.alarm.domain.interactor + +import android.os.UserHandle +import com.android.systemui.common.coroutine.ConflatedCallbackFlow +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.alarm.domain.model.AlarmTileModel +import com.android.systemui.statusbar.policy.NextAlarmController +import com.android.systemui.util.time.DateFormatUtil +import javax.inject.Inject +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf + +/** Observes alarm state changes providing the [AlarmTileModel]. */ +class AlarmTileDataInteractor +@Inject +constructor( + private val alarmController: NextAlarmController, + private val dateFormatUtil: DateFormatUtil +) : QSTileDataInteractor<AlarmTileModel> { + + override fun tileData( + user: UserHandle, + triggers: Flow<DataUpdateTrigger> + ): Flow<AlarmTileModel> = + ConflatedCallbackFlow.conflatedCallbackFlow { + val alarmCallback = + NextAlarmController.NextAlarmChangeCallback { + val model = + if (it == null) AlarmTileModel.NoAlarmSet + else AlarmTileModel.NextAlarmSet(dateFormatUtil.is24HourFormat, it) + trySend(model) + } + alarmController.addCallback(alarmCallback) + + awaitClose { alarmController.removeCallback(alarmCallback) } + } + + override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true) +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt new file mode 100644 index 000000000000..afca57c75788 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt @@ -0,0 +1,67 @@ +/* + * 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.qs.tiles.impl.alarm.domain.interactor + +import android.content.Intent +import android.provider.AlarmClock +import com.android.internal.jank.InteractionJankMonitor +import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.qs.tiles.base.interactor.QSTileInput +import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel +import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction +import javax.inject.Inject + +/** Handles alarm tile clicks. */ +class AlarmTileUserActionInteractor +@Inject +constructor( + private val activityStarter: ActivityStarter, +) : QSTileUserActionInteractor<AlarmTileModel> { + override suspend fun handleInput(input: QSTileInput<AlarmTileModel>): Unit = + with(input) { + when (action) { + is QSTileUserAction.Click -> { + val animationController = + action.view?.let { + ActivityLaunchAnimator.Controller.fromView( + it, + InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE + ) + } + if ( + data is AlarmTileModel.NextAlarmSet && + data.alarmClockInfo.showIntent != null + ) { + val pendingIndent = data.alarmClockInfo.showIntent + activityStarter.postStartActivityDismissingKeyguard( + pendingIndent, + animationController + ) + } else { + activityStarter.postStartActivityDismissingKeyguard( + Intent(AlarmClock.ACTION_SHOW_ALARMS), + 0, + animationController + ) + } + } + is QSTileUserAction.LongClick -> {} + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/model/AlarmTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/model/AlarmTileModel.kt new file mode 100644 index 000000000000..7647d7cf3194 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/model/AlarmTileModel.kt @@ -0,0 +1,28 @@ +/* + * 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.qs.tiles.impl.alarm.domain.model + +import android.app.AlarmManager + +/** Alarm tile model */ +sealed interface AlarmTileModel { + data object NoAlarmSet : AlarmTileModel + data class NextAlarmSet( + val is24HourFormat: Boolean, + val alarmClockInfo: AlarmManager.AlarmClockInfo + ) : AlarmTileModel +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt index e8623f9f7664..977df81a0783 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt @@ -22,6 +22,7 @@ import android.util.Log import android.view.View import androidx.annotation.GuardedBy import com.android.internal.logging.InstanceId +import com.android.systemui.Dumpable import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.plugins.qs.QSTile @@ -31,6 +32,7 @@ import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import java.io.PrintWriter import java.util.function.Supplier import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -47,7 +49,7 @@ constructor( @Application private val applicationScope: CoroutineScope, private val qsHost: QSHost, @Assisted private val qsTileViewModel: QSTileViewModel, -) : QSTile { +) : QSTile, Dumpable { private val context get() = qsHost.context @@ -201,6 +203,10 @@ constructor( override fun getTileSpec(): String = qsTileViewModel.config.tileSpec.spec + override fun dump(pw: PrintWriter, args: Array<out String>) = + (qsTileViewModel as? Dumpable)?.dump(pw, args) + ?: pw.println("${getTileSpec()}: QSTileViewModel isn't dumpable") + private companion object { const val DEBUG = false diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 377803fa6639..45917e85d80e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -248,9 +248,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } @Override - public void animateNavBarLongPress(boolean isTouchDown, long durationMs) { + public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) { verifyCallerAndClearCallingIdentityPostMain("animateNavBarLongPress", () -> - notifyAnimateNavBarLongPress(isTouchDown, durationMs)); + notifyAnimateNavBarLongPress(isTouchDown, shrink, durationMs)); } @Override @@ -929,9 +929,10 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } - private void notifyAnimateNavBarLongPress(boolean isTouchDown, long durationMs) { + private void notifyAnimateNavBarLongPress(boolean isTouchDown, boolean shrink, + long durationMs) { for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { - mConnectionCallbacks.get(i).animateNavBarLongPress(isTouchDown, durationMs); + mConnectionCallbacks.get(i).animateNavBarLongPress(isTouchDown, shrink, durationMs); } } @@ -1079,7 +1080,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis default void onAssistantGestureCompletion(float velocity) {} default void startAssistant(Bundle bundle) {} default void setAssistantOverridesRequested(int[] invocationTypes) {} - default void animateNavBarLongPress(boolean isTouchDown, long durationMs) {} + default void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {} } /** diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index bff0b93dccb0..62d8fb99603e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -177,7 +177,8 @@ public class RecordingController activityStarter, mUserContextProvider, onStartRecordingClicked, - mMediaProjectionMetricsLogger)) + mMediaProjectionMetricsLogger, + mDialogFactory)) : new ScreenRecordDialog( context, /* controller= */ this, diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt index 3f6c58d73346..10d51a59e44c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt @@ -28,6 +28,7 @@ import android.view.MotionEvent.ACTION_MOVE import android.view.View import android.view.View.GONE import android.view.View.VISIBLE +import android.view.accessibility.AccessibilityNodeInfo import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.Spinner @@ -54,6 +55,7 @@ class ScreenRecordPermissionDialogDelegate( private val userContextProvider: UserContextProvider, private val onStartRecordingClicked: Runnable?, mediaProjectionMetricsLogger: MediaProjectionMetricsLogger, + private val systemUIDialogFactory: SystemUIDialog.Factory ) : BaseMediaProjectionPermissionDialogDelegate<SystemUIDialog>( createOptionList(), @@ -62,14 +64,18 @@ class ScreenRecordPermissionDialogDelegate( mediaProjectionMetricsLogger, R.drawable.ic_screenrecord, R.color.screenrecord_icon_color - ) { + ), SystemUIDialog.Delegate { private lateinit var tapsSwitch: Switch private lateinit var tapsView: View private lateinit var audioSwitch: Switch private lateinit var options: Spinner + override fun createDialog(): SystemUIDialog { + return systemUIDialogFactory.create(this) + } + override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { - super.onCreate(dialog, savedInstanceState) + super<BaseMediaProjectionPermissionDialogDelegate>.onCreate(dialog, savedInstanceState) setDialogTitle(R.string.screenrecord_permission_dialog_title) dialog.setTitle(R.string.screenrecord_title) setStartButtonText(R.string.screenrecord_permission_dialog_continue) @@ -129,6 +135,19 @@ class ScreenRecordPermissionDialogDelegate( options.setOnItemClickListenerInt { _: AdapterView<*>?, _: View?, _: Int, _: Long -> audioSwitch.isChecked = true } + + // disable redundant Touch & Hold accessibility action for Switch Access + options.accessibilityDelegate = + object : View.AccessibilityDelegate() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfo + ) { + info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK) + super.onInitializeAccessibilityNodeInfo(host, info) + } + } + options.isLongClickable = false } override fun onItemSelected(adapterView: AdapterView<*>?, view: View, pos: Int, id: Long) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 67ec03fc3d0a..fa3e172d11f1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -130,6 +130,7 @@ import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewConfigurator; import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; @@ -542,6 +543,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private final NPVCDownEventState.Buffer mLastDownEvents; private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel; private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; + private final KeyguardClockInteractor mKeyguardClockInteractor; private float mMinExpandHeight; private boolean mPanelUpdateWhenAnimatorEnds; private boolean mHasVibratedOnOpen = false; @@ -561,7 +563,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private boolean mHasLayoutedSinceDown; private float mUpdateFlingVelocity; private boolean mUpdateFlingOnLayout; - private boolean mClosing; private boolean mTouchSlopExceeded; private int mTrackingPointer; private int mTouchSlop; @@ -615,10 +616,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private boolean mIsOcclusionTransitionRunning = false; private boolean mIsGoneToDreamingLockscreenHostedTransitionRunning; private int mDreamingToLockscreenTransitionTranslationY; - private int mOccludedToLockscreenTransitionTranslationY; private int mLockscreenToDreamingTransitionTranslationY; private int mGoneToDreamingTransitionTranslationY; - private int mLockscreenToOccludedTransitionTranslationY; private SplitShadeStateController mSplitShadeStateController; private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */, mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */); @@ -760,6 +759,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump SystemClock systemClock, KeyguardBottomAreaViewModel keyguardBottomAreaViewModel, KeyguardBottomAreaInteractor keyguardBottomAreaInteractor, + KeyguardClockInteractor keyguardClockInteractor, AlternateBouncerInteractor alternateBouncerInteractor, DreamingToLockscreenTransitionViewModel dreamingToLockscreenTransitionViewModel, OccludedToLockscreenTransitionViewModel occludedToLockscreenTransitionViewModel, @@ -964,6 +964,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump updateUserSwitcherFlags(); mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel; mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor; + mKeyguardClockInteractor = keyguardClockInteractor; KeyguardLongPressViewBinder.bind( mView.requireViewById(R.id.keyguard_long_press), keyguardLongPressViewModel, @@ -1157,11 +1158,13 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // Occluded->Lockscreen collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(), mOccludedToLockscreenTransition, mMainDispatcher); - collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(), + if (!KeyguardShadeMigrationNssl.isEnabled()) { + collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(), setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); - collectFlow(mView, mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY( - mOccludedToLockscreenTransitionTranslationY), - setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); + collectFlow(mView, + mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY(), + setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); + } // Lockscreen->Dreaming collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(), @@ -1187,8 +1190,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mLockscreenToOccludedTransition, mMainDispatcher); collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(), setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); - collectFlow(mView, mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY( - mLockscreenToOccludedTransitionTranslationY), + collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(), setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher); // Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth) @@ -1220,14 +1222,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump R.dimen.split_shade_scrim_transition_distance); mDreamingToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize( R.dimen.dreaming_to_lockscreen_transition_lockscreen_translation_y); - mOccludedToLockscreenTransitionTranslationY = mResources.getDimensionPixelSize( - R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y); mLockscreenToDreamingTransitionTranslationY = mResources.getDimensionPixelSize( R.dimen.lockscreen_to_dreaming_transition_lockscreen_translation_y); mGoneToDreamingTransitionTranslationY = mResources.getDimensionPixelSize( R.dimen.gone_to_dreaming_transition_lockscreen_translation_y); - mLockscreenToOccludedTransitionTranslationY = mResources.getDimensionPixelSize( - R.dimen.lockscreen_to_occluded_transition_lockscreen_translation_y); // TODO (b/265193930): remove this and make QsController listen to NotificationPanelViews mQsController.loadDimens(); } @@ -1610,7 +1608,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); boolean shouldAnimateClockChange = mScreenOffAnimationController.shouldAnimateClockChange(); if (mFeatureFlags.isEnabled(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT)) { - mKeyguardInteractor.setClockSize(computeDesiredClockSize()); + mKeyguardClockInteractor.setClockSize(computeDesiredClockSize()); } else { mKeyguardStatusViewController.displayClock(computeDesiredClockSize(), shouldAnimateClockChange); @@ -2935,10 +2933,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @VisibleForTesting void setClosing(boolean isClosing) { - if (mClosing != isClosing) { - mClosing = isClosing; - mShadeExpansionStateManager.notifyPanelCollapsingChanged(isClosing); - } + mShadeRepository.setLegacyIsClosing(isClosing); mAmbientState.setIsClosing(isClosing); } @@ -3469,7 +3464,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump ipw.print("mHasLayoutedSinceDown="); ipw.println(mHasLayoutedSinceDown); ipw.print("mUpdateFlingVelocity="); ipw.println(mUpdateFlingVelocity); ipw.print("mUpdateFlingOnLayout="); ipw.println(mUpdateFlingOnLayout); - ipw.print("mClosing="); ipw.println(mClosing); + ipw.print("isClosing()="); ipw.println(isClosing()); ipw.print("mTouchSlopExceeded="); ipw.println(mTouchSlopExceeded); ipw.print("mTrackingPointer="); ipw.println(mTrackingPointer); ipw.print("mTouchSlop="); ipw.println(mTouchSlop); @@ -3808,7 +3803,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } private void endClosing() { - if (mClosing) { + if (isClosing()) { setClosing(false); onClosingFinished(); } @@ -3928,7 +3923,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mExpandedHeight = Math.min(h, maxPanelHeight); // If we are closing the panel and we are almost there due to a slow decelerating // interpolator, abort the animation. - if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) { + if (mExpandedHeight < 1f && mExpandedHeight != 0f && isClosing()) { mExpandedHeight = 0f; if (mHeightAnimator != null) { mHeightAnimator.end(); @@ -4003,7 +3998,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @Override public boolean isCollapsing() { - return mClosing || mIsLaunchAnimationRunning; + return isClosing() || mIsLaunchAnimationRunning; } public boolean isTracking() { @@ -4012,7 +4007,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @Override public boolean canBeCollapsed() { - return !isFullyCollapsed() && !isTracking() && !mClosing; + return !isFullyCollapsed() && !isTracking() && !isClosing(); } @Override @@ -4127,7 +4122,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @VisibleForTesting boolean isClosing() { - return mClosing; + return mShadeRepository.getLegacyIsClosing().getValue(); } @Override @@ -4834,15 +4829,17 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: - mCentralSurfaces.userActivity(); + if (!KeyguardShadeMigrationNssl.isEnabled()) { + mCentralSurfaces.userActivity(); + } mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation; mMinExpandHeight = 0.0f; mDownTime = mSystemClock.uptimeMillis(); - if (mAnimatingOnDown && mClosing) { + if (mAnimatingOnDown && isClosing()) { cancelHeightAnimator(); mTouchSlopExceeded = true; mShadeLog.v("NotificationPanelViewController MotionEvent intercepted:" - + " mAnimatingOnDown: true, mClosing: true"); + + " mAnimatingOnDown: true, isClosing(): true"); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index cf1dfdc3f701..73537edcc94a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -311,6 +311,9 @@ public class NotificationShadeWindowViewController implements Dumpable { mTouchActive = true; mTouchCancelled = false; mDownEvent = ev; + if (KeyguardShadeMigrationNssl.isEnabled()) { + mService.userActivity(); + } } else if (ev.getActionMasked() == MotionEvent.ACTION_UP || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) { mTouchActive = false; diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt index 53eccfdf70d5..832fefc33ae0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeEmptyImplModule.kt @@ -17,6 +17,8 @@ package com.android.systemui.shade import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorEmptyImpl import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractorEmptyImpl import dagger.Binds @@ -36,4 +38,10 @@ abstract class ShadeEmptyImplModule { @Binds @SysUISingleton abstract fun bindsShadeInteractor(si: ShadeInteractorEmptyImpl): ShadeInteractor + + @Binds + @SysUISingleton + abstract fun bindsShadeAnimationInteractor( + sai: ShadeAnimationInteractorEmptyImpl + ): ShadeAnimationInteractor } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt index e20534cc7840..d6db19e507a6 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt @@ -163,12 +163,6 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { } } - fun notifyPanelCollapsingChanged(isCollapsing: Boolean) { - for (cb in shadeStateEventsListeners) { - cb.onPanelCollapsingChanged(isCollapsing) - } - } - private fun debugLog(msg: String) { if (!DEBUG) return Log.v(TAG, msg) diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt index 54467cffa401..d9b298d0dfa9 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt @@ -19,6 +19,9 @@ package com.android.systemui.shade import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.shared.flag.SceneContainerFlags import com.android.systemui.shade.domain.interactor.BaseShadeInteractor +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorSceneContainerImpl import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl @@ -45,6 +48,20 @@ abstract class ShadeModule { sceneContainerOff.get() } } + + @Provides + @SysUISingleton + fun provideShadeAnimationInteractor( + sceneContainerFlags: SceneContainerFlags, + sceneContainerOn: Provider<ShadeAnimationInteractorSceneContainerImpl>, + sceneContainerOff: Provider<ShadeAnimationInteractorLegacyImpl> + ): ShadeAnimationInteractor { + return if (sceneContainerFlags.isEnabled()) { + sceneContainerOn.get() + } else { + sceneContainerOff.get() + } + } } @Binds diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt index c8511d76f5f0..ff96ca3caeea 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt @@ -27,10 +27,6 @@ interface ShadeStateEvents { /** Callbacks for certain notification panel events. */ interface ShadeStateEventsListener { - - /** Invoked when the notification panel starts or stops collapsing. */ - fun onPanelCollapsingChanged(isCollapsing: Boolean) {} - /** * Invoked when the notification panel starts or stops launching an [android.app.Activity]. */ diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt index 47b08fe037a4..e94a3eb5db22 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt @@ -105,6 +105,12 @@ interface ShadeRepository { /** True when QS is taking up the entire screen, i.e. fully expanded on a non-unfolded phone. */ @Deprecated("Use ShadeInteractor instead") val legacyQsFullscreen: StateFlow<Boolean> + /** NPVC.mClosing as a flow. */ + @Deprecated("Use ShadeAnimationInteractor instead") val legacyIsClosing: StateFlow<Boolean> + + /** Sets whether a closing animation is happening. */ + @Deprecated("Use ShadeAnimationInteractor instead") fun setLegacyIsClosing(isClosing: Boolean) + /** */ @Deprecated("Use ShadeInteractor instead") fun setLegacyQsFullscreen(legacyQsFullscreen: Boolean) @@ -261,6 +267,15 @@ constructor(shadeExpansionStateManager: ShadeExpansionStateManager) : ShadeRepos _legacyShadeTracking.value = tracking } + private val _legacyIsClosing = MutableStateFlow(false) + @Deprecated("Use ShadeInteractor instead") + override val legacyIsClosing: StateFlow<Boolean> = _legacyIsClosing.asStateFlow() + + @Deprecated("Use ShadeInteractor instead") + override fun setLegacyIsClosing(isClosing: Boolean) { + _legacyIsClosing.value = isClosing + } + @Deprecated("Should only be called by NPVC and tests") override fun setLegacyLockscreenShadeTracking(tracking: Boolean) { legacyLockscreenShadeTracking.value = tracking diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractor.kt new file mode 100644 index 000000000000..ff422b72c694 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractor.kt @@ -0,0 +1,30 @@ +/* + * 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.shade.domain.interactor + +import kotlinx.coroutines.flow.Flow + +/** Business logic related to shade animations and transitions. */ +interface ShadeAnimationInteractor { + /** + * Whether a short animation to close the shade or QS is running. This will be false if the user + * is manually closing the shade or QS but true if they lift their finger and an animation + * completes the close. Important: if QS is collapsing back to shade, this will be false because + * that is not considered "closing". + */ + val isAnyCloseAnimationRunning: Flow<Boolean> +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorEmptyImpl.kt new file mode 100644 index 000000000000..b4a134fd1910 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorEmptyImpl.kt @@ -0,0 +1,27 @@ +/* + * 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.shade.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.flowOf + +/** Implementation of ShadeAnimationInteractor for shadeless SysUI variants. */ +@SysUISingleton +class ShadeAnimationInteractorEmptyImpl @Inject constructor() : ShadeAnimationInteractor { + override val isAnyCloseAnimationRunning = flowOf(false) +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorLegacyImpl.kt new file mode 100644 index 000000000000..d51409365014 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorLegacyImpl.kt @@ -0,0 +1,31 @@ +/* + * 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.shade.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.shade.data.repository.ShadeRepository +import javax.inject.Inject + +/** Implementation of ShadeAnimationInteractor compatible with NPVC. */ +@SysUISingleton +class ShadeAnimationInteractorLegacyImpl +@Inject +constructor( + shadeRepository: ShadeRepository, +) : ShadeAnimationInteractor { + override val isAnyCloseAnimationRunning = shadeRepository.legacyIsClosing +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImpl.kt new file mode 100644 index 000000000000..7c0762d755de --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImpl.kt @@ -0,0 +1,57 @@ +/* + * 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.shade.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.ObservableTransitionState +import com.android.systemui.scene.shared.model.SceneKey +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map + +/** Implementation of ShadeAnimationInteractor compatible with the scene container framework. */ +@SysUISingleton +class ShadeAnimationInteractorSceneContainerImpl +@Inject +constructor( + sceneInteractor: SceneInteractor, +) : ShadeAnimationInteractor { + @OptIn(ExperimentalCoroutinesApi::class) + override val isAnyCloseAnimationRunning = + sceneInteractor.transitionState + .flatMapLatest { state -> + when (state) { + is ObservableTransitionState.Idle -> flowOf(false) + is ObservableTransitionState.Transition -> + if ( + (state.fromScene == SceneKey.Shade && + state.toScene != SceneKey.QuickSettings) || + (state.fromScene == SceneKey.QuickSettings && + state.toScene != SceneKey.Shade) + ) { + state.isUserInputOngoing.map { !it } + } else { + flowOf(false) + } + } + } + .distinctUntilChanged() +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt index 7cff8ea7abd2..3fd070c7146e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt @@ -71,14 +71,11 @@ constructor( override val isQsBypassingShade: Flow<Boolean> = sceneInteractor.transitionState - .flatMapLatest { state -> + .map { state -> when (state) { - is ObservableTransitionState.Idle -> flowOf(false) + is ObservableTransitionState.Idle -> false is ObservableTransitionState.Transition -> - flowOf( - state.toScene == SceneKey.QuickSettings && - state.fromScene != SceneKey.Shade - ) + state.toScene == SceneKey.QuickSettings && state.fromScene != SceneKey.Shade } } .distinctUntilChanged() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt index ef87406036b3..599600d61976 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -52,7 +52,7 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView import com.android.systemui.plugins.FalsingManager -import com.android.systemui.plugins.WeatherData +import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.settings.UserTracker import com.android.systemui.shared.regionsampling.RegionSampler diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java index a2379b270f49..46e2391c87e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java @@ -29,6 +29,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeStateEvents; +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor; import com.android.systemui.statusbar.notification.VisibilityLocationProvider; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; @@ -39,6 +40,7 @@ import com.android.systemui.statusbar.notification.collection.provider.VisualSta import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.Compile; import com.android.systemui.util.concurrency.DelayableExecutor; +import com.android.systemui.util.kotlin.JavaAdapter; import java.io.PrintWriter; import java.util.HashMap; @@ -62,7 +64,9 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, private final DelayableExecutor mDelayableExecutor; private final HeadsUpManager mHeadsUpManager; private final ShadeStateEvents mShadeStateEvents; + private final ShadeAnimationInteractor mShadeAnimationInteractor; private final StatusBarStateController mStatusBarStateController; + private final JavaAdapter mJavaAdapter; private final VisibilityLocationProvider mVisibilityLocationProvider; private final VisualStabilityProvider mVisualStabilityProvider; private final WakefulnessLifecycle mWakefulnessLifecycle; @@ -95,11 +99,15 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, DumpManager dumpManager, HeadsUpManager headsUpManager, ShadeStateEvents shadeStateEvents, + ShadeAnimationInteractor shadeAnimationInteractor, + JavaAdapter javaAdapter, StatusBarStateController statusBarStateController, VisibilityLocationProvider visibilityLocationProvider, VisualStabilityProvider visualStabilityProvider, WakefulnessLifecycle wakefulnessLifecycle) { mHeadsUpManager = headsUpManager; + mShadeAnimationInteractor = shadeAnimationInteractor; + mJavaAdapter = javaAdapter; mVisibilityLocationProvider = visibilityLocationProvider; mVisualStabilityProvider = visualStabilityProvider; mWakefulnessLifecycle = wakefulnessLifecycle; @@ -119,6 +127,8 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, mStatusBarStateController.addCallback(mStatusBarStateControllerListener); mPulsing = mStatusBarStateController.isPulsing(); mShadeStateEvents.addShadeStateEventsListener(this); + mJavaAdapter.alwaysCollectFlow(mShadeAnimationInteractor.isAnyCloseAnimationRunning(), + this::onShadeOrQsClosingChanged); pipeline.setVisualStabilityManager(mNotifStabilityManager); } @@ -322,10 +332,9 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable, } } - @Override - public void onPanelCollapsingChanged(boolean isCollapsing) { - mNotifPanelCollapsing = isCollapsing; - updateAllowedStates("notifPanelCollapsing", isCollapsing); + private void onShadeOrQsClosingChanged(boolean isClosing) { + mNotifPanelCollapsing = isClosing; + updateAllowedStates("notifPanelCollapsing", isClosing); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt index b1e52afd3d8d..ecca9731f003 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt @@ -305,8 +305,6 @@ object NotificationIconContainerViewBinder { } } } - // Recalculate all icon positions, to reflect our updates. - view.calculateIconXTranslations() } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt index 3a2e21a048a5..03316548e979 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt @@ -21,6 +21,7 @@ import android.view.View import com.android.internal.util.ContrastColorUtil import com.android.systemui.res.R import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.StatusBarIconView.NO_COLOR import com.android.systemui.statusbar.notification.NotificationUtils import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconColors import kotlinx.coroutines.flow.Flow @@ -54,7 +55,8 @@ object StatusBarIconViewBinder { iconColors.collect { colors -> val isPreL = java.lang.Boolean.TRUE == view.getTag(R.id.icon_is_pre_L) val isColorized = !isPreL || NotificationUtils.isGrayscale(view, contrastColorUtil) - view.staticDrawableColor = colors.staticDrawableColor(view.viewBounds, isColorized) + view.staticDrawableColor = + if (isColorized) colors.staticDrawableColor(view.viewBounds) else NO_COLOR view.setDecorColor(colors.tint) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt index 97d1e1b5f393..2365db451836 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt @@ -35,5 +35,5 @@ interface NotificationIconColors { * Returns the color to be applied to an icon, based on that icon's view bounds and whether or * not the notification icon is colorized. */ - fun staticDrawableColor(viewBounds: Rect, isColorized: Boolean): Int + fun staticDrawableColor(viewBounds: Rect): Int } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt index af37e49c10f6..6e5ac470f1b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt @@ -117,8 +117,8 @@ constructor( override val tint: Int, private val areas: Collection<Rect>, ) : NotificationIconColors { - override fun staticDrawableColor(viewBounds: Rect, isColorized: Boolean): Int { - return if (isColorized && DarkIconDispatcher.isInAreas(areas, viewBounds)) { + override fun staticDrawableColor(viewBounds: Rect): Int { + return if (DarkIconDispatcher.isInAreas(areas, viewBounds)) { tint } else { DarkIconDispatcher.DEFAULT_ICON_TINT diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index 8eda96f62257..f6431a2e65ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -156,7 +156,7 @@ public class NotificationBackgroundView extends View implements Dumpable { new int[]{com.android.internal.R.attr.state_hovered}, new int[]{}}, - new int[]{tintColor, tintColor, tintColor} + new int[]{tintColor, 0, tintColor} ); mBackground.setTintMode(PorterDuff.Mode.SRC_ATOP); mBackground.setTintList(stateList); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt index 5e60b5f4c707..7b2caea3fd9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt @@ -82,6 +82,8 @@ object SharedNotificationContainerBinder { } launch { viewModel.translationY.collect { controller.setTranslationY(it) } } + + launch { viewModel.alpha.collect { controller.setMaxAlphaForExpansion(it) } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index 1febaf99b7b2..da847c020600 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -24,6 +24,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor import com.android.systemui.util.kotlin.sample @@ -38,6 +39,7 @@ import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn @@ -50,6 +52,7 @@ constructor( keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, private val shadeInteractor: ShadeInteractor, + occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel, ) { private val statesForConstrainedNotifications = setOf( @@ -144,14 +147,20 @@ constructor( initialValue = NotificationContainerBounds(0f, 0f), ) + val alpha: Flow<Float> = occludedToLockscreenTransitionViewModel.lockscreenAlpha + /** * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be * translated as the keyguard fades out. */ val translationY: Flow<Float> = - combine(isOnLockscreen, keyguardInteractor.keyguardTranslationY) { + combine( isOnLockscreen, - translationY -> + merge( + keyguardInteractor.keyguardTranslationY, + occludedToLockscreenTransitionViewModel.lockscreenTranslationY, + ) + ) { isOnLockscreen, translationY -> if (isOnLockscreen) { translationY } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 824de01ca59f..2df30dccb13d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -90,8 +90,13 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh private int mLastConfigurationWidthDp = -1; private int mLastConfigurationHeightDp = -1; - private List<Runnable> mOnCreateRunnables = new ArrayList<>(); + private final List<Runnable> mOnCreateRunnables = new ArrayList<>(); + /** + * @deprecated Don't subclass SystemUIDialog. Please subclass {@link Delegate} and pass it to + * {@link Factory#create(DialogDelegate)} to create a custom dialog. + */ + @Deprecated public SystemUIDialog(Context context) { this(context, DEFAULT_THEME, DEFAULT_DISMISS_ON_DEVICE_LOCK); } @@ -109,27 +114,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh Dependency.get(SystemUIDialogManager.class), Dependency.get(SysUiState.class), Dependency.get(BroadcastDispatcher.class), - Dependency.get(DialogLaunchAnimator.class), - new DialogDelegate<>() {}); - } - - @Inject - public SystemUIDialog( - @Application Context context, - FeatureFlags featureFlags, - SystemUIDialogManager systemUIDialogManager, - SysUiState sysUiState, - BroadcastDispatcher broadcastDispatcher, - DialogLaunchAnimator dialogLaunchAnimator) { - this(context, - DEFAULT_THEME, - DEFAULT_DISMISS_ON_DEVICE_LOCK, - featureFlags, - systemUIDialogManager, - sysUiState, - broadcastDispatcher, - dialogLaunchAnimator, - new DialogDelegate<>(){}); + Dependency.get(DialogLaunchAnimator.class)); } public static class Factory { @@ -156,11 +141,25 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh mDialogLaunchAnimator = dialogLaunchAnimator; } + /** Creates a new instance of {@link SystemUIDialog} with no customized behavior. + * + * When you just need a dialog, call this. + */ + public SystemUIDialog create() { + return create(new DialogDelegate<>(){}); + } + /** * Creates a new instance of {@link SystemUIDialog} with {@code delegate} as the {@link - * DialogDelegate}. + * Delegate}. + * + * When you need to customize the dialog, pass it a delegate. */ - public SystemUIDialog create(DialogDelegate<SystemUIDialog> delegate) { + public SystemUIDialog create(Delegate delegate) { + return create((DialogDelegate<SystemUIDialog>) delegate); + } + + private SystemUIDialog create(DialogDelegate<SystemUIDialog> dialogDelegate) { return new SystemUIDialog( mContext, DEFAULT_THEME, @@ -170,7 +169,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh mSysUiState, mBroadcastDispatcher, mDialogLaunchAnimator, - delegate); + dialogDelegate); } } @@ -588,4 +587,18 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh mDialog.dismiss(); } } + + /** + * A delegate class that should be implemented in place of sublcassing {@link SystemUIDialog}. + * + * Implement this interface and then pass an instance of your implementation to + * {@link SystemUIDialog.Factory#create(Delegate)}. + */ + public interface Delegate extends DialogDelegate<SystemUIDialog> { + /** + * Returns a new {@link SystemUIDialog} which has been passed this Delegate in its + * construction. + */ + SystemUIDialog createDialog(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java index f5e90348a7c4..93db91637a3e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SysuiDarkIconDispatcher.java @@ -46,7 +46,8 @@ public interface SysuiDarkIconDispatcher extends DarkIconDispatcher, Dumpable { /** Model for {@link #darkChangeFlow()} */ class DarkChange { - public static final DarkChange EMPTY = new DarkChange(new ArrayList<>(), 0, 0); + public static final DarkChange EMPTY = + new DarkChange(new ArrayList<>(), /* darkIntensity= */ 0f, DEFAULT_ICON_TINT); public DarkChange(Collection<Rect> areas, float darkIntensity, int tint) { this.areas = areas; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt index 75ae16ebab31..0f2da2d09633 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt @@ -26,6 +26,10 @@ import com.android.systemui.qs.tiles.MicrophoneToggleTile import com.android.systemui.qs.tiles.UiModeNightTile import com.android.systemui.qs.tiles.WorkModeTile import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory +import com.android.systemui.qs.tiles.impl.alarm.domain.AlarmTileMapper +import com.android.systemui.qs.tiles.impl.alarm.domain.interactor.AlarmTileDataInteractor +import com.android.systemui.qs.tiles.impl.alarm.domain.interactor.AlarmTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel import com.android.systemui.qs.tiles.impl.flashlight.domain.FlashlightMapper import com.android.systemui.qs.tiles.impl.flashlight.domain.interactor.FlashlightTileDataInteractor import com.android.systemui.qs.tiles.impl.flashlight.domain.interactor.FlashlightTileUserActionInteractor @@ -59,6 +63,7 @@ interface PolicyModule { companion object { const val FLASHLIGHT_TILE_SPEC = "flashlight" const val LOCATION_TILE_SPEC = "location" + const val ALARM_TILE_SPEC = "alarm" /** Inject flashlight config */ @Provides @@ -123,6 +128,38 @@ interface PolicyModule { stateInteractor, mapper, ) + + /** Inject alarm config */ + @Provides + @IntoMap + @StringKey(ALARM_TILE_SPEC) + fun provideAlarmTileConfig(uiEventLogger: QsEventLogger): QSTileConfig = + QSTileConfig( + tileSpec = TileSpec.create(ALARM_TILE_SPEC), + uiConfig = + QSTileUIConfig.Resource( + iconRes = R.drawable.ic_alarm, + labelRes = R.string.status_bar_alarm, + ), + instanceId = uiEventLogger.getNewInstanceId(), + ) + + /** Inject AlarmTile into tileViewModelMap in QSModule */ + @Provides + @IntoMap + @StringKey(ALARM_TILE_SPEC) + fun provideAlarmTileViewModel( + factory: QSTileViewModelFactory.Static<AlarmTileModel>, + mapper: AlarmTileMapper, + stateInteractor: AlarmTileDataInteractor, + userActionInteractor: AlarmTileUserActionInteractor + ): QSTileViewModel = + factory.create( + TileSpec.create(ALARM_TILE_SPEC), + userActionInteractor, + stateInteractor, + mapper, + ) } /** Inject FlashlightTile into tileMap in QSModule */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 39cdfa382bff..fa0cb5c939ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -143,6 +143,8 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { mSetupObserver.register(); mUserManager = context.getSystemService(UserManager.class); mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(handler)); + // This registers the alarm broadcast receiver for the current user + mUserChangedCallback.onUserChanged(getCurrentUser(), context); dumpManager.registerDumpable(getClass().getSimpleName(), this); } @@ -214,6 +216,7 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { @Override public long getNextAlarm() { + // TODO(b/314799105): Migrate usages to NextAlarmController final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId); return info != null ? info.getTriggerTime() : 0; } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt index 10fc83c8b82c..ff73e0e2ab3f 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt @@ -21,6 +21,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.shade.NotificationPanelUnfoldAnimationController import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController import com.android.systemui.unfold.dagger.UnfoldBg +import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager @@ -106,4 +107,20 @@ interface SysUIUnfoldComponent { fun getUnfoldLatencyTracker(): UnfoldLatencyTracker fun getNaturalRotationUnfoldProgressProvider(): NaturalRotationUnfoldProgressProvider + + /** Creates a UnfoldTransitionProgressProvider that calculates progress in the main thread. */ + fun getUnfoldTransitionProgressProvider(): UnfoldTransitionProgressProvider + + /** Creates a UnfoldTransitionProgressProvider that calculates progress in the background. */ + @UnfoldBg + fun getBgUnfoldTransitionProgressProvider(): UnfoldTransitionProgressProvider + + /** Creates a UnfoldTransitionProgressForwarder. */ + fun getUnfoldTransitionProgressForwarder(): UnfoldTransitionProgressForwarder + + /** Creates a FoldStateLoggingProvider. */ + fun getFoldStateLoggingProvider(): Optional<FoldStateLoggingProvider> + + /** Creates a FoldStateLogger. */ + fun getFoldStateLogger(): Optional<FoldStateLogger> } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java index e7e907a90d34..e4f1c87fc305 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.debug.IAdbManager; import android.hardware.usb.UsbManager; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.ServiceManager; @@ -69,8 +70,7 @@ public class UsbDebuggingActivity extends AlertActivity super.onCreate(icicle); // Emulator does not support reseating the usb cable to reshow the dialog. - boolean isEmulator = SystemProperties.get("ro.boot.qemu").equals("1"); - if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0 && !isEmulator) { + if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0 && !Build.IS_EMULATOR) { mDisconnectedReceiver = new UsbDisconnectedReceiver(this); IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE); mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index b403d1d5fbdc..6f58bc2fcc9f 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -31,15 +31,16 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.log.LogBuffer -import com.android.systemui.plugins.ClockAnimations -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockEvents -import com.android.systemui.plugins.ClockFaceConfig -import com.android.systemui.plugins.ClockFaceController -import com.android.systemui.plugins.ClockFaceEvents -import com.android.systemui.plugins.ClockTickRate +import com.android.systemui.plugins.clocks.ClockAnimations +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockEvents +import com.android.systemui.plugins.clocks.ClockFaceConfig +import com.android.systemui.plugins.clocks.ClockFaceController +import com.android.systemui.plugins.clocks.ClockFaceEvents +import com.android.systemui.plugins.clocks.ClockTickRate import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -97,6 +98,7 @@ class ClockEventControllerTest : SysuiTestCase() { @Mock private lateinit var largeLogBuffer: LogBuffer @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor private lateinit var underTest: ClockEventController + @Mock private lateinit var zenModeController: ZenModeController @Before fun setUp() { @@ -140,7 +142,8 @@ class ClockEventControllerTest : SysuiTestCase() { bgExecutor, smallLogBuffer, largeLogBuffer, - withDeps.featureFlags + withDeps.featureFlags, + zenModeController ) underTest.clock = clock diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java index adf0adabe24c..2bbf0dfa1a3b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java @@ -44,13 +44,13 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager; import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel; import com.android.systemui.log.LogBuffer; -import com.android.systemui.plugins.ClockAnimations; -import com.android.systemui.plugins.ClockController; -import com.android.systemui.plugins.ClockEvents; -import com.android.systemui.plugins.ClockFaceConfig; -import com.android.systemui.plugins.ClockFaceController; -import com.android.systemui.plugins.ClockFaceEvents; -import com.android.systemui.plugins.ClockTickRate; +import com.android.systemui.plugins.clocks.ClockAnimations; +import com.android.systemui.plugins.clocks.ClockController; +import com.android.systemui.plugins.clocks.ClockEvents; +import com.android.systemui.plugins.clocks.ClockFaceConfig; +import com.android.systemui.plugins.clocks.ClockFaceController; +import com.android.systemui.plugins.clocks.ClockFaceEvents; +import com.android.systemui.plugins.clocks.ClockTickRate; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.res.R; import com.android.systemui.shared.clocks.AnimatableClockView; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index cb26e6193ae6..e8d86dddcda5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -35,8 +35,8 @@ import android.view.View; import androidx.test.filters.SmallTest; -import com.android.systemui.plugins.ClockFaceConfig; -import com.android.systemui.plugins.ClockTickRate; +import com.android.systemui.plugins.clocks.ClockFaceConfig; +import com.android.systemui.plugins.clocks.ClockTickRate; import com.android.systemui.shared.clocks.ClockRegistry; import com.android.systemui.statusbar.StatusBarState; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index e54b1845ce6b..4508aea81176 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -40,10 +40,10 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextView; -import com.android.systemui.res.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.ClockController; -import com.android.systemui.plugins.ClockFaceController; +import com.android.systemui.plugins.clocks.ClockController; +import com.android.systemui.plugins.clocks.ClockFaceController; +import com.android.systemui.res.R; import com.android.systemui.statusbar.StatusBarState; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index 9c3288b9f93d..fad85526dec9 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -37,8 +37,8 @@ import android.view.View; import com.android.app.animation.Interpolators; import com.android.systemui.animation.ViewHierarchyAnimator; -import com.android.systemui.plugins.ClockConfig; -import com.android.systemui.plugins.ClockController; +import com.android.systemui.plugins.clocks.ClockConfig; +import com.android.systemui.plugins.clocks.ClockController; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; diff --git a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt index 6c91c987f327..2d5c2ab981b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/FaceScanningProviderFactoryTest.kt @@ -27,8 +27,6 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.biometrics.AuthController import com.android.systemui.decor.FaceScanningProviderFactory import com.android.systemui.dump.logcatLogBuffer -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.log.ScreenDecorationsLogger import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.util.mockito.whenever @@ -55,8 +53,6 @@ class FaceScanningProviderFactoryTest : SysuiTestCase() { @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor - @Mock private lateinit var display: Display - private val displayId = 2 @Before @@ -82,8 +78,6 @@ class FaceScanningProviderFactoryTest : SysuiTestCase() { R.bool.config_fillMainBuiltInDisplayCutout, true ) - val featureFlags = FakeFeatureFlags() - featureFlags.set(Flags.STOP_PULSING_FACE_SCANNING_ANIMATION, true) underTest = FaceScanningProviderFactory( authController, @@ -92,7 +86,6 @@ class FaceScanningProviderFactoryTest : SysuiTestCase() { keyguardUpdateMonitor, mock(Executor::class.java), ScreenDecorationsLogger(logcatLogBuffer("FaceScanningProviderFactoryTest")), - featureFlags, ) whenever(authController.faceSensorLocation).thenReturn(Point(10, 10)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index af88df79be87..639276e302a7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -78,7 +78,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; -import com.android.systemui.res.R; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.biometrics.AuthController; import com.android.systemui.decor.CornerDecorProvider; @@ -93,10 +92,9 @@ import com.android.systemui.decor.OverlayWindow; import com.android.systemui.decor.PrivacyDotCornerDecorProviderImpl; import com.android.systemui.decor.PrivacyDotDecorProviderFactory; import com.android.systemui.decor.RoundedCornerResDelegate; -import com.android.systemui.flags.FakeFeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.log.ScreenDecorationsLogger; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R; import com.android.systemui.settings.FakeDisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.commandline.CommandRegistry; @@ -229,16 +227,13 @@ public class ScreenDecorationsTest extends SysuiTestCase { doAnswer(it -> !(mMockCutoutList.isEmpty())).when(mCutoutFactory).getHasProviders(); doReturn(mMockCutoutList).when(mCutoutFactory).getProviders(); - FakeFeatureFlags featureFlags = new FakeFeatureFlags(); - featureFlags.set(Flags.STOP_PULSING_FACE_SCANNING_ANIMATION, true); mFaceScanningDecorProvider = spy(new FaceScanningOverlayProviderImpl( BOUNDS_POSITION_TOP, mAuthController, mStatusBarStateController, mKeyguardUpdateMonitor, mExecutor, - new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")), - featureFlags)); + new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")))); mScreenDecorations = spy(new ScreenDecorations(mContext, mSecureSettings, mCommandRegistry, mUserTracker, mDisplayTracker, mDotViewController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java index 0ff8da5dfba7..8c8544cd6e5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java @@ -20,16 +20,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.hardware.biometrics.BiometricSourceType; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; @@ -60,14 +58,13 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { @Rule public MockitoRule rule = MockitoJUnit.rule(); - @Mock - FingerprintManager mFingerprintManager; - @Mock - FaceManager mFaceManager; - @Mock - SystemUIDialog mDialog; + @Mock Resources mResources; + @Mock FingerprintManager mFingerprintManager; + @Mock FaceManager mFaceManager; + @Mock SystemUIDialog.Factory mSystemUIDialogFactory; + @Mock SystemUIDialog mDialog; + @Mock BiometricNotificationDialogFactory.ActivityStarter mActivityStarter; - private Context mContextSpy; private final ArgumentCaptor<DialogInterface.OnClickListener> mOnClickListenerArgumentCaptor = ArgumentCaptor.forClass(DialogInterface.OnClickListener.class); private final ArgumentCaptor<Intent> mIntentArgumentCaptor = @@ -76,15 +73,16 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { @Before public void setUp() throws ExecutionException, InterruptedException { - mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); - mContext.addMockSystemService(FaceManager.class, mFaceManager); - mContextSpy = spy(mContext); - when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); - doNothing().when(mContextSpy).startActivity(any()); - - mDialogFactory = new BiometricNotificationDialogFactory(); + when(mSystemUIDialogFactory.create()).thenReturn(mDialog); + + mDialogFactory = new BiometricNotificationDialogFactory( + mResources, + mSystemUIDialogFactory, + mFingerprintManager, + mFaceManager + ); } @Test @@ -92,8 +90,7 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { assumeTrue(getContext().getPackageManager() .hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)); - mDialogFactory.createReenrollDialog(mContextSpy, mDialog, - BiometricSourceType.FINGERPRINT); + mDialogFactory.createReenrollDialog(0, mActivityStarter, BiometricSourceType.FINGERPRINT); verify(mDialog).setPositiveButton(anyInt(), mOnClickListenerArgumentCaptor.capture()); @@ -108,7 +105,7 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { removalCallbackArgumentCaptor.getValue().onRemovalSucceeded(null /* fp */, 0 /* remaining */); - verify(mContextSpy).startActivity(mIntentArgumentCaptor.capture()); + verify(mActivityStarter).startActivity(mIntentArgumentCaptor.capture()); assertThat(mIntentArgumentCaptor.getValue().getAction()).isEqualTo( Settings.ACTION_FINGERPRINT_ENROLL); } @@ -118,8 +115,7 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { assumeTrue(getContext().getPackageManager() .hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)); - mDialogFactory.createReenrollDialog(mContextSpy, mDialog, - BiometricSourceType.FINGERPRINT); + mDialogFactory.createReenrollDialog(0, mActivityStarter, BiometricSourceType.FINGERPRINT); verify(mDialog).setPositiveButton(anyInt(), mOnClickListenerArgumentCaptor.capture()); @@ -134,7 +130,7 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { removalCallbackArgumentCaptor.getValue().onRemovalError(null /* fp */, 0 /* errmsgId */, "Error" /* errString */); - verify(mContextSpy, never()).startActivity(any()); + verify(mActivityStarter, never()).startActivity(any()); } @Test @@ -142,8 +138,7 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { assumeTrue(getContext().getPackageManager() .hasSystemFeature(PackageManager.FEATURE_FACE)); - mDialogFactory.createReenrollDialog(mContextSpy, mDialog, - BiometricSourceType.FACE); + mDialogFactory.createReenrollDialog(0, mActivityStarter, BiometricSourceType.FACE); verify(mDialog).setPositiveButton(anyInt(), mOnClickListenerArgumentCaptor.capture()); @@ -158,7 +153,7 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { removalCallbackArgumentCaptor.getValue().onRemovalSucceeded(null /* fp */, 0 /* remaining */); - verify(mContextSpy).startActivity(mIntentArgumentCaptor.capture()); + verify(mActivityStarter).startActivity(mIntentArgumentCaptor.capture()); assertThat(mIntentArgumentCaptor.getValue().getAction()).isEqualTo( "android.settings.FACE_ENROLL"); } @@ -168,8 +163,7 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { assumeTrue(getContext().getPackageManager() .hasSystemFeature(PackageManager.FEATURE_FACE)); - mDialogFactory.createReenrollDialog(mContextSpy, mDialog, - BiometricSourceType.FACE); + mDialogFactory.createReenrollDialog(0, mActivityStarter, BiometricSourceType.FACE); verify(mDialog).setPositiveButton(anyInt(), mOnClickListenerArgumentCaptor.capture()); @@ -184,6 +178,6 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { removalCallbackArgumentCaptor.getValue().onRemovalError(null /* face */, 0 /* errmsgId */, "Error" /* errString */); - verify(mContextSpy, never()).startActivity(any()); + verify(mActivityStarter, never()).startActivity(any()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java index 3c106789290d..c6771b262114 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricNotificationServiceTest.java @@ -18,9 +18,7 @@ package com.android.systemui.biometrics; import static com.android.systemui.biometrics.BiometricNotificationBroadcastReceiver.ACTION_SHOW_FACE_REENROLL_DIALOG; import static com.android.systemui.biometrics.BiometricNotificationBroadcastReceiver.ACTION_SHOW_FINGERPRINT_REENROLL_DIALOG; - import static com.google.common.truth.Truth.assertThat; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; @@ -71,6 +69,8 @@ public class BiometricNotificationServiceTest extends SysuiTestCase { @Mock NotificationManager mNotificationManager; @Mock + BiometricNotificationDialogFactory mNotificationDialogFactory; + @Mock Optional<FingerprintReEnrollNotification> mFingerprintReEnrollNotificationOptional; @Mock FingerprintReEnrollNotification mFingerprintReEnrollNotification; @@ -103,9 +103,8 @@ public class BiometricNotificationServiceTest extends SysuiTestCase { mLooper = TestableLooper.get(this); Handler handler = new Handler(mLooper.getLooper()); - BiometricNotificationDialogFactory dialogFactory = new BiometricNotificationDialogFactory(); BiometricNotificationBroadcastReceiver broadcastReceiver = - new BiometricNotificationBroadcastReceiver(mContext, dialogFactory); + new BiometricNotificationBroadcastReceiver(mContext, mNotificationDialogFactory); mBiometricNotificationService = new BiometricNotificationService(mContext, mKeyguardUpdateMonitor, mKeyguardStateController, handler, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt index dfb18b9cdc79..f5f1622ac69b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelTest.kt @@ -17,29 +17,23 @@ package com.android.systemui.biometrics.ui.viewmodel import androidx.test.filters.SmallTest -import com.android.systemui.SysUITestComponent -import com.android.systemui.SysUITestModule import com.android.systemui.SysuiTestCase -import com.android.systemui.TestMocksModule -import com.android.systemui.collectLastValue -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition -import com.android.systemui.runCurrent -import com.android.systemui.runTest -import com.android.systemui.shade.data.repository.FakeShadeRepository +import com.android.systemui.keyguard.ui.viewmodel.deviceEntryIconViewModelTransitionsMock +import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.phone.SystemUIDialogManager -import com.android.systemui.user.domain.UserDomainLayerModule -import com.android.systemui.util.mockito.mock +import com.android.systemui.statusbar.phone.systemUIDialogManager +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat -import dagger.BindsInstance -import dagger.Component import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -53,35 +47,11 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(JUnit4::class) class DeviceEntryUdfpsTouchOverlayViewModelTest : SysuiTestCase() { - @Captor - private lateinit var sysuiDialogListenerCaptor: ArgumentCaptor<SystemUIDialogManager.Listener> - private var systemUIDialogManager: SystemUIDialogManager = mock() - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - } - - @SysUISingleton - @Component( - modules = - [ - SysUITestModule::class, - UserDomainLayerModule::class, - ] - ) - interface TestComponent : SysUITestComponent<DeviceEntryUdfpsTouchOverlayViewModel> { - val keyguardRepository: FakeKeyguardRepository - val shadeRepository: FakeShadeRepository - @Component.Factory - interface Factory { - fun create( - @BindsInstance test: SysuiTestCase, - featureFlags: FakeFeatureFlagsClassicModule, - mocks: TestMocksModule, - ): TestComponent + val kosmos = + testKosmos().apply { + featureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, true) } } - } + val testScope = kosmos.testScope private val testDeviceEntryIconTransitionAlpha = MutableStateFlow(0f) private val testDeviceEntryIconTransition: DeviceEntryIconTransition @@ -90,60 +60,59 @@ class DeviceEntryUdfpsTouchOverlayViewModelTest : SysuiTestCase() { override val deviceEntryParentViewAlpha: Flow<Float> = testDeviceEntryIconTransitionAlpha.asStateFlow() } - private val testComponent: TestComponent = - DaggerDeviceEntryUdfpsTouchOverlayViewModelTest_TestComponent.factory() - .create( - test = this, - featureFlags = - FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) }, - mocks = - TestMocksModule( - systemUIDialogManager = systemUIDialogManager, - deviceEntryIconTransitions = - setOf( - testDeviceEntryIconTransition, - ) - ), - ) + + init { + kosmos.deviceEntryIconViewModelTransitionsMock.add(testDeviceEntryIconTransition) + } + val systemUIDialogManager = kosmos.systemUIDialogManager + private val underTest = kosmos.deviceEntryUdfpsTouchOverlayViewModel + + @Captor + private lateinit var sysuiDialogListenerCaptor: ArgumentCaptor<SystemUIDialogManager.Listener> + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + } @Test fun dialogShowing_shouldHandleTouchesFalse() = - testComponent.runTest { + testScope.runTest { val shouldHandleTouches by collectLastValue(underTest.shouldHandleTouches) - runCurrent() testDeviceEntryIconTransitionAlpha.value = 1f + runCurrent() + verify(systemUIDialogManager).registerListener(sysuiDialogListenerCaptor.capture()) sysuiDialogListenerCaptor.value.shouldHideAffordances(true) - runCurrent() assertThat(shouldHandleTouches).isFalse() } @Test fun transitionAlphaIsSmall_shouldHandleTouchesFalse() = - testComponent.runTest { + testScope.runTest { val shouldHandleTouches by collectLastValue(underTest.shouldHandleTouches) - runCurrent() testDeviceEntryIconTransitionAlpha.value = .3f + runCurrent() + verify(systemUIDialogManager).registerListener(sysuiDialogListenerCaptor.capture()) sysuiDialogListenerCaptor.value.shouldHideAffordances(false) - runCurrent() assertThat(shouldHandleTouches).isFalse() } @Test fun alphaFullyShowing_noDialog_shouldHandleTouchesTrue() = - testComponent.runTest { + testScope.runTest { val shouldHandleTouches by collectLastValue(underTest.shouldHandleTouches) - runCurrent() testDeviceEntryIconTransitionAlpha.value = 1f + runCurrent() + verify(systemUIDialogManager).registerListener(sysuiDialogListenerCaptor.capture()) sysuiDialogListenerCaptor.value.shouldHideAffordances(false) - runCurrent() assertThat(shouldHandleTouches).isTrue() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java index eee0ed45345d..4022d4388ab1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java @@ -16,8 +16,10 @@ package com.android.systemui.bluetooth; +import static com.android.systemui.statusbar.phone.SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK; import static com.google.common.truth.Truth.assertThat; - +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -26,31 +28,41 @@ import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.TextView; import androidx.test.filters.SmallTest; -import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; -import com.android.systemui.res.R; -import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; +import com.android.systemui.broadcast.BroadcastSender; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.media.dialog.MediaOutputDialogFactory; +import com.android.systemui.model.SysUiState; +import com.android.systemui.res.R; +import com.android.systemui.statusbar.phone.SystemUIDialog; +import com.android.systemui.statusbar.phone.SystemUIDialogManager; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) -public class BroadcastDialogTest extends SysuiTestCase { +public class BroadcastDialogDelegateTest extends SysuiTestCase { private static final String CURRENT_BROADCAST_APP = "Music"; private static final String SWITCH_APP = "System UI"; @@ -61,33 +73,64 @@ public class BroadcastDialogTest extends SysuiTestCase { private final LocalBluetoothLeBroadcast mLocalBluetoothLeBroadcast = mock( LocalBluetoothLeBroadcast.class); private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class); - private BroadcastDialog mBroadcastDialog; - private View mDialogView; + private BroadcastDialogDelegate mBroadcastDialogDelegate; + private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); + @Mock SystemUIDialog.Factory mSystemUIDialogFactory; + @Mock SystemUIDialogManager mDialogManager; + @Mock SysUiState mSysUiState; + @Mock DialogLaunchAnimator mDialogLaunchAnimator; + @Mock MediaOutputDialogFactory mMediaOutputDialogFactory; + private SystemUIDialog mDialog; private TextView mTitle; private TextView mSubTitle; private Button mSwitchBroadcastAppButton; private Button mChangeOutputButton; + private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null); - mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class), - mLocalBluetoothManager, CURRENT_BROADCAST_APP, TEST_PACKAGE, - mock(UiEventLogger.class), mBroadcastSender); - mBroadcastDialog.show(); - mDialogView = mBroadcastDialog.mDialogView; + + mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM, true); + when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); + when(mSystemUIDialogFactory.create(any())).thenReturn(mDialog); + + mBroadcastDialogDelegate = new BroadcastDialogDelegate( + mContext, + mMediaOutputDialogFactory, + mLocalBluetoothManager, + new UiEventLoggerFake(), + mFakeExecutor, + mBroadcastSender, + mSystemUIDialogFactory, + CURRENT_BROADCAST_APP, + TEST_PACKAGE); + + mDialog = new SystemUIDialog( + mContext, + 0, + DEFAULT_DISMISS_ON_DEVICE_LOCK, + mFeatureFlags, + mDialogManager, + mSysUiState, + getFakeBroadcastDispatcher(), + mDialogLaunchAnimator, + mBroadcastDialogDelegate + ); + + mDialog.show(); } @After public void tearDown() { - mBroadcastDialog.dismiss(); + mDialog.dismiss(); } @Test public void onCreate_withCurrentApp_titleIsCurrentAppName() { - mTitle = mDialogView.requireViewById(R.id.dialog_title); + mTitle = mDialog.requireViewById(R.id.dialog_title); assertThat(mTitle.getText().toString()).isEqualTo(mContext.getString( R.string.bt_le_audio_broadcast_dialog_title, CURRENT_BROADCAST_APP)); @@ -95,7 +138,7 @@ public class BroadcastDialogTest extends SysuiTestCase { @Test public void onCreate_withCurrentApp_subTitleIsSwitchAppName() { - mSubTitle = mDialogView.requireViewById(R.id.dialog_subtitle); + mSubTitle = mDialog.requireViewById(R.id.dialog_subtitle); assertThat(mSubTitle.getText()).isEqualTo( mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title, SWITCH_APP)); @@ -103,7 +146,7 @@ public class BroadcastDialogTest extends SysuiTestCase { @Test public void onCreate_withCurrentApp_switchBtnIsSwitchAppName() { - mSwitchBroadcastAppButton = mDialogView.requireViewById(R.id.switch_broadcast); + mSwitchBroadcastAppButton = mDialog.requireViewById(R.id.switch_broadcast); assertThat(mSwitchBroadcastAppButton.getText().toString()).isEqualTo( mContext.getString(R.string.bt_le_audio_broadcast_dialog_switch_app, SWITCH_APP)); @@ -111,17 +154,17 @@ public class BroadcastDialogTest extends SysuiTestCase { @Test public void onClick_withChangeOutput_dismissBroadcastDialog() { - mChangeOutputButton = mDialogView.requireViewById(R.id.change_output); + mChangeOutputButton = mDialog.requireViewById(R.id.change_output); mChangeOutputButton.performClick(); - assertThat(mBroadcastDialog.isShowing()).isFalse(); + assertThat(mDialog.isShowing()).isFalse(); } @Test public void onClick_withSwitchBroadcast_stopCurrentBroadcast() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); - mSwitchBroadcastAppButton = mDialogView.requireViewById(R.id.switch_broadcast); + mSwitchBroadcastAppButton = mDialog.requireViewById(R.id.switch_broadcast); mSwitchBroadcastAppButton.performClick(); verify(mLocalBluetoothLeBroadcast).stopLatestBroadcast(); @@ -129,7 +172,7 @@ public class BroadcastDialogTest extends SysuiTestCase { @Test public void onClick_withSwitchBroadcast_stopCurrentBroadcastFailed() { - mSwitchBroadcastAppButton = mDialogView.requireViewById(R.id.switch_broadcast); + mSwitchBroadcastAppButton = mDialog.requireViewById(R.id.switch_broadcast); mSwitchBroadcastAppButton.performClick(); assertThat(mSwitchBroadcastAppButton.getText().toString()).isEqualTo( @@ -139,9 +182,9 @@ public class BroadcastDialogTest extends SysuiTestCase { @Test public void handleLeBroadcastStopped_withBroadcastProfileNull_doRefreshButton() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null); - mSwitchBroadcastAppButton = mDialogView.requireViewById(R.id.switch_broadcast); + mSwitchBroadcastAppButton = mDialog.requireViewById(R.id.switch_broadcast); - mBroadcastDialog.handleLeBroadcastStopped(); + mBroadcastDialogDelegate.handleLeBroadcastStopped(); assertThat(mSwitchBroadcastAppButton.getText().toString()).isEqualTo( mContext.getString(R.string.bt_le_audio_broadcast_dialog_switch_app, SWITCH_APP)); @@ -152,7 +195,7 @@ public class BroadcastDialogTest extends SysuiTestCase { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); - mBroadcastDialog.handleLeBroadcastStopped(); + mBroadcastDialogDelegate.handleLeBroadcastStopped(); verify(mLocalBluetoothLeBroadcast).startBroadcast(eq(SWITCH_APP), any()); } @@ -160,17 +203,17 @@ public class BroadcastDialogTest extends SysuiTestCase { @Test public void handleLeBroadcastMetadataChanged_withNotLaunchFlag_doNotDismissDialog() { - mBroadcastDialog.handleLeBroadcastMetadataChanged(); + mBroadcastDialogDelegate.handleLeBroadcastMetadataChanged(); - assertThat(mBroadcastDialog.isShowing()).isTrue(); + assertThat(mDialog.isShowing()).isTrue(); } @Test public void handleLeBroadcastMetadataChanged_withLaunchFlag_dismissDialog() { - mBroadcastDialog.handleLeBroadcastStarted(); - mBroadcastDialog.handleLeBroadcastMetadataChanged(); + mBroadcastDialogDelegate.handleLeBroadcastStarted(); + mBroadcastDialogDelegate.handleLeBroadcastMetadataChanged(); - assertThat(mBroadcastDialog.isShowing()).isFalse(); + assertThat(mDialog.isShowing()).isFalse(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java index 967196689650..c425e8224a4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java @@ -444,6 +444,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { verify(mClipboardOverlayView, never()).setMinimized(true); verify(mClipboardOverlayView).setMinimized(false); + verify(mClipboardOverlayView).getEnterAnimation(); verify(mClipboardOverlayView).showTextPreview("Test Item", false); } @@ -458,6 +459,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { verify(mClipboardOverlayView).setMinimized(true); verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SHOWN_MINIMIZED, 0, "abc"); + verify(mClipboardOverlayView).getEnterAnimation(); verify(mClipboardOverlayView, never()).setMinimized(false); verify(mClipboardOverlayView, never()).showTextPreview(any(), anyBoolean()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractorTest.kt new file mode 100644 index 000000000000..c5c02080fb80 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractorTest.kt @@ -0,0 +1,82 @@ +/* + * 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.common.ui.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.coroutines.collectLastValue +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.MockitoAnnotations + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class ConfigurationInteractorTest : SysuiTestCase() { + private lateinit var testScope: TestScope + private lateinit var underTest: ConfigurationInteractor + private lateinit var configurationRepository: FakeConfigurationRepository + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + configurationRepository = FakeConfigurationRepository() + testScope = TestScope() + underTest = ConfigurationInteractor(configurationRepository) + } + + @Test + fun dimensionPixelSize() = + testScope.runTest { + val resourceId = 1001 + val pixelSize = 501 + configurationRepository.setDimensionPixelSize(resourceId, pixelSize) + + val dimensionPixelSize by collectLastValue(underTest.dimensionPixelSize(resourceId)) + + configurationRepository.onAnyConfigurationChange() + + assertThat(dimensionPixelSize).isEqualTo(pixelSize) + } + + @Test + fun dimensionPixelSizes() = + testScope.runTest { + val resourceId1 = 1001 + val pixelSize1 = 501 + val resourceId2 = 1002 + val pixelSize2 = 502 + configurationRepository.setDimensionPixelSize(resourceId1, pixelSize1) + configurationRepository.setDimensionPixelSize(resourceId2, pixelSize2) + + val dimensionPixelSizes by + collectLastValue(underTest.dimensionPixelSize(setOf(resourceId1, resourceId2))) + + configurationRepository.onAnyConfigurationChange() + + assertThat(dimensionPixelSizes!![resourceId1]).isEqualTo(pixelSize1) + assertThat(dimensionPixelSizes!![resourceId2]).isEqualTo(pixelSize2) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt new file mode 100644 index 000000000000..e931384fd61e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogDelegateTest.kt @@ -0,0 +1,101 @@ +/* + * 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.contrast + +import android.app.UiModeManager +import android.app.UiModeManager.ContrastUtils.fromContrastLevel +import android.os.Looper +import android.provider.Settings +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.model.SysUiState +import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.SecureSettings +import com.android.systemui.util.time.FakeSystemClock +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.eq +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +/** Test the behaviour of buttons of the [ContrastDialogDelegate]. */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class ContrastDialogDelegateTest : SysuiTestCase() { + + private val mainExecutor = FakeExecutor(FakeSystemClock()) + private lateinit var mContrastDialogDelegate: ContrastDialogDelegate + @Mock private lateinit var sysuiDialogFactory: SystemUIDialog.Factory + @Mock private lateinit var sysuiDialog: SystemUIDialog + @Mock private lateinit var mockUiModeManager: UiModeManager + @Mock private lateinit var mockUserTracker: UserTracker + @Mock private lateinit var mockSecureSettings: SecureSettings + @Mock private lateinit var sysuiState: SysUiState + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + mDependency.injectTestDependency(FeatureFlags::class.java, FakeFeatureFlags()) + mDependency.injectTestDependency(SysUiState::class.java, sysuiState) + mDependency.injectMockDependency(DialogLaunchAnimator::class.java) + whenever(sysuiState.setFlag(any(), any())).thenReturn(sysuiState) + whenever(sysuiDialogFactory.create(any())).thenReturn(sysuiDialog) + whenever(sysuiDialog.layoutInflater).thenReturn(LayoutInflater.from(mContext)) + + whenever(mockUserTracker.userId).thenReturn(context.userId) + if (Looper.myLooper() == null) Looper.prepare() + + mContrastDialogDelegate = + ContrastDialogDelegate( + sysuiDialogFactory, + mainExecutor, + mockUiModeManager, + mockUserTracker, + mockSecureSettings + ) + } + + @Test + fun testClickButtons_putsContrastInSettings() { + mContrastDialogDelegate.onCreate(sysuiDialog, null) + + mContrastDialogDelegate.contrastButtons.forEach { + (contrastLevel: Int, clickedButton: FrameLayout) -> + clickedButton.performClick() + mainExecutor.runAllReady() + verify(mockSecureSettings) + .putFloatForUser( + eq(Settings.Secure.CONTRAST_LEVEL), + eq(fromContrastLevel(contrastLevel)), + eq(context.userId) + ) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt deleted file mode 100644 index 7753197afc9b..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.contrast - -import android.app.UiModeManager -import android.app.UiModeManager.ContrastUtils.fromContrastLevel -import android.os.Looper -import android.provider.Settings -import android.testing.AndroidTestingRunner -import android.widget.FrameLayout -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.settings.UserTracker -import com.android.systemui.util.mockito.whenever -import com.android.systemui.util.settings.SecureSettings -import com.google.common.util.concurrent.MoreExecutors -import java.util.concurrent.Executor -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Mockito.eq -import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations - -/** Test the behaviour of buttons of the [ContrastDialog]. */ -@SmallTest -@RunWith(AndroidTestingRunner::class) -class ContrastDialogTest : SysuiTestCase() { - - private lateinit var mainExecutor: Executor - private lateinit var contrastDialog: ContrastDialog - @Mock private lateinit var mockUiModeManager: UiModeManager - @Mock private lateinit var mockUserTracker: UserTracker - @Mock private lateinit var mockSecureSettings: SecureSettings - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - mainExecutor = MoreExecutors.directExecutor() - whenever(mockUserTracker.userId).thenReturn(context.userId) - } - - @Test - fun testClickButtons_putsContrastInSettings() { - if (Looper.myLooper() == null) Looper.prepare() - contrastDialog = - ContrastDialog( - context, - mainExecutor, - mockUiModeManager, - mockUserTracker, - mockSecureSettings - ) - contrastDialog.show() - try { - contrastDialog.contrastButtons.forEach { - (contrastLevel: Int, clickedButton: FrameLayout) -> - clickedButton.performClick() - verify(mockSecureSettings) - .putFloatForUser( - eq(Settings.Secure.CONTRAST_LEVEL), - eq(fromContrastLevel(contrastLevel)), - eq(context.userId) - ) - } - } finally { - contrastDialog.dismiss() - } - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt index bc40c2ddb407..d75cbec8c542 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.data.repository import android.provider.Settings import androidx.test.filters.SmallTest +import com.android.keyguard.ClockEventController import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.shared.model.SettingsClockSize @@ -47,6 +48,7 @@ class KeyguardClockRepositoryTest : SysuiTestCase() { private lateinit var underTest: KeyguardClockRepository private lateinit var fakeSettings: FakeSettings @Mock private lateinit var clockRegistry: ClockRegistry + @Mock private lateinit var clockEventController: ClockEventController @Before fun setup() { @@ -55,7 +57,14 @@ class KeyguardClockRepositoryTest : SysuiTestCase() { scheduler = TestCoroutineScheduler() dispatcher = StandardTestDispatcher(scheduler) scope = TestScope(dispatcher) - underTest = KeyguardClockRepository(fakeSettings, clockRegistry, dispatcher) + underTest = + KeyguardClockRepositoryImpl( + fakeSettings, + clockRegistry, + clockEventController, + dispatcher, + scope.backgroundScope + ) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt index b3e8fed24c3b..de12b8f91d20 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -130,6 +130,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { mContext, testScope.backgroundScope, dispatcher, + dispatcher, faceAuthRepository, { PrimaryBouncerInteractor( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt index a04ea2e4fa9c..edd781dec3a0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt @@ -24,8 +24,10 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepos import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -35,125 +37,138 @@ import org.junit.runners.JUnit4 @SmallTest @RunWith(JUnit4::class) class KeyguardTransitionAnimationFlowTest : SysuiTestCase() { - private lateinit var underTest: KeyguardTransitionAnimationFlow + private lateinit var underTest: KeyguardTransitionAnimationFlow.SharedFlowBuilder private lateinit var repository: FakeKeyguardTransitionRepository + private lateinit var testScope: TestScope @Before fun setUp() { + testScope = TestScope() repository = FakeKeyguardTransitionRepository() underTest = KeyguardTransitionAnimationFlow( - 1000.milliseconds, - repository.transitions, - ) + testScope.backgroundScope, + mock(), + ) + .setup( + duration = 1000.milliseconds, + stepFlow = repository.transitions, + ) } @Test(expected = IllegalArgumentException::class) - fun zeroDurationThrowsException() = runTest { - val flow = underTest.createFlow(duration = 0.milliseconds, onStep = { it }) - } + fun zeroDurationThrowsException() = + testScope.runTest { + val flow = underTest.sharedFlow(duration = 0.milliseconds, onStep = { it }) + } @Test(expected = IllegalArgumentException::class) - fun startTimePlusDurationGreaterThanTransitionDurationThrowsException() = runTest { - val flow = - underTest.createFlow( - startTime = 300.milliseconds, - duration = 800.milliseconds, - onStep = { it } - ) - } + fun startTimePlusDurationGreaterThanTransitionDurationThrowsException() = + testScope.runTest { + val flow = + underTest.sharedFlow( + startTime = 300.milliseconds, + duration = 800.milliseconds, + onStep = { it } + ) + } @Test - fun onFinishRunsWhenSpecified() = runTest { - val flow = - underTest.createFlow( - duration = 100.milliseconds, - onStep = { it }, - onFinish = { 10f }, - ) - var animationValues = collectLastValue(flow) - repository.sendTransitionStep(step(1f, TransitionState.FINISHED), validateStep = false) - assertThat(animationValues()).isEqualTo(10f) - } + fun onFinishRunsWhenSpecified() = + testScope.runTest { + val flow = + underTest.sharedFlow( + duration = 100.milliseconds, + onStep = { it }, + onFinish = { 10f }, + ) + var animationValues = collectLastValue(flow) + repository.sendTransitionStep(step(1f, TransitionState.FINISHED), validateStep = false) + assertThat(animationValues()).isEqualTo(10f) + } @Test - fun onCancelRunsWhenSpecified() = runTest { - val flow = - underTest.createFlow( - duration = 100.milliseconds, - onStep = { it }, - onCancel = { 100f }, - ) - var animationValues = collectLastValue(flow) - repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED)) - assertThat(animationValues()).isEqualTo(100f) - } + fun onCancelRunsWhenSpecified() = + testScope.runTest { + val flow = + underTest.sharedFlow( + duration = 100.milliseconds, + onStep = { it }, + onCancel = { 100f }, + ) + var animationValues = collectLastValue(flow) + repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED)) + assertThat(animationValues()).isEqualTo(100f) + } @Test - fun usesStartTime() = runTest { - val flow = - underTest.createFlow( - startTime = 500.milliseconds, - duration = 500.milliseconds, - onStep = { it }, - ) - var animationValues = collectLastValue(flow) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(animationValues()).isEqualTo(0f) + fun usesStartTime() = + testScope.runTest { + val flow = + underTest.sharedFlow( + startTime = 500.milliseconds, + duration = 500.milliseconds, + onStep = { it }, + ) + var animationValues = collectLastValue(flow) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(animationValues()).isEqualTo(0f) - // Should not emit a value - repository.sendTransitionStep(step(0.1f, TransitionState.RUNNING)) + // Should not emit a value + repository.sendTransitionStep(step(0.1f, TransitionState.RUNNING)) - repository.sendTransitionStep(step(0.5f, TransitionState.RUNNING)) - assertFloat(animationValues(), 0f) - repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING)) - assertFloat(animationValues(), 0.2f) - repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING)) - assertFloat(animationValues(), 0.6f) - repository.sendTransitionStep(step(1f, TransitionState.RUNNING)) - assertFloat(animationValues(), 1f) - } + repository.sendTransitionStep(step(0.5f, TransitionState.RUNNING)) + assertFloat(animationValues(), 0f) + repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING)) + assertFloat(animationValues(), 0.2f) + repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING)) + assertFloat(animationValues(), 0.6f) + repository.sendTransitionStep(step(1f, TransitionState.RUNNING)) + assertFloat(animationValues(), 1f) + } @Test - fun usesInterpolator() = runTest { - val flow = - underTest.createFlow( - duration = 1000.milliseconds, - interpolator = EMPHASIZED_ACCELERATE, - onStep = { it }, - ) - var animationValues = collectLastValue(flow) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0f)) - repository.sendTransitionStep(step(0.5f, TransitionState.RUNNING)) - assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.5f)) - repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING)) - assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.6f)) - repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING)) - assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.8f)) - repository.sendTransitionStep(step(1f, TransitionState.RUNNING)) - assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(1f)) - } + fun usesInterpolator() = + testScope.runTest { + val flow = + underTest.sharedFlow( + duration = 1000.milliseconds, + interpolator = EMPHASIZED_ACCELERATE, + onStep = { it }, + ) + var animationValues = collectLastValue(flow) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0f)) + repository.sendTransitionStep(step(0.5f, TransitionState.RUNNING)) + assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.5f)) + repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING)) + assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.6f)) + repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING)) + assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0.8f)) + repository.sendTransitionStep(step(1f, TransitionState.RUNNING)) + assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(1f)) + } @Test - fun usesOnStepToDoubleValue() = runTest { - val flow = - underTest.createFlow( - duration = 1000.milliseconds, - onStep = { it * 2 }, - ) - var animationValues = collectLastValue(flow) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertFloat(animationValues(), 0f) - repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING)) - assertFloat(animationValues(), 0.6f) - repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING)) - assertFloat(animationValues(), 1.2f) - repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING)) - assertFloat(animationValues(), 1.6f) - repository.sendTransitionStep(step(1f, TransitionState.RUNNING)) - assertFloat(animationValues(), 2f) - } + fun usesOnStepToDoubleValue() = + testScope.runTest { + val flow = + underTest.sharedFlow( + duration = 1000.milliseconds, + onStep = { it * 2 }, + ) + var animationValues = collectLastValue(flow) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertFloat(animationValues(), 0f) + repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING)) + assertFloat(animationValues(), 0.6f) + repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING)) + assertFloat(animationValues(), 1.2f) + repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING)) + assertFloat(animationValues(), 1.6f) + repository.sendTransitionStep(step(1f, TransitionState.RUNNING)) + assertFloat(animationValues(), 2f) + } private fun assertFloat(actual: Float?, expected: Float) { assertThat(actual!!).isWithin(0.01f).of(expected) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt new file mode 100644 index 000000000000..a4d217f1af79 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt @@ -0,0 +1,103 @@ +/* + * 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.ui.binder + +import android.view.View +import androidx.constraintlayout.helper.widget.Layer +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.clocks.ClockConfig +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockFaceController +import com.android.systemui.plugins.clocks.ClockFaceLayout +import com.android.systemui.util.mockito.whenever +import kotlin.test.Test +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +@kotlinx.coroutines.ExperimentalCoroutinesApi +class KeyguardClockViewBinderTest : SysuiTestCase() { + @Mock private lateinit var rootView: ConstraintLayout + @Mock private lateinit var burnInLayer: Layer + @Mock private lateinit var clock: ClockController + @Mock private lateinit var largeClock: ClockFaceController + @Mock private lateinit var smallClock: ClockFaceController + @Mock private lateinit var largeClockView: View + @Mock private lateinit var smallClockView: View + @Mock private lateinit var smallClockFaceLayout: ClockFaceLayout + @Mock private lateinit var largeClockFaceLayout: ClockFaceLayout + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + } + + @Test + fun addClockViews_nonWeatherClock() { + setupNonWeatherClock() + KeyguardClockViewBinder.addClockViews(clock, rootView, burnInLayer) + verify(rootView).addView(smallClockView) + verify(rootView).addView(largeClockView) + verify(burnInLayer).addView(smallClockView) + verify(burnInLayer, never()).addView(largeClockView) + } + + @Test + fun addClockViews_WeatherClock() { + setupWeatherClock() + KeyguardClockViewBinder.addClockViews(clock, rootView, burnInLayer) + verify(rootView).addView(smallClockView) + verify(rootView).addView(largeClockView) + verify(burnInLayer).addView(smallClockView) + verify(burnInLayer).addView(largeClockView) + } + + private fun setupWeatherClock() { + setupClock() + val clockConfig = + ClockConfig( + id = "WEATHER_CLOCK", + name = "", + description = "", + useAlternateSmartspaceAODTransition = true + ) + whenever(clock.config).thenReturn(clockConfig) + } + + private fun setupNonWeatherClock() { + setupClock() + val clockConfig = ClockConfig(id = "NON_WEATHER_CLOCK", name = "", description = "") + whenever(clock.config).thenReturn(clockConfig) + } + + private fun setupClock() { + whenever(largeClockFaceLayout.views).thenReturn(listOf(largeClockView)) + whenever(smallClockFaceLayout.views).thenReturn(listOf(smallClockView)) + whenever(clock.largeClock).thenReturn(largeClock) + whenever(clock.smallClock).thenReturn(smallClock) + whenever(largeClock.layout).thenReturn(largeClockFaceLayout) + whenever(smallClock.layout).thenReturn(smallClockFaceLayout) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt index 740fce988a68..3109e761e423 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt @@ -27,9 +27,9 @@ import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialInd import com.android.systemui.keyguard.shared.model.KeyguardBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.view.KeyguardRootView -import com.android.systemui.keyguard.ui.view.layout.items.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection +import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt index 6b85cf719ef5..64a07fa9f723 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt @@ -22,9 +22,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags.MIGRATE_CLOCKS_TO_BLUEPRINT -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor -import com.android.systemui.keyguard.ui.view.layout.items.ClockSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R @@ -32,7 +30,6 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.Utils import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import dagger.Lazy import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -47,7 +44,6 @@ class ClockSectionTest : SysuiTestCase() { @Mock private lateinit var keyguardClockViewModel: KeyguardClockViewModel @Mock private lateinit var smartspaceViewModel: KeyguardSmartspaceViewModel @Mock private lateinit var splitShadeStateController: SplitShadeStateController - @Mock private lateinit var keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor> private var featureFlags: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic() private lateinit var underTest: ClockSection @@ -94,7 +90,6 @@ class ClockSectionTest : SysuiTestCase() { smartspaceViewModel, mContext, splitShadeStateController, - keyguardBlueprintInteractor, featureFlags ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt index fc9f54ec74f7..d959872fa80c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt @@ -21,66 +21,45 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager +import com.android.systemui.testKosmos import com.google.common.collect.Range 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.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.mockito.Mock -import org.mockito.MockitoAnnotations @ExperimentalCoroutinesApi @RunWith(JUnit4::class) @SmallTest class AlternateBouncerViewModelTest : SysuiTestCase() { - - private lateinit var testScope: TestScope - - @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager - - private lateinit var transitionRepository: FakeKeyguardTransitionRepository - private lateinit var transitionInteractor: KeyguardTransitionInteractor - private lateinit var underTest: AlternateBouncerViewModel - - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - testScope = TestScope() - - val transitionInteractorWithDependencies = - KeyguardTransitionInteractorFactory.create(testScope.backgroundScope) - transitionInteractor = transitionInteractorWithDependencies.keyguardTransitionInteractor - transitionRepository = transitionInteractorWithDependencies.repository - underTest = - AlternateBouncerViewModel( - statusBarKeyguardViewManager, - transitionInteractor, - ) - } + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val transitionRepository = kosmos.fakeKeyguardTransitionRepository + private val statusBarKeyguardViewManager = kosmos.statusBarKeyguardViewManager + private val underTest = kosmos.alternateBouncerViewModel @Test fun transitionToAlternateBouncer_scrimAlphaUpdate() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val scrimAlphas by collectValues(underTest.scrimAlpha) - transitionRepository.sendTransitionStep( - stepToAlternateBouncer(0f, TransitionState.STARTED) + transitionRepository.sendTransitionSteps( + listOf( + stepToAlternateBouncer(0f, TransitionState.STARTED), + stepToAlternateBouncer(.4f), + stepToAlternateBouncer(.6f), + stepToAlternateBouncer(1f), + ), + testScope, ) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(.4f)) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f)) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f)) assertThat(scrimAlphas.size).isEqualTo(4) scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } @@ -88,15 +67,18 @@ class AlternateBouncerViewModelTest : SysuiTestCase() { @Test fun transitionFromAlternateBouncer_scrimAlphaUpdate() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val scrimAlphas by collectValues(underTest.scrimAlpha) - transitionRepository.sendTransitionStep( - stepFromAlternateBouncer(0f, TransitionState.STARTED) + transitionRepository.sendTransitionSteps( + listOf( + stepToAlternateBouncer(0f, TransitionState.STARTED), + stepToAlternateBouncer(.4f), + stepToAlternateBouncer(.6f), + stepToAlternateBouncer(1f), + ), + testScope, ) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.4f)) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f)) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f)) assertThat(scrimAlphas.size).isEqualTo(4) scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } @@ -104,43 +86,57 @@ class AlternateBouncerViewModelTest : SysuiTestCase() { @Test fun forcePluginOpen() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val forcePluginOpen by collectLastValue(underTest.forcePluginOpen) - transitionRepository.sendTransitionStep( - stepToAlternateBouncer(0f, TransitionState.STARTED) + + transitionRepository.sendTransitionSteps( + listOf( + stepToAlternateBouncer(0f, TransitionState.STARTED), + stepToAlternateBouncer(.4f), + stepToAlternateBouncer(.6f), + stepToAlternateBouncer(1f), + ), + testScope, ) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f)) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f)) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f)) assertThat(forcePluginOpen).isTrue() - transitionRepository.sendTransitionStep( - stepFromAlternateBouncer(0f, TransitionState.STARTED) + transitionRepository.sendTransitionSteps( + listOf( + stepFromAlternateBouncer(0f, TransitionState.STARTED), + stepFromAlternateBouncer(.3f), + stepFromAlternateBouncer(.6f), + stepFromAlternateBouncer(1f), + ), + testScope, ) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f)) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f)) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f)) assertThat(forcePluginOpen).isFalse() } @Test fun registerForDismissGestures() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val registerForDismissGestures by collectLastValue(underTest.registerForDismissGestures) - transitionRepository.sendTransitionStep( - stepToAlternateBouncer(0f, TransitionState.STARTED) + + transitionRepository.sendTransitionSteps( + listOf( + stepToAlternateBouncer(0f, TransitionState.STARTED), + stepToAlternateBouncer(.4f), + stepToAlternateBouncer(.6f), + stepToAlternateBouncer(1f), + ), + testScope, ) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(.3f)) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(.6f)) - transitionRepository.sendTransitionStep(stepToAlternateBouncer(1f)) assertThat(registerForDismissGestures).isTrue() - transitionRepository.sendTransitionStep( - stepFromAlternateBouncer(0f, TransitionState.STARTED) + transitionRepository.sendTransitionSteps( + listOf( + stepFromAlternateBouncer(0f, TransitionState.STARTED), + stepFromAlternateBouncer(.3f), + stepFromAlternateBouncer(.6f), + stepFromAlternateBouncer(1f), + ), + testScope, ) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.3f)) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(.6f)) - transitionRepository.sendTransitionStep(stepFromAlternateBouncer(1f)) assertThat(registerForDismissGestures).isFalse() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt index f282481ba01c..4c972e9195e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt @@ -20,16 +20,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -37,34 +36,25 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class AodToGoneTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: AodToGoneTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = AodToGoneTransitionViewModel(interactor) - } + val kosmos = testKosmos() + val testScope = kosmos.testScope + val repository = kosmos.fakeKeyguardTransitionRepository + val underTest = kosmos.aodToGoneTransitionViewModel @Test - fun deviceEntryParentViewHides() = runTest { - val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.4f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) - deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(0f) } - } + fun deviceEntryParentViewHides() = + testScope.runTest { + val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.1f)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.4f)) + repository.sendTransitionStep(step(0.5f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(0.8f)) + repository.sendTransitionStep(step(1f)) + deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(0f) } + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt index 517149c99a62..af8d8a8978b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt @@ -19,22 +19,18 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -42,83 +38,67 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class AodToLockscreenTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: AodToLockscreenTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - fingerprintPropertyRepository = FakeFingerprintPropertyRepository() - underTest = - AodToLockscreenTransitionViewModel( - interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor, - deviceEntryUdfpsInteractor = - DeviceEntryUdfpsInteractor( - fingerprintPropertyRepository = fingerprintPropertyRepository, - fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(), - biometricSettingsRepository = FakeBiometricSettingsRepository(), - ), - ) - } + val kosmos = testKosmos() + val testScope = kosmos.testScope + val repository = kosmos.fakeKeyguardTransitionRepository + val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + val underTest = kosmos.aodToLockscreenTransitionViewModel @Test - fun deviceEntryParentViewShows() = runTest { - val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(1f)) - deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) } - } + fun deviceEntryParentViewShows() = + testScope.runTest { + val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.1f)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.5f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(1f)) + deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) } + } @Test - fun deviceEntryBackgroundView_udfps_alphaFadeIn() = runTest { - fingerprintPropertyRepository.supportsUdfps() - val deviceEntryBackgroundViewAlpha by - collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + fun deviceEntryBackgroundView_udfps_alphaFadeIn() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + val deviceEntryBackgroundViewAlpha by + collectLastValue(underTest.deviceEntryBackgroundViewAlpha) - // fade in - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + // fade in + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - repository.sendTransitionStep(step(0.1f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(.2f) + repository.sendTransitionStep(step(0.1f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(.2f) - repository.sendTransitionStep(step(0.3f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(.6f) + repository.sendTransitionStep(step(0.3f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(.6f) - repository.sendTransitionStep(step(0.6f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(1f) + repository.sendTransitionStep(step(0.6f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(1f) - } + repository.sendTransitionStep(step(1f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(1f) + } @Test - fun deviceEntryBackgroundView_rearFp_noUpdates() = runTest { - fingerprintPropertyRepository.supportsRearFps() - val deviceEntryBackgroundViewAlpha by - collectLastValue(underTest.deviceEntryBackgroundViewAlpha) - // no updates - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryBackgroundViewAlpha).isNull() - repository.sendTransitionStep(step(0.1f)) - assertThat(deviceEntryBackgroundViewAlpha).isNull() - repository.sendTransitionStep(step(0.3f)) - assertThat(deviceEntryBackgroundViewAlpha).isNull() - repository.sendTransitionStep(step(0.6f)) - assertThat(deviceEntryBackgroundViewAlpha).isNull() - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryBackgroundViewAlpha).isNull() - } + fun deviceEntryBackgroundView_rearFp_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsRearFps() + val deviceEntryBackgroundViewAlpha by + collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + // no updates + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryBackgroundViewAlpha).isNull() + repository.sendTransitionStep(step(0.1f)) + assertThat(deviceEntryBackgroundViewAlpha).isNull() + repository.sendTransitionStep(step(0.3f)) + assertThat(deviceEntryBackgroundViewAlpha).isNull() + repository.sendTransitionStep(step(0.6f)) + assertThat(deviceEntryBackgroundViewAlpha).isNull() + repository.sendTransitionStep(step(1f)) + assertThat(deviceEntryBackgroundViewAlpha).isNull() + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt index 96f69462accf..db8fbf604430 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt @@ -20,16 +20,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -37,34 +36,25 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class AodToOccludedTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: AodToOccludedTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = AodToOccludedTransitionViewModel(interactor) - } + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val repository = kosmos.fakeKeyguardTransitionRepository + private val underTest = kosmos.aodToOccludedTransitionViewModel @Test - fun deviceEntryParentViewHides() = runTest { - val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.4f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) - deviceEntryParentViewAlpha.forEach { Truth.assertThat(it).isEqualTo(0f) } - } + fun deviceEntryParentViewHides() = + testScope.runTest { + val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.1f)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.4f)) + repository.sendTransitionStep(step(0.5f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(0.8f)) + repository.sendTransitionStep(step(1f)) + deviceEntryParentViewAlpha.forEach { Truth.assertThat(it).isEqualTo(0f) } + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt index 1ff46db99624..c9b14a41edca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt @@ -19,28 +19,26 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor +import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor import com.android.systemui.coroutines.collectValues -import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER import com.android.systemui.keyguard.shared.model.ScrimAlpha import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.sysuiStatusBarStateController +import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat -import dagger.Lazy import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -51,56 +49,47 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class BouncerToGoneFlowsTest : SysuiTestCase() { - private lateinit var underTest: BouncerToGoneFlows - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var featureFlags: FakeFeatureFlags - @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController - @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor - @Mock - private lateinit var keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor> @Mock private lateinit var shadeInteractor: ShadeInteractor private val shadeExpansionStateFlow = MutableStateFlow(0.1f) + private val kosmos = + testKosmos().apply { + featureFlagsClassic.apply { + set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) + set(Flags.FULL_SCREEN_USER_SWITCHER, false) + } + } + private val testScope = kosmos.testScope + private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private val shadeRepository = kosmos.shadeRepository + private val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController + private val primaryBouncerInteractor = kosmos.primaryBouncerInteractor + private val underTest = kosmos.bouncerToGoneFlows + @Before fun setUp() { MockitoAnnotations.initMocks(this) - whenever(shadeInteractor.shadeExpansion).thenReturn(shadeExpansionStateFlow) - - repository = FakeKeyguardTransitionRepository() - val featureFlags = - FakeFeatureFlags().apply { set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) } - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = - BouncerToGoneFlows( - interactor, - statusBarStateController, - primaryBouncerInteractor, - keyguardDismissActionInteractor, - featureFlags, - shadeInteractor, - ) - whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false) - whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) + sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false) } @Test fun scrimAlpha_runDimissFromKeyguard_shadeExpanded() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) - shadeExpansionStateFlow.value = 1f + shadeRepository.setLockscreenShadeExpansion(1f) whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.6f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it.frontAlpha).isEqualTo(0f) } @@ -110,16 +99,21 @@ class BouncerToGoneFlowsTest : SysuiTestCase() { @Test fun scrimAlpha_runDimissFromKeyguard_shadeNotExpanded() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) - shadeExpansionStateFlow.value = 0f + shadeRepository.setLockscreenShadeExpansion(0f) whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.6f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isEqualTo(ScrimAlpha()) } @@ -127,15 +121,20 @@ class BouncerToGoneFlowsTest : SysuiTestCase() { @Test fun scrimBehindAlpha_leaveShadeOpen() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) - whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true) + sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.6f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(4) values.forEach { @@ -145,15 +144,17 @@ class BouncerToGoneFlowsTest : SysuiTestCase() { @Test fun scrimBehindAlpha_doNotLeaveShadeOpen() = - runTest(UnconfinedTestDispatcher()) { + testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) - - whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) - - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.6f), + step(1f), + ), + testScope, + ) assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it.notificationsAlpha).isEqualTo(0f) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt index 5dccc3b1d05f..dd542d482745 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt @@ -25,6 +25,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -43,29 +45,36 @@ class DozingToLockscreenTransitionViewModelTest : SysuiTestCase() { @Before fun setUp() { + testScope = TestScope() repository = FakeKeyguardTransitionRepository() underTest = DozingToLockscreenTransitionViewModel( interactor = KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, + scope = testScope.backgroundScope, repository = repository, ) .keyguardTransitionInteractor, + animationFlow = + KeyguardTransitionAnimationFlow( + scope = testScope.backgroundScope, + logger = mock() + ), ) } @Test - fun deviceEntryParentViewShows() = runTest { - val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(1f)) - deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) } - } + fun deviceEntryParentViewShows() = + testScope.runTest { + val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.1f)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.5f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(1f)) + deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) } + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt index c1444a55f7d9..a105008f3f37 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt @@ -19,23 +19,19 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -43,37 +39,12 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class GoneToAodTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: GoneToAodTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository - private lateinit var testScope: TestScope - - @Before - fun setUp() { - val testDispatcher = StandardTestDispatcher() - testScope = TestScope(testDispatcher) - - repository = FakeKeyguardTransitionRepository() - fingerprintPropertyRepository = FakeFingerprintPropertyRepository() - biometricSettingsRepository = FakeBiometricSettingsRepository() - - underTest = - GoneToAodTransitionViewModel( - interactor = - KeyguardTransitionInteractorFactory.create( - scope = testScope.backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor, - deviceEntryUdfpsInteractor = - DeviceEntryUdfpsInteractor( - fingerprintPropertyRepository = fingerprintPropertyRepository, - fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(), - biometricSettingsRepository = biometricSettingsRepository, - ), - ) - } + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val repository = kosmos.fakeKeyguardTransitionRepository + private val underTest = kosmos.goneToAodTransitionViewModel + private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + private val biometricSettingsRepository = kosmos.biometricSettingsRepository @Test fun enterFromTopTranslationY() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt index 46a7735d92a0..d4210040faf3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt @@ -25,11 +25,16 @@ import com.android.keyguard.KeyguardClockSwitch.SMALL import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.KeyguardClockRepository +import com.android.systemui.keyguard.data.repository.KeyguardClockRepositoryImpl import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockFaceConfig +import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.shared.clocks.ClockRegistry +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlin.test.Test @@ -50,7 +55,6 @@ class KeyguardClockViewModelTest : SysuiTestCase() { private lateinit var scheduler: TestCoroutineScheduler private lateinit var dispatcher: CoroutineDispatcher private lateinit var scope: TestScope - private lateinit var underTest: KeyguardClockViewModel private lateinit var keyguardInteractor: KeyguardInteractor private lateinit var keyguardRepository: KeyguardRepository @@ -58,6 +62,9 @@ class KeyguardClockViewModelTest : SysuiTestCase() { private lateinit var keyguardClockRepository: KeyguardClockRepository private lateinit var fakeSettings: FakeSettings @Mock private lateinit var clockRegistry: ClockRegistry + @Mock private lateinit var clock: ClockController + @Mock private lateinit var largeClock: ClockFaceController + @Mock private lateinit var clockFaceConfig: ClockFaceConfig @Mock private lateinit var eventController: ClockEventController @Before fun setup() { @@ -70,13 +77,21 @@ class KeyguardClockViewModelTest : SysuiTestCase() { scheduler = TestCoroutineScheduler() dispatcher = StandardTestDispatcher(scheduler) scope = TestScope(dispatcher) - keyguardClockRepository = KeyguardClockRepository(fakeSettings, clockRegistry, dispatcher) - keyguardClockInteractor = KeyguardClockInteractor(eventController, keyguardClockRepository) + setupMockClock() + keyguardClockRepository = + KeyguardClockRepositoryImpl( + fakeSettings, + clockRegistry, + eventController, + dispatcher, + scope.backgroundScope + ) + keyguardClockInteractor = KeyguardClockInteractor(keyguardClockRepository) underTest = KeyguardClockViewModel( keyguardInteractor, keyguardClockInteractor, - scope.backgroundScope + scope.backgroundScope, ) } @@ -86,7 +101,7 @@ class KeyguardClockViewModelTest : SysuiTestCase() { // When use double line clock is disabled, // should always return small fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 0) - keyguardRepository.setClockSize(LARGE) + keyguardClockRepository.setClockSize(LARGE) val value = collectLastValue(underTest.clockSize) assertThat(value()).isEqualTo(SMALL) } @@ -95,12 +110,19 @@ class KeyguardClockViewModelTest : SysuiTestCase() { fun testClockSize_dynamicClockSize() = scope.runTest { fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1) - keyguardRepository.setClockSize(SMALL) + keyguardClockRepository.setClockSize(SMALL) var value = collectLastValue(underTest.clockSize) assertThat(value()).isEqualTo(SMALL) - keyguardRepository.setClockSize(LARGE) + keyguardClockRepository.setClockSize(LARGE) value = collectLastValue(underTest.clockSize) assertThat(value()).isEqualTo(LARGE) } + + private fun setupMockClock() { + whenever(clock.largeClock).thenReturn(largeClock) + whenever(largeClock.config).thenReturn(clockFaceConfig) + whenever(clockFaceConfig.hasCustomWeatherDataDisplay).thenReturn(false) + whenever(clockRegistry.createCurrentClock()).thenReturn(clock) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt index 88a4aa509c37..864acfb1ddb9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModelTest.kt @@ -17,7 +17,10 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.filters.SmallTest +import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.doze.util.BurnInHelperWrapper import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -65,6 +68,9 @@ class KeyguardIndicationAreaViewModelTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) + + mSetFlagsRule.disableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR) + whenever(burnInHelperWrapper.burnInOffset(anyInt(), any())) .thenReturn(RETURNED_BURN_IN_OFFSET) @@ -83,6 +89,7 @@ class KeyguardIndicationAreaViewModelTest : SysuiTestCase() { keyguardBottomAreaViewModel = bottomAreaViewModel, burnInHelperWrapper = burnInHelperWrapper, shortcutsCombinedViewModel = shortcutsCombinedViewModel, + configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()), ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index a57feda64723..23a2709b7edf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -23,46 +23,41 @@ import android.view.View import androidx.test.filters.SmallTest import com.android.systemui.Flags as AConfigFlags import com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION -import com.android.systemui.SysUITestComponent -import com.android.systemui.SysUITestModule import com.android.systemui.SysuiTestCase -import com.android.systemui.TestMocksModule import com.android.systemui.collectLastValue -import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository -import com.android.systemui.flags.FakeFeatureFlagsClassicModule -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.flags.Flags +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.BurnInInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.BurnInModel import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.plugins.ClockController -import com.android.systemui.runCurrent -import com.android.systemui.runTest -import com.android.systemui.statusbar.notification.data.repository.FakeNotificationsKeyguardViewStateRepository -import com.android.systemui.statusbar.phone.DozeParameters -import com.android.systemui.statusbar.phone.ScreenOffAnimationController -import com.android.systemui.util.mockito.mock +import com.android.systemui.kosmos.testScope +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.statusbar.notification.data.repository.fakeNotificationsKeyguardViewStateRepository +import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor +import com.android.systemui.statusbar.phone.dozeParameters +import com.android.systemui.statusbar.phone.screenOffAnimationController +import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import com.android.systemui.util.ui.isAnimating import com.android.systemui.util.ui.stopAnimating import com.android.systemui.util.ui.value import com.google.common.truth.Truth.assertThat -import dagger.BindsInstance -import dagger.Component import javax.inject.Provider import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.emptyFlow -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -72,45 +67,49 @@ import org.mockito.Answers import org.mockito.Mock import org.mockito.Mockito.RETURNS_DEEP_STUBS import org.mockito.Mockito.anyInt -import org.mockito.Mockito.reset -import org.mockito.Mockito.withSettings import org.mockito.MockitoAnnotations @SmallTest @RunWith(JUnit4::class) class KeyguardRootViewModelTest : SysuiTestCase() { - + private val kosmos = + testKosmos().apply { + featureFlagsClassic.apply { set(Flags.MIGRATE_CLOCKS_TO_BLUEPRINT, false) } + } + private val testScope = kosmos.testScope + private val repository = kosmos.fakeKeyguardRepository + private val configurationRepository = kosmos.fakeConfigurationRepository + private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private val screenOffAnimationController = kosmos.screenOffAnimationController + private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository + private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor + private val fakeNotificationsKeyguardViewStateRepository = + kosmos.fakeNotificationsKeyguardViewStateRepository + private val dozeParameters = kosmos.dozeParameters private lateinit var underTest: KeyguardRootViewModel - private lateinit var testScope: TestScope - private lateinit var repository: FakeKeyguardRepository - private lateinit var keyguardInteractor: KeyguardInteractor - private lateinit var configurationRepository: FakeConfigurationRepository + @Mock private lateinit var burnInInteractor: BurnInInteractor - @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor + private val burnInFlow = MutableStateFlow(BurnInModel()) + @Mock private lateinit var goneToAodTransitionViewModel: GoneToAodTransitionViewModel + private val enterFromTopAnimationAlpha = MutableStateFlow(0f) + @Mock private lateinit var aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var clockController: ClockController + @Mock + private lateinit var occludedToLockscreenTransitionViewModel: + OccludedToLockscreenTransitionViewModel + private val occludedToLockscreenTranslationY = MutableStateFlow(0f) + private val occludedToLockscreenAlpha = MutableStateFlow(0f) - private val burnInFlow = MutableStateFlow(BurnInModel()) - private val goneToAodTransitionViewModelVisibility = MutableStateFlow(0) - private val enterFromTopAnimationAlpha = MutableStateFlow(0f) - private val goneToAodTransitionStep = MutableSharedFlow<TransitionStep>(replay = 1) - private val dozeAmountTransitionStep = MutableSharedFlow<TransitionStep>(replay = 1) - private val startedKeyguardState = MutableStateFlow(KeyguardState.GONE) + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var clockController: ClockController @Before fun setUp() { - val testDispatcher = StandardTestDispatcher() - testScope = TestScope(testDispatcher) MockitoAnnotations.initMocks(this) mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR) - - val withDeps = KeyguardInteractorFactory.create() - keyguardInteractor = withDeps.keyguardInteractor - repository = withDeps.repository - configurationRepository = withDeps.configurationRepository + mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION) whenever(goneToAodTransitionViewModel.enterFromTopTranslationY(anyInt())) .thenReturn(emptyFlow<Float>()) @@ -119,30 +118,29 @@ class KeyguardRootViewModelTest : SysuiTestCase() { whenever(burnInInteractor.keyguardBurnIn).thenReturn(burnInFlow) - whenever(keyguardTransitionInteractor.goneToAodTransition) - .thenReturn(goneToAodTransitionStep) - whenever(keyguardTransitionInteractor.dozeAmountTransition) - .thenReturn(dozeAmountTransitionStep) - whenever(keyguardTransitionInteractor.startedKeyguardState).thenReturn(startedKeyguardState) + whenever(occludedToLockscreenTransitionViewModel.lockscreenTranslationY) + .thenReturn(occludedToLockscreenTranslationY) + whenever(occludedToLockscreenTransitionViewModel.lockscreenAlpha) + .thenReturn(occludedToLockscreenAlpha) underTest = KeyguardRootViewModel( - context, - deviceEntryInteractor = - mock { whenever(isBypassEnabled).thenReturn(MutableStateFlow(false)) }, - dozeParameters = mock(), - keyguardInteractor, - keyguardTransitionInteractor, - notificationsKeyguardInteractor = - mock { - whenever(areNotificationsFullyHidden).thenReturn(emptyFlow()) - whenever(isPulseExpanding).thenReturn(emptyFlow()) - }, - burnInInteractor, - goneToAodTransitionViewModel, - aodToLockscreenTransitionViewModel, - screenOffAnimationController = mock(), + configurationInteractor = kosmos.configurationInteractor, + deviceEntryInteractor = kosmos.deviceEntryInteractor, + dozeParameters = kosmos.dozeParameters, + keyguardInteractor = kosmos.keyguardInteractor, + keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor, + notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor, + burnInInteractor = burnInInteractor, + keyguardClockViewModel = kosmos.keyguardClockViewModel, + goneToAodTransitionViewModel = goneToAodTransitionViewModel, + aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, + occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, + screenOffAnimationController = screenOffAnimationController, + // TODO(b/310989341): remove after change to aconfig + featureFlags = kosmos.featureFlagsClassic ) + underTest.clockControllerProvider = Provider { clockController } } @@ -150,8 +148,8 @@ class KeyguardRootViewModelTest : SysuiTestCase() { fun alpha() = testScope.runTest { val value = collectLastValue(underTest.alpha) + assertThat(value()).isEqualTo(0f) - assertThat(value()).isEqualTo(1f) repository.setKeyguardAlpha(0.1f) assertThat(value()).isEqualTo(0.1f) repository.setKeyguardAlpha(0.5f) @@ -160,6 +158,8 @@ class KeyguardRootViewModelTest : SysuiTestCase() { assertThat(value()).isEqualTo(0.2f) repository.setKeyguardAlpha(0f) assertThat(value()).isEqualTo(0f) + occludedToLockscreenAlpha.value = 0.8f + assertThat(value()).isEqualTo(0.8f) } @Test @@ -170,7 +170,15 @@ class KeyguardRootViewModelTest : SysuiTestCase() { val scale by collectLastValue(underTest.scale) // Set to not dozing (on lockscreen) - dozeAmountTransitionStep.emit(TransitionStep(value = 0f)) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) // Trigger a change to the burn-in model burnInFlow.value = @@ -195,7 +203,15 @@ class KeyguardRootViewModelTest : SysuiTestCase() { underTest.statusViewTop = 100 // Set to dozing (on AOD) - dozeAmountTransitionStep.emit(TransitionStep(value = 1f)) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) // Trigger a change to the burn-in model burnInFlow.value = BurnInModel( @@ -203,12 +219,21 @@ class KeyguardRootViewModelTest : SysuiTestCase() { translationY = 30, scale = 0.5f, ) + assertThat(translationX).isEqualTo(20) assertThat(translationY).isEqualTo(30) assertThat(scale).isEqualTo(Pair(0.5f, true /* scaleClockOnly */)) // Set to the beginning of GONE->AOD transition - goneToAodTransitionStep.emit(TransitionStep(value = 0f)) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 0f, + transitionState = TransitionState.STARTED + ), + validateStep = false, + ) assertThat(translationX).isEqualTo(0) assertThat(translationY).isEqualTo(0) assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */)) @@ -225,7 +250,16 @@ class KeyguardRootViewModelTest : SysuiTestCase() { underTest.topInset = 80 // Set to dozing (on AOD) - dozeAmountTransitionStep.emit(TransitionStep(value = 1f)) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) + // Trigger a change to the burn-in model burnInFlow.value = BurnInModel( @@ -239,7 +273,15 @@ class KeyguardRootViewModelTest : SysuiTestCase() { assertThat(scale).isEqualTo(Pair(0.5f, true /* scaleClockOnly */)) // Set to the beginning of GONE->AOD transition - goneToAodTransitionStep.emit(TransitionStep(value = 0f)) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 0f, + transitionState = TransitionState.STARTED + ), + validateStep = false, + ) assertThat(translationX).isEqualTo(0) assertThat(translationY).isEqualTo(0) assertThat(scale).isEqualTo(Pair(1f, true /* scaleClockOnly */)) @@ -255,7 +297,15 @@ class KeyguardRootViewModelTest : SysuiTestCase() { val scale by collectLastValue(underTest.scale) // Set to dozing (on AOD) - dozeAmountTransitionStep.emit(TransitionStep(value = 1f)) + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + value = 1f, + transitionState = TransitionState.FINISHED + ), + validateStep = false, + ) // Trigger a change to the burn-in model burnInFlow.value = @@ -275,10 +325,15 @@ class KeyguardRootViewModelTest : SysuiTestCase() { testScope.runTest { val burnInLayerVisibility by collectLastValue(underTest.burnInLayerVisibility) - startedKeyguardState.value = KeyguardState.OCCLUDED - assertThat(burnInLayerVisibility).isNull() - - startedKeyguardState.value = KeyguardState.AOD + keyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + value = 0f, + transitionState = TransitionState.STARTED + ), + validateStep = false, + ) assertThat(burnInLayerVisibility).isEqualTo(View.VISIBLE) } @@ -293,165 +348,124 @@ class KeyguardRootViewModelTest : SysuiTestCase() { enterFromTopAnimationAlpha.value = 1f assertThat(burnInLayerAlpha).isEqualTo(1f) } -} - -@SmallTest -class KeyguardRootViewModelTestWithFakes : SysuiTestCase() { - - @Component(modules = [SysUITestModule::class]) - @SysUISingleton - interface TestComponent : SysUITestComponent<KeyguardRootViewModel> { - val deviceEntryRepository: FakeDeviceEntryRepository - val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository - val repository: FakeKeyguardRepository - val transitionRepository: FakeKeyguardTransitionRepository - - @Component.Factory - interface Factory { - fun create( - @BindsInstance test: SysuiTestCase, - featureFlags: FakeFeatureFlagsClassicModule, - mocks: TestMocksModule, - ): TestComponent - } - } - private val clockController: ClockController = - mock(withSettings().defaultAnswer(RETURNS_DEEP_STUBS)) - private val dozeParams: DozeParameters = mock() - private val screenOffAnimController: ScreenOffAnimationController = mock() - - private fun runTest(block: suspend TestComponent.() -> Unit): Unit = - DaggerKeyguardRootViewModelTestWithFakes_TestComponent.factory() - .create( - test = this, - featureFlags = FakeFeatureFlagsClassicModule(), - mocks = - TestMocksModule( - dozeParameters = dozeParams, - screenOffAnimationController = screenOffAnimController, - ), + @Test + fun iconContainer_isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.OFF, + to = KeyguardState.GONE, + testScope, ) - .runTest { - reset(clockController) - underTest.clockControllerProvider = Provider { clockController } - block() - } - - @Before - fun before() { - mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION) - } + whenever(screenOffAnimationController.shouldShowAodIconsWhenShade()).thenReturn(false) + runCurrent() - @Test - fun iconContainer_isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - transitionRepository.sendTransitionSteps( - from = KeyguardState.OFF, - to = KeyguardState.GONE, - testScope, - ) - whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false) - runCurrent() - - assertThat(isVisible?.value).isFalse() - assertThat(isVisible?.isAnimating).isFalse() - } + assertThat(isVisible?.value).isFalse() + assertThat(isVisible?.isAnimating).isFalse() + } @Test - fun iconContainer_isVisible_bypassEnabled() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - deviceEntryRepository.setBypassEnabled(true) - runCurrent() + fun iconContainer_isVisible_bypassEnabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + deviceEntryRepository.setBypassEnabled(true) + runCurrent() - assertThat(isVisible?.value).isTrue() - } + assertThat(isVisible?.value).isTrue() + } @Test - fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(true) - deviceEntryRepository.setBypassEnabled(false) - runCurrent() - - assertThat(isVisible?.value).isEqualTo(false) - } + fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(true) + deviceEntryRepository.setBypassEnabled(false) + runCurrent() + + assertThat(isVisible?.value).isEqualTo(false) + } @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassEnabled() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(true) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isTrue() - } + fun iconContainer_isVisible_notifsFullyHidden_bypassEnabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(true) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isTrue() + } @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(false) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isFalse() - } + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(false) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isFalse() + } @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(true) - whenever(dozeParams.displayNeedsBlanking).thenReturn(true) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isFalse() - } + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(true) + whenever(dozeParameters.displayNeedsBlanking).thenReturn(true) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isFalse() + } @Test - fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(true) - whenever(dozeParams.displayNeedsBlanking).thenReturn(false) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.value).isTrue() - assertThat(isVisible?.isAnimating).isTrue() - } + fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(true) + whenever(dozeParameters.displayNeedsBlanking).thenReturn(false) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.value).isTrue() + assertThat(isVisible?.isAnimating).isTrue() + } @Test - fun isIconContainerVisible_stopAnimation() = runTest { - val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) - runCurrent() - notifsKeyguardRepository.setPulseExpanding(false) - deviceEntryRepository.setBypassEnabled(false) - whenever(dozeParams.alwaysOn).thenReturn(true) - whenever(dozeParams.displayNeedsBlanking).thenReturn(false) - notifsKeyguardRepository.setNotificationsFullyHidden(true) - runCurrent() - - assertThat(isVisible?.isAnimating).isEqualTo(true) - isVisible?.stopAnimating() - runCurrent() - - assertThat(isVisible?.isAnimating).isEqualTo(false) - } + fun isIconContainerVisible_stopAnimation() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isNotifIconContainerVisible) + runCurrent() + fakeNotificationsKeyguardViewStateRepository.setPulseExpanding(false) + deviceEntryRepository.setBypassEnabled(false) + whenever(dozeParameters.alwaysOn).thenReturn(true) + whenever(dozeParameters.displayNeedsBlanking).thenReturn(false) + fakeNotificationsKeyguardViewStateRepository.setNotificationsFullyHidden(true) + runCurrent() + + assertThat(isVisible?.isAnimating).isEqualTo(true) + isVisible?.stopAnimating() + runCurrent() + + assertThat(isVisible?.isAnimating).isEqualTo(false) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt index 2314c8358ff8..c15a2c6a3df7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt @@ -18,88 +18,47 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.SysUITestComponent -import com.android.systemui.SysUITestModule import com.android.systemui.SysuiTestCase -import com.android.systemui.TestMocksModule -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository -import com.android.systemui.collectLastValue -import com.android.systemui.collectValues -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository -import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.runCurrent -import com.android.systemui.runTest -import com.android.systemui.shade.data.repository.FakeShadeRepository -import com.android.systemui.user.domain.UserDomainLayerModule +import com.android.systemui.kosmos.testScope +import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat -import dagger.BindsInstance -import dagger.Component import kotlin.test.Test import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.runner.RunWith @ExperimentalCoroutinesApi @SmallTest @RunWith(AndroidJUnit4::class) class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { - @SysUISingleton - @Component( - modules = - [ - SysUITestModule::class, - UserDomainLayerModule::class, - ] - ) - interface TestComponent : SysUITestComponent<LockscreenToAodTransitionViewModel> { - val repository: FakeKeyguardTransitionRepository - val deviceEntryRepository: FakeDeviceEntryRepository - val keyguardRepository: FakeKeyguardRepository - val shadeRepository: FakeShadeRepository - val fingerprintPropertyRepository: FakeFingerprintPropertyRepository - val biometricSettingsRepository: FakeBiometricSettingsRepository - - @Component.Factory - interface Factory { - fun create( - @BindsInstance test: SysuiTestCase, - featureFlags: FakeFeatureFlagsClassicModule, - mocks: TestMocksModule, - ): TestComponent - } - } - - private fun TestComponent.shadeExpanded(expanded: Boolean) { - if (expanded) { - shadeRepository.setQsExpansion(1f) - } else { - keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) - shadeRepository.setQsExpansion(0f) - shadeRepository.setLockscreenShadeExpansion(0f) - } - } - - private val testComponent: TestComponent = - DaggerLockscreenToAodTransitionViewModelTest_TestComponent.factory() - .create( - test = this, - featureFlags = - FakeFeatureFlagsClassicModule { set(FULL_SCREEN_USER_SWITCHER, true) }, - mocks = TestMocksModule(), - ) + private val kosmos = + testKosmos().apply { featureFlagsClassic.apply { set(FULL_SCREEN_USER_SWITCHER, false) } } + private val testScope = kosmos.testScope + private val repository = kosmos.fakeKeyguardTransitionRepository + private val shadeRepository = kosmos.shadeRepository + private val keyguardRepository = kosmos.fakeKeyguardRepository + private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + private val biometricSettingsRepository = kosmos.biometricSettingsRepository + private val underTest = kosmos.lockscreenToAodTransitionViewModel @Test fun backgroundViewAlpha_shadeNotExpanded() = - testComponent.runTest { + testScope.runTest { val actual by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) shadeExpanded(false) runCurrent() @@ -121,7 +80,7 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { @Test fun backgroundViewAlpha_shadeExpanded() = - testComponent.runTest { + testScope.runTest { val actual by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) shadeExpanded(true) runCurrent() @@ -142,7 +101,7 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { @Test fun deviceEntryParentViewAlpha_udfpsEnrolled_shadeNotExpanded() = - testComponent.runTest { + testScope.runTest { val values by collectValues(underTest.deviceEntryParentViewAlpha) fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) @@ -165,7 +124,7 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { @Test fun deviceEntryParentViewAlpha_udfpsEnrolled_shadeExpanded() = - testComponent.runTest { + testScope.runTest { val actual by collectLastValue(underTest.deviceEntryParentViewAlpha) fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) @@ -189,7 +148,7 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { @Test fun deviceEntryParentViewAlpha_rearFp_shadeNotExpanded() = - testComponent.runTest { + testScope.runTest { val actual by collectLastValue(underTest.deviceEntryParentViewAlpha) fingerprintPropertyRepository.supportsRearFps() shadeExpanded(false) @@ -212,7 +171,7 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { @Test fun deviceEntryParentViewAlpha_rearFp_shadeExpanded() = - testComponent.runTest { + testScope.runTest { val values by collectValues(underTest.deviceEntryParentViewAlpha) fingerprintPropertyRepository.supportsRearFps() shadeExpanded(true) @@ -232,6 +191,16 @@ class LockscreenToAodTransitionViewModelTest : SysuiTestCase() { values.forEach { assertThat(it).isEqualTo(0f) } } + private fun shadeExpanded(expanded: Boolean) { + if (expanded) { + shadeRepository.setQsExpansion(1f) + } else { + keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) + shadeRepository.setQsExpansion(0f) + shadeRepository.setLockscreenShadeExpansion(0f) + } + } + private fun step( value: Float, state: TransitionState = TransitionState.RUNNING diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt index 1494c92cdb06..8b05a54fe7cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt @@ -20,16 +20,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -37,37 +36,25 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class LockscreenToGoneTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: LockscreenToGoneTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = - LockscreenToGoneTransitionViewModel( - interactor, - ) - } + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val repository = kosmos.fakeKeyguardTransitionRepository + private val underTest = kosmos.lockscreenToGoneTransitionViewModel @Test - fun deviceEntryParentViewHides() = runTest { - val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.1f)) - repository.sendTransitionStep(step(0.3f)) - repository.sendTransitionStep(step(0.4f)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(0.6f)) - repository.sendTransitionStep(step(0.8f)) - repository.sendTransitionStep(step(1f)) - deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(0f) } - } + fun deviceEntryParentViewHides() = + testScope.runTest { + val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.1f)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.4f)) + repository.sendTransitionStep(step(0.5f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(0.8f)) + repository.sendTransitionStep(step(1f)) + deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(0f) } + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt index 049e4e27e374..b31968c79647 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt @@ -18,81 +18,44 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.SysUITestComponent -import com.android.systemui.SysUITestModule import com.android.systemui.SysuiTestCase -import com.android.systemui.TestMocksModule -import com.android.systemui.collectLastValue -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.runCurrent -import com.android.systemui.runTest -import com.android.systemui.shade.data.repository.FakeShadeRepository -import com.android.systemui.user.domain.UserDomainLayerModule +import com.android.systemui.kosmos.testScope +import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth -import dagger.BindsInstance -import dagger.Component import kotlin.test.Test import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.runner.RunWith @ExperimentalCoroutinesApi @SmallTest @RunWith(AndroidJUnit4::class) class LockscreenToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { - @SysUISingleton - @Component( - modules = - [ - SysUITestModule::class, - UserDomainLayerModule::class, - ] - ) - interface TestComponent : SysUITestComponent<LockscreenToPrimaryBouncerTransitionViewModel> { - val repository: FakeKeyguardTransitionRepository - val keyguardRepository: FakeKeyguardRepository - val shadeRepository: FakeShadeRepository - - @Component.Factory - interface Factory { - fun create( - @BindsInstance test: SysuiTestCase, - featureFlags: FakeFeatureFlagsClassicModule, - mocks: TestMocksModule, - ): TestComponent + private val kosmos = + testKosmos().apply { + featureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) } } - } - - private fun TestComponent.shadeExpanded(expanded: Boolean) { - if (expanded) { - shadeRepository.setQsExpansion(1f) - } else { - keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) - shadeRepository.setQsExpansion(0f) - shadeRepository.setLockscreenShadeExpansion(0f) - } - } - - private val testComponent: TestComponent = - DaggerLockscreenToPrimaryBouncerTransitionViewModelTest_TestComponent.factory() - .create( - test = this, - featureFlags = - FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) }, - mocks = TestMocksModule(), - ) + private val testScope = kosmos.testScope + private val repository = kosmos.fakeKeyguardTransitionRepository + private val shadeRepository = kosmos.shadeRepository + private val keyguardRepository = kosmos.fakeKeyguardRepository + private val underTest = kosmos.lockscreenToPrimaryBouncerTransitionViewModel @Test fun deviceEntryParentViewAlpha_shadeExpanded() = - testComponent.runTest { + testScope.runTest { val actual by collectLastValue(underTest.deviceEntryParentViewAlpha) shadeExpanded(true) runCurrent() @@ -117,7 +80,7 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { @Test fun deviceEntryParentViewAlpha_shadeNotExpanded() = - testComponent.runTest { + testScope.runTest { val actual by collectLastValue(underTest.deviceEntryParentViewAlpha) shadeExpanded(false) runCurrent() @@ -153,4 +116,14 @@ class LockscreenToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { ownerName = "LockscreenToPrimaryBouncerTransitionViewModelTest" ) } + + private fun shadeExpanded(expanded: Boolean) { + if (expanded) { + shadeRepository.setQsExpansion(1f) + } else { + keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD) + shadeRepository.setQsExpansion(0f) + shadeRepository.setLockscreenShadeExpansion(0f) + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt index 0eb8ff6ba966..5e6231734d32 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt @@ -19,21 +19,18 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -41,119 +38,105 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class OccludedToAodTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: OccludedToAodTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - fingerprintPropertyRepository = FakeFingerprintPropertyRepository() - biometricSettingsRepository = FakeBiometricSettingsRepository() - - underTest = - OccludedToAodTransitionViewModel( - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor, - DeviceEntryUdfpsInteractor( - fingerprintPropertyRepository = fingerprintPropertyRepository, - fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(), - biometricSettingsRepository = biometricSettingsRepository, - ), - ) - } + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val biometricSettingsRepository = kosmos.biometricSettingsRepository + val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + val underTest = kosmos.occludedToAodTransitionViewModel @Test - fun deviceEntryBackgroundViewAlpha() = runTest { - val deviceEntryBackgroundViewAlpha by - collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + fun deviceEntryBackgroundViewAlpha() = + testScope.runTest { + val deviceEntryBackgroundViewAlpha by + collectLastValue(underTest.deviceEntryBackgroundViewAlpha) - // immediately 0f - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + // immediately 0f + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - repository.sendTransitionStep(step(0.4f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + keyguardTransitionRepository.sendTransitionStep(step(0.4f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - repository.sendTransitionStep(step(.85f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + keyguardTransitionRepository.sendTransitionStep(step(.85f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - } + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + } @Test - fun deviceEntryParentViewAlpha_udfpsEnrolled() = runTest { - fingerprintPropertyRepository.supportsUdfps() - biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) - val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + fun deviceEntryParentViewAlpha_udfpsEnrolled() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) - // immediately 1f - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + // immediately 1f + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(0.5f)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(.95f)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(.95f)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + } @Test - fun deviceEntryParentViewAlpha_rearFpEnrolled_noUpdates() = runTest { - fingerprintPropertyRepository.supportsRearFps() - biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) - val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + fun deviceEntryParentViewAlpha_rearFpEnrolled_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsRearFps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) - // no updates - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryParentViewAlpha).isNull() + // no updates + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(0.5f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(.95f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(.95f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(deviceEntryParentViewAlpha).isNull() - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(deviceEntryParentViewAlpha).isNull() + } @Test - fun deviceEntryParentViewAlpha_udfpsNotEnrolled_noUpdates() = runTest { - fingerprintPropertyRepository.supportsUdfps() - biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) - val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + fun deviceEntryParentViewAlpha_udfpsNotEnrolled_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) - // no updates - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryParentViewAlpha).isNull() + // no updates + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(0.5f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(.95f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(.95f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(deviceEntryParentViewAlpha).isNull() - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(deviceEntryParentViewAlpha).isNull() + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt index 350b31008478..9729022ca890 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt @@ -19,21 +19,18 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -41,113 +38,100 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class PrimaryBouncerToAodTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: PrimaryBouncerToAodTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - fingerprintPropertyRepository = FakeFingerprintPropertyRepository() - biometricSettingsRepository = FakeBiometricSettingsRepository() - val interactor = - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor - underTest = - PrimaryBouncerToAodTransitionViewModel( - interactor, - DeviceEntryUdfpsInteractor( - fingerprintPropertyRepository = fingerprintPropertyRepository, - fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(), - biometricSettingsRepository = biometricSettingsRepository, - ), - ) - } + + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + val biometricSettingsRepository = kosmos.biometricSettingsRepository + + val underTest = kosmos.primaryBouncerToAodTransitionViewModel @Test - fun deviceEntryBackgroundViewAlpha() = runTest { - fingerprintPropertyRepository.supportsUdfps() - val deviceEntryBackgroundViewAlpha by - collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + fun deviceEntryBackgroundViewAlpha() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + val deviceEntryBackgroundViewAlpha by + collectLastValue(underTest.deviceEntryBackgroundViewAlpha) - // immediately 0f - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + // immediately 0f + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - repository.sendTransitionStep(step(0.4f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + keyguardTransitionRepository.sendTransitionStep(step(0.4f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - repository.sendTransitionStep(step(.85f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + keyguardTransitionRepository.sendTransitionStep(step(.85f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) - } + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(0f) + } @Test - fun deviceEntryParentViewAlpha_udfpsEnrolled_fadeIn() = runTest { - fingerprintPropertyRepository.supportsUdfps() - biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) - val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + fun deviceEntryParentViewAlpha_udfpsEnrolled_fadeIn() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) - repository.sendTransitionStep(step(0.5f)) - repository.sendTransitionStep(step(.75f)) - repository.sendTransitionStep(step(1f)) + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + keyguardTransitionRepository.sendTransitionStep(step(.75f)) + keyguardTransitionRepository.sendTransitionStep(step(1f)) - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + } @Test - fun deviceEntryParentViewAlpha_rearFpEnrolled_noUpdates() = runTest { - fingerprintPropertyRepository.supportsRearFps() - biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) - val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + fun deviceEntryParentViewAlpha_rearFpEnrolled_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsRearFps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) - // animation doesn't start until the end - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryParentViewAlpha).isNull() + // animation doesn't start until the end + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(0.5f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(.95f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(.95f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(deviceEntryParentViewAlpha).isNull() - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(deviceEntryParentViewAlpha).isNull() + } @Test - fun deviceEntryParentViewAlpha_udfpsNotEnrolled_noUpdates() = runTest { - fingerprintPropertyRepository.supportsUdfps() - biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) - val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + fun deviceEntryParentViewAlpha_udfpsNotEnrolled_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(0.5f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(.75f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(.75f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryParentViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryParentViewAlpha).isNull() - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(deviceEntryParentViewAlpha).isNull() - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(deviceEntryParentViewAlpha).isNull() + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt index 24e4920c66d6..2c6436e07b91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt @@ -19,21 +19,18 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -41,91 +38,77 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class PrimaryBouncerToLockscreenTransitionViewModelTest : SysuiTestCase() { - private lateinit var underTest: PrimaryBouncerToLockscreenTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository - - @Before - fun setUp() { - repository = FakeKeyguardTransitionRepository() - fingerprintPropertyRepository = FakeFingerprintPropertyRepository() - biometricSettingsRepository = FakeBiometricSettingsRepository() - - underTest = - PrimaryBouncerToLockscreenTransitionViewModel( - KeyguardTransitionInteractorFactory.create( - scope = TestScope().backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor, - DeviceEntryUdfpsInteractor( - fingerprintPropertyRepository = fingerprintPropertyRepository, - fingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository(), - biometricSettingsRepository = biometricSettingsRepository, - ), - ) - } + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + val biometricSettingsRepository = kosmos.biometricSettingsRepository + + val underTest = kosmos.primaryBouncerToLockscreenTransitionViewModel @Test - fun deviceEntryParentViewAlpha() = runTest { - val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + fun deviceEntryParentViewAlpha() = + testScope.runTest { + val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) - // immediately 1f - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + // immediately 1f + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(0.4f)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(0.4f)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(.85f)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(.85f)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(1f)) - assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) - } + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(deviceEntryParentViewAlpha).isEqualTo(1f) + } @Test - fun deviceEntryBackgroundViewAlpha_udfpsEnrolled_show() = runTest { - fingerprintPropertyRepository.supportsUdfps() - val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + fun deviceEntryBackgroundViewAlpha_udfpsEnrolled_show() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) - // immediately 1f - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(bgViewAlpha).isEqualTo(1f) + // immediately 1f + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(bgViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(0.1f)) - assertThat(bgViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(0.1f)) + assertThat(bgViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(.3f)) - assertThat(bgViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(.3f)) + assertThat(bgViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(.5f)) - assertThat(bgViewAlpha).isEqualTo(1f) + keyguardTransitionRepository.sendTransitionStep(step(.5f)) + assertThat(bgViewAlpha).isEqualTo(1f) - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(bgViewAlpha).isEqualTo(1f) - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(bgViewAlpha).isEqualTo(1f) + } @Test - fun deviceEntryBackgroundViewAlpha_rearFpEnrolled_noUpdates() = runTest { - fingerprintPropertyRepository.supportsRearFps() - val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) - repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertThat(bgViewAlpha).isNull() + fun deviceEntryBackgroundViewAlpha_rearFpEnrolled_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsRearFps() + val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) + assertThat(bgViewAlpha).isNull() - repository.sendTransitionStep(step(0.5f)) - assertThat(bgViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(0.5f)) + assertThat(bgViewAlpha).isNull() - repository.sendTransitionStep(step(.75f)) - assertThat(bgViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(.75f)) + assertThat(bgViewAlpha).isNull() - repository.sendTransitionStep(step(1f)) - assertThat(bgViewAlpha).isNull() + keyguardTransitionRepository.sendTransitionStep(step(1f)) + assertThat(bgViewAlpha).isNull() - repository.sendTransitionStep(step(1f, TransitionState.FINISHED)) - assertThat(bgViewAlpha).isNull() - } + keyguardTransitionRepository.sendTransitionStep(step(1f, TransitionState.FINISHED)) + assertThat(bgViewAlpha).isNull() + } private fun step( value: Float, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt new file mode 100644 index 000000000000..02d40da1c124 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt @@ -0,0 +1,130 @@ +/* + * 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.qs.tiles.base.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingManagerFake +import com.android.systemui.common.shared.model.ContentDescription +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics +import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor +import com.android.systemui.qs.tiles.base.interactor.FakeQSTileDataInteractor +import com.android.systemui.qs.tiles.base.interactor.FakeQSTileUserActionInteractor +import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper +import com.android.systemui.qs.tiles.base.logging.QSTileLogger +import com.android.systemui.qs.tiles.viewmodel.QSTileConfig +import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder +import com.android.systemui.qs.tiles.viewmodel.QSTilePolicy +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.user.data.repository.FakeUserRepository +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import java.io.PrintWriter +import java.io.StringWriter +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +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 + +@SmallTest +@RunWith(AndroidJUnit4::class) +@OptIn(ExperimentalCoroutinesApi::class) +class QSTileViewModelImplTest : SysuiTestCase() { + + @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() + + @Mock private lateinit var qsTileLogger: QSTileLogger + @Mock private lateinit var qsTileAnalytics: QSTileAnalytics + + private val userRepository = FakeUserRepository() + private val tileDataInteractor = FakeQSTileDataInteractor<Any>() + private val tileUserActionInteractor = FakeQSTileUserActionInteractor<Any>() + private val disabledByPolicyInteractor = FakeDisabledByPolicyInteractor() + private val falsingManager = FalsingManagerFake() + + private val testCoroutineDispatcher = StandardTestDispatcher() + private val testScope = TestScope(testCoroutineDispatcher) + + private lateinit var underTest: QSTileViewModelImpl<Any> + + @Before + fun setup() { + underTest = + QSTileViewModelImpl( + QSTileConfigTestBuilder.build { + policy = QSTilePolicy.Restricted("test_restriction") + }, + { tileUserActionInteractor }, + { tileDataInteractor }, + { + object : QSTileDataToStateMapper<Any> { + override fun map(config: QSTileConfig, data: Any): QSTileState = + QSTileState.build( + { Icon.Resource(0, ContentDescription.Resource(0)) }, + data.toString() + ) {} + } + }, + disabledByPolicyInteractor, + userRepository, + falsingManager, + qsTileAnalytics, + qsTileLogger, + FakeSystemClock(), + testCoroutineDispatcher, + testScope.backgroundScope, + ) + } + + @Test + fun dumpWritesState() = + testScope.runTest { + tileDataInteractor.emitData("test_data") + underTest.state.launchIn(backgroundScope) + runCurrent() + + val sw = StringWriter() + PrintWriter(sw).use { underTest.dump(it, emptyArray()) } + + assertThat(sw.buffer.toString()) + .isEqualTo( + "test_spec:\n" + + " QSTileState(" + + "icon=() -> com.android.systemui.common.shared.model.Icon, " + + "label=test_data, " + + "activationState=INACTIVE, " + + "secondaryLabel=null, " + + "supportedActions=[CLICK], " + + "contentDescription=null, " + + "stateDescription=null, " + + "sideViewIcon=None, " + + "enabledState=ENABLED, " + + "expandedAccessibilityClassName=android.widget.Switch)\n" + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java index 1b4ba6433ded..cb90cc53f0f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java @@ -328,7 +328,7 @@ public class RecordingControllerTest extends SysuiTestCase { } @Override - public SystemUIDialog create(DialogDelegate<SystemUIDialog> delegate) { + public SystemUIDialog create(SystemUIDialog.Delegate delegate) { SystemUIDialog dialog = super.create(delegate); mLastDelegate = delegate; mLastCreatedDialog = dialog; diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt index c848287aa53e..8f696e7f11ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt @@ -89,8 +89,9 @@ class ScreenRecordPermissionDialogDelegateTest : SysuiTestCase() { userContextProvider, onStartRecordingClicked, mediaProjectionMetricsLogger, + systemUIDialogFactory ) - dialog = systemUIDialogFactory.create(delegate) + dialog = delegate.createDialog() delegate.onCreate(dialog, savedInstanceState = null) whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true) } 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 03878b7bcf45..b0b29e500fe4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -96,6 +96,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewConfigurator; import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor; +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory; @@ -343,6 +344,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { protected final int mMaxUdfpsBurnInOffsetY = 5; protected FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic(); protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor; + protected KeyguardClockInteractor mKeyguardClockInteractor; protected FakeKeyguardRepository mFakeKeyguardRepository; protected KeyguardInteractor mKeyguardInteractor; protected SceneTestUtils mUtils = new SceneTestUtils(this); @@ -527,7 +529,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { .thenReturn(emptyFlow()); when(mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha()) .thenReturn(emptyFlow()); - when(mOccludedToLockscreenTransitionViewModel.lockscreenTranslationY(anyInt())) + when(mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY()) .thenReturn(emptyFlow()); // Lockscreen->Dreaming @@ -565,7 +567,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { .thenReturn(emptyFlow()); when(mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha()) .thenReturn(emptyFlow()); - when(mLockscreenToOccludedTransitionViewModel.lockscreenTranslationY(anyInt())) + when(mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY()) .thenReturn(emptyFlow()); // Primary Bouncer->Gone @@ -696,6 +698,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { systemClock, mKeyguardBottomAreaViewModel, mKeyguardBottomAreaInteractor, + mKeyguardClockInteractor, mAlternateBouncerInteractor, mDreamingToLockscreenTransitionViewModel, mOccludedToLockscreenTransitionViewModel, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index 36b4435e2137..28fe8e4e8d3a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -362,6 +362,28 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test + public void onInterceptTouchEvent_nsslMigrationOff_userActivity() { + mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL); + + mTouchHandler.onInterceptTouchEvent(MotionEvent.obtain(0L /* downTime */, + 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, + 0 /* metaState */)); + + verify(mCentralSurfaces).userActivity(); + } + + @Test + public void onInterceptTouchEvent_nsslMigrationOn_userActivity_not_called() { + mSetFlagsRule.enableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL); + + mTouchHandler.onInterceptTouchEvent(MotionEvent.obtain(0L /* downTime */, + 0L /* eventTime */, MotionEvent.ACTION_DOWN, 0f /* x */, 0f /* y */, + 0 /* metaState */)); + + verify(mCentralSurfaces, times(0)).userActivity(); + } + + @Test public void testOnTouchEvent_expansionResumesAfterBriefTouch() { mFalsingManager.setIsClassifierEnabled(true); mFalsingManager.setIsFalseTouch(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 39b306b781f9..39739e7bb93d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -53,6 +53,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlagsClassic; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -190,7 +191,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { powerInteractor, sceneContainerFlags, new FakeKeyguardBouncerRepository(), - configurationRepository, + new ConfigurationInteractor(configurationRepository), shadeRepository, () -> sceneInteractor); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 0587633b09cf..6ff79660efec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -98,7 +98,6 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat -import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.TestScope @@ -113,8 +112,9 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import java.util.Optional +import org.mockito.Mockito.`when` as whenever @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -446,6 +446,26 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { } @Test + fun handleDispatchTouchEvent_nsslMigrationOff_userActivity_not_called() { + mSetFlagsRule.disableFlags(Flags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL) + underTest.setStatusBarViewController(phoneStatusBarViewController) + + interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT) + + verify(centralSurfaces, times(0)).userActivity() + } + + @Test + fun handleDispatchTouchEvent_nsslMigrationOn_userActivity() { + mSetFlagsRule.enableFlags(Flags.FLAG_KEYGUARD_SHADE_MIGRATION_NSSL) + underTest.setStatusBarViewController(phoneStatusBarViewController) + + interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT) + + verify(centralSurfaces).userActivity() + } + + @Test fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() { // down event should be intercepted by keyguardViewManager whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java index 62c0ebeb8c07..e723d7d0367b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java @@ -40,6 +40,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlagsClassic; import com.android.systemui.flags.FeatureFlags; @@ -228,7 +229,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { powerInteractor, sceneContainerFlags, new FakeKeyguardBouncerRepository(), - configurationRepository, + new ConfigurationInteractor(configurationRepository), mShadeRepository, () -> sceneInteractor); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt index 5f8777ddcbb6..f8aa359b569d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt @@ -225,4 +225,13 @@ class ShadeRepositoryImplTest : SysuiTestCase() { underTest.setLegacyQsFullscreen(true) assertThat(underTest.legacyQsFullscreen.value).isEqualTo(true) } + + @Test + fun updateLegacyIsClosing() = + testScope.runTest { + assertThat(underTest.legacyIsClosing.value).isEqualTo(false) + + underTest.setLegacyIsClosing(true) + assertThat(underTest.legacyIsClosing.value).isEqualTo(true) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt new file mode 100644 index 000000000000..40006ba8dd82 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt @@ -0,0 +1,149 @@ +/* + * 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.shade.domain.interactor + +import androidx.test.filters.SmallTest +import com.android.systemui.SysUITestComponent +import com.android.systemui.SysUITestModule +import com.android.systemui.SysuiTestCase +import com.android.systemui.TestMocksModule +import com.android.systemui.collectLastValue +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FakeFeatureFlagsClassicModule +import com.android.systemui.flags.Flags +import com.android.systemui.runCurrent +import com.android.systemui.runTest +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.ObservableTransitionState +import com.android.systemui.scene.shared.model.SceneKey +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.user.domain.UserDomainLayerModule +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth +import dagger.BindsInstance +import dagger.Component +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf +import org.junit.Test + +@SmallTest +class ShadeAnimationInteractorSceneContainerImplTest : SysuiTestCase() { + + @SysUISingleton + @Component( + modules = + [ + SysUITestModule::class, + UserDomainLayerModule::class, + ] + ) + interface TestComponent : SysUITestComponent<ShadeAnimationInteractorSceneContainerImpl> { + val sceneInteractor: SceneInteractor + + @Component.Factory + interface Factory { + fun create( + @BindsInstance test: SysuiTestCase, + featureFlags: FakeFeatureFlagsClassicModule, + mocks: TestMocksModule, + ): TestComponent + } + } + + private val dozeParameters: DozeParameters = mock() + + private val testComponent: TestComponent = + DaggerShadeAnimationInteractorSceneContainerImplTest_TestComponent.factory() + .create( + test = this, + featureFlags = + FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) }, + mocks = + TestMocksModule( + dozeParameters = dozeParameters, + ), + ) + + @Test + fun isAnyCloseAnimationRunning_qsToShade() = + testComponent.runTest() { + val actual by collectLastValue(underTest.isAnyCloseAnimationRunning) + + // WHEN transitioning from QS to Shade + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.QuickSettings, + toScene = SceneKey.Shade, + progress = MutableStateFlow(.1f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + sceneInteractor.setTransitionState(transitionState) + runCurrent() + + // THEN qs is animating closed + Truth.assertThat(actual).isFalse() + } + + @Test + fun isAnyCloseAnimationRunning_qsToGone_userInputNotOngoing() = + testComponent.runTest() { + val actual by collectLastValue(underTest.isAnyCloseAnimationRunning) + + // WHEN transitioning from QS to Gone with no ongoing user input + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.QuickSettings, + toScene = SceneKey.Gone, + progress = MutableStateFlow(.1f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + sceneInteractor.setTransitionState(transitionState) + runCurrent() + + // THEN qs is animating closed + Truth.assertThat(actual).isTrue() + } + + @Test + fun isAnyCloseAnimationRunning_qsToGone_userInputOngoing() = + testComponent.runTest() { + val actual by collectLastValue(underTest.isAnyCloseAnimationRunning) + + // WHEN transitioning from QS to Gone with user input ongoing + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.QuickSettings, + toScene = SceneKey.Gone, + progress = MutableStateFlow(.1f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(true), + ) + ) + sceneInteractor.setTransitionState(transitionState) + runCurrent() + + // THEN qs is not animating closed + Truth.assertThat(actual).isFalse() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt index 565e20a034db..310b86f908c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt @@ -127,22 +127,22 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { val actual by collectLastValue(underTest.qsExpansion) // WHEN split shade is enabled and QS is expanded - keyguardRepository.setStatusBarState(StatusBarState.SHADE) overrideResource(R.bool.config_use_split_notification_shade, true) configurationRepository.onAnyConfigurationChange() - val progress = MutableStateFlow(.3f) + runCurrent() val transitionState = MutableStateFlow<ObservableTransitionState>( ObservableTransitionState.Transition( fromScene = SceneKey.QuickSettings, toScene = SceneKey.Shade, - progress = progress, + progress = MutableStateFlow(.3f), isInitiatedByUserInput = false, isUserInputOngoing = flowOf(false), ) ) sceneInteractor.setTransitionState(transitionState) runCurrent() + keyguardRepository.setStatusBarState(StatusBarState.SHADE) // THEN legacy shade expansion is passed through Truth.assertThat(actual).isEqualTo(.3f) @@ -157,6 +157,8 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { // WHEN split shade is not enabled and QS is expanded keyguardRepository.setStatusBarState(StatusBarState.SHADE) overrideResource(R.bool.config_use_split_notification_shade, false) + configurationRepository.onAnyConfigurationChange() + runCurrent() val progress = MutableStateFlow(.3f) val transitionState = MutableStateFlow<ObservableTransitionState>( @@ -182,13 +184,12 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { // WHEN scene transition active keyguardRepository.setStatusBarState(StatusBarState.SHADE) - val progress = MutableStateFlow(.3f) val transitionState = MutableStateFlow<ObservableTransitionState>( ObservableTransitionState.Transition( fromScene = SceneKey.QuickSettings, toScene = SceneKey.Shade, - progress = progress, + progress = MutableStateFlow(.3f), isInitiatedByUserInput = false, isUserInputOngoing = flowOf(false), ) @@ -347,6 +348,52 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { Truth.assertThat(expansionAmount).isEqualTo(0f) } + fun isQsBypassingShade_goneToQs() = + testComponent.runTest() { + val actual by collectLastValue(underTest.isQsBypassingShade) + + // WHEN transitioning from QS directly to Gone + configurationRepository.onAnyConfigurationChange() + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.Gone, + toScene = SceneKey.QuickSettings, + progress = MutableStateFlow(.1f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + sceneInteractor.setTransitionState(transitionState) + runCurrent() + + // THEN qs is bypassing shade + Truth.assertThat(actual).isTrue() + } + + fun isQsBypassingShade_shadeToQs() = + testComponent.runTest() { + val actual by collectLastValue(underTest.isQsBypassingShade) + + // WHEN transitioning from QS to Shade + configurationRepository.onAnyConfigurationChange() + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Transition( + fromScene = SceneKey.Shade, + toScene = SceneKey.QuickSettings, + progress = MutableStateFlow(.1f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + sceneInteractor.setTransitionState(transitionState) + runCurrent() + + // THEN qs is not bypassing shade + Truth.assertThat(actual).isFalse() + } + @Test fun lockscreenShadeExpansion_transitioning_toAndFromDifferentScenes() = testComponent.runTest() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index ae659f4d2676..186ae6b0c4f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -24,11 +24,11 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags.TRANSIT_CLOCK -import com.android.systemui.plugins.ClockController -import com.android.systemui.plugins.ClockId -import com.android.systemui.plugins.ClockMetadata -import com.android.systemui.plugins.ClockProviderPlugin -import com.android.systemui.plugins.ClockSettings +import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.plugins.clocks.ClockId +import com.android.systemui.plugins.clocks.ClockMetadata +import com.android.systemui.plugins.clocks.ClockProviderPlugin +import com.android.systemui.plugins.clocks.ClockSettings import com.android.systemui.plugins.PluginLifecycleManager import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginManager diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt index bd3dae4f5fae..fef262f50306 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt @@ -24,9 +24,9 @@ import android.util.TypedValue import android.view.LayoutInflater import android.widget.FrameLayout import androidx.test.filters.SmallTest -import com.android.systemui.customization.R import com.android.systemui.SysuiTestCase -import com.android.systemui.plugins.ClockSettings +import com.android.systemui.customization.R +import com.android.systemui.plugins.clocks.ClockSettings import com.android.systemui.shared.clocks.DefaultClockController.Companion.DOZE_COLOR import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index 7546dfa1cbf9..dff91ddf559f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -26,6 +26,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.FakeCommandQueue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -121,7 +122,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { powerInteractor, sceneContainerFlags, FakeKeyguardBouncerRepository(), - configurationRepository, + ConfigurationInteractor(configurationRepository), shadeRepository, utils::sceneInteractor ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt index 8440e00a89f7..a5f3f57f5be6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt @@ -44,7 +44,7 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView import com.android.systemui.plugins.FalsingManager -import com.android.systemui.plugins.WeatherData +import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener import com.android.systemui.settings.UserTracker diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java index e488f39bf27d..bd4647431ab9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java @@ -34,12 +34,14 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.keyguard.TestScopeProvider; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeStateEvents; import com.android.systemui.shade.ShadeStateEvents.ShadeStateEventsListener; +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor; import com.android.systemui.statusbar.notification.VisibilityLocationProvider; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder; @@ -51,6 +53,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; @@ -62,6 +65,10 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.verification.VerificationMode; +import kotlinx.coroutines.flow.MutableStateFlow; +import kotlinx.coroutines.flow.StateFlowKt; +import kotlinx.coroutines.test.TestScope; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -78,6 +85,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { @Mock private ShadeStateEvents mShadeStateEvents; @Mock private VisibilityLocationProvider mVisibilityLocationProvider; @Mock private VisualStabilityProvider mVisualStabilityProvider; + @Mock private ShadeAnimationInteractor mShadeAnimationInteractor; @Captor private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessObserverCaptor; @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mSBStateListenerCaptor; @@ -86,6 +94,9 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { private FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock); + private final TestScope mTestScope = TestScopeProvider.getTestScope(); + private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope()); + private final MutableStateFlow<Boolean> mShadeClosing = StateFlowKt.MutableStateFlow(false); private WakefulnessLifecycle.Observer mWakefulnessObserver; private StatusBarStateController.StateListener mStatusBarStateListener; @@ -103,11 +114,13 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { mDumpManager, mHeadsUpManager, mShadeStateEvents, + mShadeAnimationInteractor, + mJavaAdapter, mStatusBarStateController, mVisibilityLocationProvider, mVisualStabilityProvider, mWakefulnessLifecycle); - + when(mShadeAnimationInteractor.isAnyCloseAnimationRunning()).thenReturn(mShadeClosing); mCoordinator.attach(mNotifPipeline); // capture arguments: @@ -549,7 +562,8 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase { } private void setPanelCollapsing(boolean collapsing) { - mNotifPanelEventsCallback.onPanelCollapsingChanged(collapsing); + mShadeClosing.setValue(collapsing); + mTestScope.getTestScheduler().runCurrent(); } private void setPulsing(boolean pulsing) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt index 741564505b53..349a35ebf798 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt @@ -285,28 +285,13 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() { assertThat(iconColors.tint).isEqualTo(0xAABBCC) - val staticDrawableColor = iconColors.staticDrawableColor(Rect(), isColorized = true) + val staticDrawableColor = iconColors.staticDrawableColor(Rect()) assertThat(staticDrawableColor).isEqualTo(0xAABBCC) } @Test - fun iconColors_staticDrawableColor_nonColorized() = - testComponent.runTest { - darkIconRepository.darkState.value = - SysuiDarkIconDispatcher.DarkChange( - emptyList(), - 0f, - 0xAABBCC, - ) - val iconColorsLookup by collectLastValue(underTest.iconColors) - val iconColors = iconColorsLookup?.iconColors(Rect()) - val staticDrawableColor = iconColors?.staticDrawableColor(Rect(), isColorized = false) - assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT) - } - - @Test - fun iconColors_staticDrawableColor_isColorized_notInDarkTintArea() = + fun iconColors_staticDrawableColor_notInDarkTintArea() = testComponent.runTest { darkIconRepository.darkState.value = SysuiDarkIconDispatcher.DarkChange( @@ -316,8 +301,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() { ) val iconColorsLookup by collectLastValue(underTest.iconColors) val iconColors = iconColorsLookup?.iconColors(Rect(1, 1, 4, 4)) - val staticDrawableColor = - iconColors?.staticDrawableColor(Rect(6, 6, 7, 7), isColorized = true) + val staticDrawableColor = iconColors?.staticDrawableColor(Rect(6, 6, 7, 7)) assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index 62a2bc54af20..5102b4f7a817 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -55,6 +55,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; import com.android.systemui.flags.FakeFeatureFlagsClassic; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; @@ -167,7 +168,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { PowerInteractorFactory.create().getPowerInteractor(), mSceneTestUtils.getSceneContainerFlags(), new FakeKeyguardBouncerRepository(), - new FakeConfigurationRepository(), + new ConfigurationInteractor(new FakeConfigurationRepository()), new FakeShadeRepository(), () -> mSceneTestUtils.sceneInteractor()); mViewModel = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt index 59bf9f30a828..9419d638b1c7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt @@ -20,6 +20,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -56,7 +57,7 @@ class KeyguardStatusBarViewModelTest : SysuiTestCase() { PowerInteractorFactory.create().powerInteractor, sceneTestUtils.sceneContainerFlags, FakeKeyguardBouncerRepository(), - FakeConfigurationRepository(), + ConfigurationInteractor(FakeConfigurationRepository()), FakeShadeRepository(), ) { sceneTestUtils.sceneInteractor() diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 52c25f7b2b71..8585d46fa8a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -96,6 +96,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FakeFeatureFlagsClassic; @@ -415,7 +416,7 @@ public class BubblesTest extends SysuiTestCase { powerInteractor, sceneContainerFlags, new FakeKeyguardBouncerRepository(), - configurationRepository, + new ConfigurationInteractor(configurationRepository), shadeRepository, () -> sceneInteractor); diff --git a/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/BiometricUnlockLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/BiometricUnlockLoggerKosmos.kt new file mode 100644 index 000000000000..f55ae2fd9466 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/BiometricUnlockLoggerKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.keyguard.logging + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.biometricUnlockLogger by Kosmos.Fixture { mock<BiometricUnlockLogger>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/KeyguardTransitionAnimationLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/KeyguardTransitionAnimationLoggerKosmos.kt new file mode 100644 index 000000000000..db2a87ebafbc --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/keyguard/logging/KeyguardTransitionAnimationLoggerKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.keyguard.logging + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.keyguardTransitionAnimationLogger by + Kosmos.Fixture { mock<KeyguardTransitionAnimationLogger>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt new file mode 100644 index 000000000000..54756590ee83 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * 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.biometrics.ui.viewmodel + +import com.android.systemui.keyguard.ui.viewmodel.deviceEntryIconViewModel +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.statusbar.phone.systemUIDialogManager + +val Kosmos.deviceEntryUdfpsTouchOverlayViewModel by Fixture { + DeviceEntryUdfpsTouchOverlayViewModel( + deviceEntryIconViewModel = deviceEntryIconViewModel, + systemUIDialogManager = systemUIDialogManager, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt new file mode 100644 index 000000000000..06b6cda62806 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.bouncer.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.primaryBouncerInteractor by Kosmos.Fixture { mock<PrimaryBouncerInteractor>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractorKosmos.kt new file mode 100644 index 000000000000..7e0e5f39c708 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.common.ui.domain.interactor + +import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.kosmos.Kosmos + +var Kosmos.configurationInteractor: ConfigurationInteractor by + Kosmos.Fixture { ConfigurationInteractor(configurationRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/DeviceEntryHapticsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/DeviceEntryHapticsRepositoryKosmos.kt new file mode 100644 index 000000000000..8bb07d9487cd --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/DeviceEntryHapticsRepositoryKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.deviceentry.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.deviceEntryHapticsRepository: DeviceEntryHapticsRepository by + Kosmos.Fixture { fakeDeviceEntryHapticsRepository } +val Kosmos.fakeDeviceEntryHapticsRepository by Kosmos.Fixture { FakeDeviceEntryHapticsRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt new file mode 100644 index 000000000000..de6cacb00faa --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt @@ -0,0 +1,42 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.deviceentry.domain.interactor + +import com.android.keyguard.logging.biometricUnlockLogger +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryHapticsRepository +import com.android.systemui.keyevent.domain.interactor.keyEventInteractor +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.util.time.fakeSystemClock +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.deviceEntryHapticsInteractor by + Kosmos.Fixture { + DeviceEntryHapticsInteractor( + repository = fakeDeviceEntryHapticsRepository, + fingerprintPropertyRepository = fingerprintPropertyRepository, + biometricSettingsRepository = biometricSettingsRepository, + keyEventInteractor = keyEventInteractor, + powerInteractor = powerInteractor, + systemClock = fakeSystemClock, + logger = biometricUnlockLogger, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryKosmos.kt new file mode 100644 index 000000000000..1238a7a0021e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/data/repository/KeyEventRepositoryKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.keyevent.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.keyEventRepository: KeyEventRepository by Kosmos.Fixture { fakeKeyEventRepository } +val Kosmos.fakeKeyEventRepository by Kosmos.Fixture { FakeKeyEventRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorKosmos.kt new file mode 100644 index 000000000000..53a1b034e4ed --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/domain/interactor/KeyEventInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.keyevent.domain.interactor + +import com.android.systemui.keyevent.data.repository.keyEventRepository +import com.android.systemui.kosmos.Kosmos + +var Kosmos.keyEventInteractor by + Kosmos.Fixture { KeyEventInteractor(repository = keyEventRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt index 6838e7676a23..abbd9be66b17 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.data import com.android.systemui.keyguard.data.repository.FakeCommandQueueModule +import com.android.systemui.keyguard.data.repository.FakeKeyguardClockRepositoryModule import com.android.systemui.keyguard.data.repository.FakeKeyguardRepositoryModule import com.android.systemui.keyguard.data.repository.FakeKeyguardSurfaceBehindRepositoryModule import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepositoryModule @@ -28,6 +29,7 @@ import dagger.Module FakeKeyguardRepositoryModule::class, FakeKeyguardTransitionRepositoryModule::class, FakeKeyguardSurfaceBehindRepositoryModule::class, + FakeKeyguardClockRepositoryModule::class, ] ) object FakeKeyguardDataLayerModule diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt new file mode 100644 index 000000000000..85a233fd3af1 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt @@ -0,0 +1,56 @@ +/* + * 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.data.repository + +import com.android.keyguard.ClockEventController +import com.android.keyguard.KeyguardClockSwitch.ClockSize +import com.android.keyguard.KeyguardClockSwitch.LARGE +import com.android.systemui.keyguard.shared.model.SettingsClockSize +import com.android.systemui.plugins.clocks.ClockId +import com.android.systemui.shared.clocks.DEFAULT_CLOCK_ID +import com.android.systemui.util.mockito.mock +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +class FakeKeyguardClockRepository @Inject constructor() : KeyguardClockRepository { + private val _clockSize = MutableStateFlow(LARGE) + override val clockSize: StateFlow<Int> = _clockSize + + private val _selectedClockSize = MutableStateFlow(SettingsClockSize.DYNAMIC) + override val selectedClockSize = _selectedClockSize + + private val _currentClockId = MutableStateFlow(DEFAULT_CLOCK_ID) + override val currentClockId: Flow<ClockId> = _currentClockId + + private val _currentClock = MutableStateFlow(null) + override val currentClock = _currentClock + override val clockEventController: ClockEventController + get() = mock() + + override fun setClockSize(@ClockSize size: Int) { + _clockSize.value = size + } +} + +@Module +interface FakeKeyguardClockRepositoryModule { + @Binds fun bindFake(fake: FakeKeyguardClockRepository): KeyguardClockRepository +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt index 4068e408f0bd..81a7bec52bb5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.data.repository import android.graphics.Point -import com.android.keyguard.KeyguardClockSwitch.LARGE import com.android.systemui.common.shared.model.Position import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.BiometricUnlockModel @@ -26,7 +25,6 @@ import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DismissAction import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.KeyguardDone -import com.android.systemui.keyguard.shared.model.KeyguardRootViewVisibilityState import com.android.systemui.keyguard.shared.model.StatusBarState import dagger.Binds import dagger.Module @@ -42,8 +40,6 @@ import kotlinx.coroutines.flow.asStateFlow class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { private val _deferKeyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow() override val keyguardDone: Flow<KeyguardDone> = _deferKeyguardDone - private val _clockSize = MutableStateFlow<Int>(LARGE) - override val clockSize: Flow<Int> = _clockSize private val _clockShouldBeCentered = MutableStateFlow<Boolean>(true) override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered @@ -123,17 +119,6 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { private val _keyguardAlpha = MutableStateFlow(1f) override val keyguardAlpha: StateFlow<Float> = _keyguardAlpha - private val _keyguardRootViewVisibility = - MutableStateFlow( - KeyguardRootViewVisibilityState( - 0, - goingToFullShade = false, - occlusionTransitionRunning = false - ) - ) - override val keyguardRootViewVisibility: Flow<KeyguardRootViewVisibilityState> = - _keyguardRootViewVisibility.asStateFlow() - override fun setQuickSettingsVisible(isVisible: Boolean) { _isQuickSettingsVisible.value = isVisible } @@ -187,10 +172,6 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { _deferKeyguardDone.emit(timing) } - override fun setClockSize(size: Int) { - _clockSize.value = size - } - override fun setClockShouldBeCentered(shouldBeCentered: Boolean) { _clockShouldBeCentered.value = shouldBeCentered } @@ -254,19 +235,6 @@ class FakeKeyguardRepository @Inject constructor() : KeyguardRepository { override fun setKeyguardAlpha(alpha: Float) { _keyguardAlpha.value = alpha } - - override fun setKeyguardVisibility( - statusBarState: Int, - goingToFullShade: Boolean, - occlusionTransitionRunning: Boolean - ) { - _keyguardRootViewVisibility.value = - KeyguardRootViewVisibilityState( - statusBarState, - goingToFullShade, - occlusionTransitionRunning - ) - } } @Module diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryKosmos.kt new file mode 100644 index 000000000000..e6716ba32cda --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.keyguardClockRepository: KeyguardClockRepository by + Kosmos.Fixture { fakeKeyguardClockRepository } +val Kosmos.fakeKeyguardClockRepository by Kosmos.Fixture { FakeKeyguardClockRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt new file mode 100644 index 000000000000..d791e949f853 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.keyguardClockRepository +import com.android.systemui.kosmos.Kosmos + +val Kosmos.keyguardClockInteractor by + Kosmos.Fixture { KeyguardClockInteractor(keyguardClockRepository = keyguardClockRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt index c575bb3fe25d..0bba36b172c0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.keyguard.data.repository.FakeCommandQueue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -63,7 +64,7 @@ object KeyguardInteractorFactory { commandQueue = commandQueue, sceneContainerFlags = sceneContainerFlags, bouncerRepository = bouncerRepository, - configurationRepository = configurationRepository, + configurationInteractor = ConfigurationInteractor(configurationRepository), shadeRepository = shadeRepository, sceneInteractorProvider = { sceneInteractor }, powerInteractor = powerInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt index bb840362185f..58d99b5bcc12 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt @@ -17,7 +17,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository -import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.power.domain.interactor.powerInteractor @@ -34,7 +34,7 @@ val Kosmos.keyguardInteractor by powerInteractor = powerInteractor, sceneContainerFlags = sceneContainerFlags, bouncerRepository = keyguardBouncerRepository, - configurationRepository = configurationRepository, + configurationInteractor = configurationInteractor, shadeRepository = shadeRepository, sceneInteractorProvider = { sceneInteractor }, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt new file mode 100644 index 000000000000..8d6529a114b8 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt @@ -0,0 +1,32 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui + +import com.android.keyguard.logging.keyguardTransitionAnimationLogger +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.applicationCoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.keyguardTransitionAnimationFlow by Fixture { + KeyguardTransitionAnimationFlow( + scope = applicationCoroutineScope, + logger = keyguardTransitionAnimationLogger, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt new file mode 100644 index 000000000000..9f0466dda51e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt @@ -0,0 +1,34 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.alternateBouncerViewModel by Fixture { + AlternateBouncerViewModel( + statusBarKeyguardViewManager = statusBarKeyguardViewManager, + transitionInteractor = keyguardTransitionInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..44e542660971 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt @@ -0,0 +1,32 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.aodToGoneTransitionViewModel by Fixture { + AodToGoneTransitionViewModel( + interactor = keyguardTransitionInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt index a31ab3ee1fc4..b5a5f039200f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -28,5 +29,6 @@ val Kosmos.aodToLockscreenTransitionViewModel by Fixture { AodToLockscreenTransitionViewModel( interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..27ad0f0f01e3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt @@ -0,0 +1,32 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.aodToOccludedTransitionViewModel by Fixture { + AodToOccludedTransitionViewModel( + interactor = keyguardTransitionInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt new file mode 100644 index 000000000000..6ffcc9a03b05 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt @@ -0,0 +1,42 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.statusbar.sysuiStatusBarStateController +import com.android.systemui.util.mockito.mock +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.bouncerToGoneFlows by Fixture { + BouncerToGoneFlows( + interactor = keyguardTransitionInteractor, + statusBarStateController = sysuiStatusBarStateController, + primaryBouncerInteractor = primaryBouncerInteractor, + keyguardDismissActionInteractor = mock(), + featureFlags = featureFlagsClassic, + shadeInteractor = shadeInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt new file mode 100644 index 000000000000..299262b91027 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt @@ -0,0 +1,51 @@ +/* + * 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.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryHapticsInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.burnInInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.scene.shared.flag.sceneContainerFlags +import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager + +val Kosmos.deviceEntryIconViewModelTransitionsMock by Fixture { + mutableSetOf<DeviceEntryIconTransition>() +} + +val Kosmos.deviceEntryIconViewModel by Fixture { + DeviceEntryIconViewModel( + transitions = deviceEntryIconViewModelTransitionsMock, + burnInInteractor = burnInInteractor, + shadeInteractor = shadeInteractor, + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + transitionInteractor = keyguardTransitionInteractor, + keyguardInteractor = keyguardInteractor, + viewModel = aodToLockscreenTransitionViewModel, + shadeDependentFlows = shadeDependentFlows, + sceneContainerFlags = sceneContainerFlags, + keyguardViewController = { statusBarKeyguardViewManager }, + deviceEntryHapticsInteractor = deviceEntryHapticsInteractor, + deviceEntryInteractor = deviceEntryInteractor, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..8b5407cc7e17 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt @@ -0,0 +1,36 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.util.mockito.mock +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.dreamingToLockscreenTransitionViewModel by Fixture { + DreamingToLockscreenTransitionViewModel( + keyguardTransitionInteractor = keyguardTransitionInteractor, + fromDreamingTransitionInteractor = mock(), + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt index 5db95cf3ebc5..14e2cff6a7a5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -27,6 +28,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.goneToAodTransitionViewModel by Fixture { GoneToAodTransitionViewModel( interactor = keyguardTransitionInteractor, - deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..073b34bcf277 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt @@ -0,0 +1,32 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.goneToDreamingTransitionViewModel by Fixture { + GoneToDreamingTransitionViewModel( + interactor = keyguardTransitionInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt new file mode 100644 index 000000000000..d8786830f536 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * 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.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope + +val Kosmos.keyguardClockViewModel by + Kosmos.Fixture { + KeyguardClockViewModel( + keyguardInteractor = keyguardInteractor, + keyguardClockInteractor = keyguardClockInteractor, + applicationScope = applicationCoroutineScope, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 663b8450e690..13ee74738437 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -18,8 +18,9 @@ package com.android.systemui.keyguard.ui.viewmodel -import android.content.applicationContext +import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.keyguard.domain.interactor.burnInInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor @@ -32,7 +33,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.keyguardRootViewModel by Fixture { KeyguardRootViewModel( - context = applicationContext, + configurationInteractor = configurationInteractor, deviceEntryInteractor = deviceEntryInteractor, dozeParameters = dozeParameters, keyguardInteractor = keyguardInteractor, @@ -41,6 +42,9 @@ val Kosmos.keyguardRootViewModel by Fixture { burnInInteractor = burnInInteractor, goneToAodTransitionViewModel = goneToAodTransitionViewModel, aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, + occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, screenOffAnimationController = screenOffAnimationController, + keyguardClockViewModel = keyguardClockViewModel, + featureFlags = FakeFeatureFlagsClassic(), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..7865f71ead83 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt @@ -0,0 +1,35 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.lockscreenToAodTransitionViewModel by Fixture { + LockscreenToAodTransitionViewModel( + interactor = keyguardTransitionInteractor, + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + shadeDependentFlows = shadeDependentFlows, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..b9f4b71d24d6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.lockscreenToDreamingTransitionViewModel by Fixture { + LockscreenToDreamingTransitionViewModel( + interactor = keyguardTransitionInteractor, + shadeDependentFlows = shadeDependentFlows, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..475aa2de3f9b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt @@ -0,0 +1,32 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.lockscreenToGoneTransitionViewModel by Fixture { + LockscreenToGoneTransitionViewModel( + interactor = keyguardTransitionInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..8541a4fe7096 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt @@ -0,0 +1,35 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.lockscreenToOccludedTransitionViewModel by Fixture { + LockscreenToOccludedTransitionViewModel( + interactor = keyguardTransitionInteractor, + shadeDependentFlows = shadeDependentFlows, + configurationInteractor = configurationInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..65c47fc9c2c7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.lockscreenToPrimaryBouncerTransitionViewModel by Fixture { + LockscreenToPrimaryBouncerTransitionViewModel( + interactor = keyguardTransitionInteractor, + shadeDependentFlows = shadeDependentFlows, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..ddde5498d544 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt @@ -0,0 +1,34 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.occludedToAodTransitionViewModel by Fixture { + OccludedToAodTransitionViewModel( + interactor = keyguardTransitionInteractor, + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..5bbde2b1c419 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt @@ -0,0 +1,36 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.occludedToLockscreenTransitionViewModel by Fixture { + OccludedToLockscreenTransitionViewModel( + interactor = keyguardTransitionInteractor, + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + configurationInteractor = configurationInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..a7f29d637281 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt @@ -0,0 +1,34 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.primaryBouncerToAodTransitionViewModel by Fixture { + PrimaryBouncerToAodTransitionViewModel( + interactor = keyguardTransitionInteractor, + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..ace6ae3e3eec --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt @@ -0,0 +1,41 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.statusbar.sysuiStatusBarStateController +import com.android.systemui.util.mockito.mock +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture { + PrimaryBouncerToGoneTransitionViewModel( + interactor = keyguardTransitionInteractor, + statusBarStateController = sysuiStatusBarStateController, + primaryBouncerInteractor = primaryBouncerInteractor, + keyguardDismissActionInteractor = mock(), + featureFlags = featureFlagsClassic, + bouncerToGoneFlows = bouncerToGoneFlows, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..3bbabf713b91 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt @@ -0,0 +1,34 @@ +/* + * 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.primaryBouncerToLockscreenTransitionViewModel by Fixture { + PrimaryBouncerToLockscreenTransitionViewModel( + interactor = keyguardTransitionInteractor, + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/alarm/AlarmTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/alarm/AlarmTileKosmos.kt new file mode 100644 index 000000000000..2fa92c75b917 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/alarm/AlarmTileKosmos.kt @@ -0,0 +1,24 @@ +/* + * 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.qs.tiles.impl.alarm + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.qsEventLogger +import com.android.systemui.statusbar.policy.PolicyModule + +val Kosmos.qsAlarmTileConfig by + Kosmos.Fixture { PolicyModule.provideAlarmTileConfig(qsEventLogger) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt new file mode 100644 index 000000000000..9d0faca94fb4 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/QSTileStateSubject.kt @@ -0,0 +1,76 @@ +/* + * 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.qs.tiles.impl.custom + +import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject.Companion.assertThat +import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject.Companion.states +import com.android.systemui.qs.tiles.impl.custom.TileSubject.Companion.assertThat +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.google.common.truth.FailureMetadata +import com.google.common.truth.Subject +import com.google.common.truth.Subject.Factory +import com.google.common.truth.Truth + +/** + * [QSTileState]-specific extension for [Truth]. Use [assertThat] or [states] to get an instance of + * this subject. + */ +class QSTileStateSubject +private constructor(failureMetadata: FailureMetadata, subject: QSTileState?) : + Subject(failureMetadata, subject) { + + private val actual: QSTileState? = subject + + /** Asserts if the [QSTileState] fields are the same. */ + fun isEqualTo(other: QSTileState?) { + if (actual == null) { + check("other").that(other).isNull() + return + } else { + check("other").that(other).isNotNull() + other ?: return + } + check("icon").that(actual.icon()).isEqualTo(other.icon()) + check("label").that(actual.label).isEqualTo(other.label) + check("activationState").that(actual.activationState).isEqualTo(other.activationState) + check("secondaryLabel").that(actual.secondaryLabel).isEqualTo(other.secondaryLabel) + check("label").that(actual.supportedActions).isEqualTo(other.supportedActions) + check("contentDescription") + .that(actual.contentDescription) + .isEqualTo(other.contentDescription) + check("stateDescription").that(actual.stateDescription).isEqualTo(other.stateDescription) + check("sideViewIcon").that(actual.sideViewIcon).isEqualTo(other.sideViewIcon) + check("enabledState").that(actual.enabledState).isEqualTo(other.enabledState) + check("expandedAccessibilityClassName") + .that(actual.expandedAccessibilityClassName) + .isEqualTo(other.expandedAccessibilityClassName) + } + + companion object { + + /** Returns a factory to be used with [Truth.assertAbout]. */ + fun states(): Factory<QSTileStateSubject, QSTileState?> { + return Factory { failureMetadata: FailureMetadata, subject: QSTileState? -> + QSTileStateSubject(failureMetadata, subject) + } + } + + /** Shortcut for `Truth.assertAbout(states()).that(state)`. */ + fun assertThat(state: QSTileState?): QSTileStateSubject = + Truth.assertAbout(states()).that(state) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt index 3c96051a718f..d78bcb93b256 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt @@ -47,6 +47,7 @@ import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.classifier.domain.interactor.FalsingInteractor import com.android.systemui.common.shared.model.Text import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.communal.data.repository.FakeCommunalRepository import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory @@ -133,6 +134,9 @@ class SceneTestUtils( val configurationRepository: FakeConfigurationRepository by lazy { FakeConfigurationRepository() } + val configurationInteractor: ConfigurationInteractor by lazy { + ConfigurationInteractor(configurationRepository) + } private val emergencyServicesRepository: EmergencyServicesRepository by lazy { EmergencyServicesRepository( applicationScope = applicationScope(), @@ -246,7 +250,7 @@ class SceneTestUtils( commandQueue = FakeCommandQueue(), sceneContainerFlags = sceneContainerFlags, bouncerRepository = FakeKeyguardBouncerRepository(), - configurationRepository = configurationRepository, + configurationInteractor = configurationInteractor, shadeRepository = FakeShadeRepository(), sceneInteractorProvider = { sceneInteractor() }, powerInteractor = PowerInteractorFactory.create().powerInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt index 92ec4f22001b..9c108487e4c5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt @@ -24,6 +24,7 @@ import dagger.Module import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow /** Fake implementation of [ShadeRepository] */ @SysUISingleton @@ -105,6 +106,14 @@ class FakeShadeRepository @Inject constructor() : ShadeRepository { _legacyQsFullscreen.value = legacyQsFullscreen } + private val _legacyIsClosing = MutableStateFlow(false) + @Deprecated("Use ShadeInteractor instead") override val legacyIsClosing = _legacyIsClosing + + @Deprecated("Use ShadeInteractor instead") + override fun setLegacyIsClosing(isClosing: Boolean) { + _legacyIsClosing.value = isClosing + } + fun setShadeModel(model: ShadeModel) { _shadeModel.value = model } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SysuiStatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SysuiStatusBarStateControllerKosmos.kt new file mode 100644 index 000000000000..fead581d5434 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/SysuiStatusBarStateControllerKosmos.kt @@ -0,0 +1,21 @@ +/* + * 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.statusbar + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.sysuiStatusBarStateController by Kosmos.Fixture { FakeStatusBarStateController() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt index c17083c5fb1c..e2479fe45405 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.ui.viewmodel.occludedToLockscreenTransitionViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope @@ -31,5 +32,6 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture { keyguardInteractor = keyguardInteractor, keyguardTransitionInteractor = keyguardTransitionInteractor, shadeInteractor = shadeInteractor, + occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt new file mode 100644 index 000000000000..4e15ea2d9377 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.statusbar.phone + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.statusBarKeyguardViewManager by Kosmos.Fixture { mock<StatusBarKeyguardViewManager>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogManagerKosmos.kt new file mode 100644 index 000000000000..7dfbf2a38de6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogManagerKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.statusbar.phone + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.systemUIDialogManager by Kosmos.Fixture { mock<SystemUIDialogManager>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/FakeDarkIconRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/FakeDarkIconRepository.kt index 50d3f0a106f2..282e2e859afe 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/FakeDarkIconRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/FakeDarkIconRepository.kt @@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.MutableStateFlow @SysUISingleton class FakeDarkIconRepository @Inject constructor() : DarkIconRepository { - override val darkState = MutableStateFlow(DarkChange(emptyList(), 0f, 0)) + override val darkState = MutableStateFlow(DarkChange.EMPTY) } @Module diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java index 5ae8e22c06ee..377e97ca0f9a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeNextAlarmController.java @@ -14,15 +14,44 @@ package com.android.systemui.utils.leaks; +import android.app.AlarmManager; import android.testing.LeakCheck; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; +import java.util.ArrayList; +import java.util.List; + public class FakeNextAlarmController extends BaseLeakChecker<NextAlarmChangeCallback> implements NextAlarmController { + private AlarmManager.AlarmClockInfo mNextAlarm = null; + private List<NextAlarmChangeCallback> mCallbacks = new ArrayList<>(); + public FakeNextAlarmController(LeakCheck test) { super(test, "alarm"); } + + /** + * Helper method for setting the next alarm + */ + public void setNextAlarm(AlarmManager.AlarmClockInfo nextAlarm) { + this.mNextAlarm = nextAlarm; + for (var callback: mCallbacks) { + callback.onNextAlarmChanged(nextAlarm); + } + } + + @Override + public void addCallback(NextAlarmChangeCallback listener) { + mCallbacks.add(listener); + listener.onNextAlarmChanged(mNextAlarm); + } + + @Override + public void removeCallback(NextAlarmChangeCallback listener) { + mCallbacks.remove(listener); + } + } diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING index 72eb665bee65..031984829e77 100644 --- a/ravenwood/TEST_MAPPING +++ b/ravenwood/TEST_MAPPING @@ -1,7 +1,21 @@ { - "presubmit": [ - // Let's only run this one as a smoke test. - // TODO: Enable it once the infra knows how to run it. - // { "name": "CtsUtilTestCasesRavenwood" } - ] + "presubmit": [ + { + "name": "RavenwoodMockitoTest_device" + } + ], + "ravenwood-presubmit": [ + { + "name": "RavenwoodMinimumTest", + "host": true + }, + { + "name": "RavenwoodMockitoTest", + "host": true + }, + { + "name": "CtsUtilTestCasesRavenwood", + "host": true + } + ] } diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt index 96cfa4896808..6a6ae3876f6b 100644 --- a/ravenwood/framework-minus-apex-ravenwood-policies.txt +++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt @@ -85,18 +85,13 @@ class com.android.internal.util.FastMath stubclass class com.android.internal.util.FastPrintWriter stubclass class com.android.internal.util.GrowingArrayUtils stubclass class com.android.internal.util.LineBreakBufferedWriter stubclass +class com.android.internal.util.Parcelling stubclass class com.android.internal.util.Preconditions stubclass class com.android.internal.util.StringPool stubclass class com.android.internal.os.SomeArgs stubclass # Parcel -class android.os.Parcel stubclass - method writeException (Ljava/lang/Exception;)V @writeException$ravenwood - method writeNoException ()V @writeNoException$ravenwood -class android.os.Parcel !com.android.hoststubgen.nativesubstitution.Parcel_host - -class android.os.Parcelable stubclass class android.os.ParcelFormatException stubclass class android.os.BadParcelableException stubclass class android.os.BadTypeParcelableException stubclass diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java index be0c09ee4a25..eacdc2f79254 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java @@ -32,6 +32,8 @@ public class RavenwoodRuleImpl { android.os.Process.init$ravenwood(rule.mUid, rule.mPid); android.os.Binder.init$ravenwood(); + com.android.server.LocalServices.removeAllServicesForTest(); + if (rule.mProvideMainThread) { final HandlerThread main = new HandlerThread(MAIN_THREAD_NAME); main.start(); @@ -45,6 +47,8 @@ public class RavenwoodRuleImpl { Looper.clearMainLooperForTest(); } + com.android.server.LocalServices.removeAllServicesForTest(); + android.os.Process.reset$ravenwood(); android.os.Binder.reset$ravenwood(); } diff --git a/ravenwood/minimum-test/Android.bp b/ravenwood/minimum-test/Android.bp new file mode 100644 index 000000000000..bf3583cebd2c --- /dev/null +++ b/ravenwood/minimum-test/Android.bp @@ -0,0 +1,24 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +// Minimum ravenwood test according to test-authors.md. +android_ravenwood_test { + name: "RavenwoodMinimumTest", + + static_libs: [ + "androidx.annotation_annotation", + "androidx.test.rules", + ], + + srcs: [ + "test/**/*.java", + ], + sdk_version: "test_current", + auto_gen_config: true, +} diff --git a/ravenwood/minimum-test/test/com/android/ravenwood/RavenwoodMinimumTest.java b/ravenwood/minimum-test/test/com/android/ravenwood/RavenwoodMinimumTest.java new file mode 100644 index 000000000000..085c18622885 --- /dev/null +++ b/ravenwood/minimum-test/test/com/android/ravenwood/RavenwoodMinimumTest.java @@ -0,0 +1,45 @@ +/* + * 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.ravenwood; + +import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.ravenwood.RavenwoodRule; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class RavenwoodMinimumTest { + @Rule + public RavenwoodRule mRavenwood = new RavenwoodRule.Builder() + .setProcessApp() + .build(); + + @Test + public void testSimple() { + Assert.assertTrue(android.os.Process.isApplicationUid(android.os.Process.myUid())); + } + + @Test + @IgnoreUnderRavenwood + public void testIgnored() { + throw new RuntimeException("Shouldn't be executed under ravenwood"); + } +} diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt index eba6e0b90bb9..290293234b34 100644 --- a/ravenwood/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/ravenwood-annotation-allowed-classes.txt @@ -23,6 +23,8 @@ android.os.IBinder android.os.Looper android.os.Message android.os.MessageQueue +android.os.Parcel +android.os.Parcelable android.os.Process android.os.SystemClock android.os.ThreadLocalWorkSource @@ -64,3 +66,5 @@ android.graphics.Point android.graphics.PointF android.graphics.Rect android.graphics.RectF + +com.android.server.LocalServices diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md index 2b5bd9083a40..5adef534a2b2 100644 --- a/ravenwood/test-authors.md +++ b/ravenwood/test-authors.md @@ -31,6 +31,14 @@ android_ravenwood_test { * Write your unit test just like you would for an Android device: ``` +import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.ravenwood.RavenwoodRule; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + @RunWith(AndroidJUnit4.class) public class MyCodeTest { @Test @@ -43,6 +51,14 @@ public class MyCodeTest { * APIs available under Ravenwood are stateless by default. If your test requires explicit states (such as defining the UID you’re running under, or requiring a main `Looper` thread), add a `RavenwoodRule` to declare that: ``` +import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.ravenwood.RavenwoodRule; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + @RunWith(AndroidJUnit4.class) public class MyCodeTest { @Rule diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java index 2032a5021cd9..b4deeb0a6872 100644 --- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java +++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java @@ -29,12 +29,14 @@ import android.companion.virtual.VirtualDeviceManager; import android.content.ComponentName; import android.content.Context; import android.hardware.display.DisplayManager; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.ArraySet; import android.util.IntArray; +import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -66,8 +68,8 @@ import java.util.function.Consumer; * TODO(241117292): Remove or cut down during simultaneous user refactoring. */ public class ProxyManager { - private static final boolean DEBUG = false; private static final String LOG_TAG = "ProxyManager"; + private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG) && Build.IS_DEBUGGABLE; // Names used to populate ComponentName and ResolveInfo in connection.mA11yServiceInfo and in // the infos of connection.setInstalledAndEnabledServices diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java index e3797c98bebe..f55ecb05c55f 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java @@ -916,18 +916,27 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH && event.getPointerCount() == 2; mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE); - if (isActivated() && event.getPointerCount() == 2) { - storePointerDownLocation(mSecondPointerDownLocation, event); - mHandler.sendEmptyMessageDelayed(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE, - ViewConfiguration.getTapTimeout()); - } else if (mIsTwoFingerCountReached) { - // Placing two-finger triple-taps behind isActivated to avoid - // blocking panning scaling state + if (event.getPointerCount() == 2) { if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event)) { // 3tap and hold afterLongTapTimeoutTransitionToDraggingState(event); } else { - afterMultiTapTimeoutTransitionToDelegatingState(); + if (mDetectTwoFingerTripleTap) { + // If mDetectTwoFingerTripleTap, delay transition to the delegating + // state for mMultiTapMaxDelay to ensure reachability of + // multi finger multi tap + afterMultiTapTimeoutTransitionToDelegatingState(); + } + + if (isActivated()) { + // If activated, delay transition to the panning scaling + // state for tap timeout to ensure reachability of + // multi finger multi tap + storePointerDownLocation(mSecondPointerDownLocation, event); + mHandler.sendEmptyMessageDelayed( + MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE, + ViewConfiguration.getTapTimeout()); + } } } else { transitionToDelegatingStateAndClear(); @@ -953,6 +962,9 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH // (which is a rare combo to be used aside from magnification) if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) { transitionToViewportDraggingStateAndClear(event); + } else if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event) + && event.getPointerCount() == 2) { + transitionToViewportDraggingStateAndClear(event); } else if (isActivated() && event.getPointerCount() == 2) { if (mIsSinglePanningEnabled && overscrollState(event, mFirstPointerDownLocation) @@ -961,11 +973,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } //Primary pointer is swiping, so transit to PanningScalingState transitToPanningScalingStateAndClear(); - } else if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event) - && event.getPointerCount() == 2) { - // Placing two-finger triple-taps behind isActivated to avoid - // blocking panning scaling state - transitionToViewportDraggingStateAndClear(event); } else if (mIsSinglePanningEnabled && isActivated() && event.getPointerCount() == 1) { @@ -979,8 +986,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } } else if (isActivated() && pointerDownValid(mSecondPointerDownLocation) && distanceClosestPointerToPoint( - mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) { - //Second pointer is swiping, so transit to PanningScalingState + mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance + // If mCompleteTapCount is not zero, it means that it is a multi tap + // gesture. So, we should not transit to the PanningScalingState. + && mCompletedTapCount == 0) { + // Second pointer is swiping, so transit to PanningScalingState transitToPanningScalingStateAndClear(); } } @@ -988,6 +998,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH case ACTION_UP: { mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD); + mHandler.removeMessages(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE); if (!mFullScreenMagnificationController.magnificationRegionContains( mDisplayId, event.getX(), event.getY())) { diff --git a/services/core/Android.bp b/services/core/Android.bp index 3323d0ba64dd..659112e90203 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -136,7 +136,6 @@ java_library_static { "android.hardware.light-V2.0-java", "android.hardware.gnss-V2-java", "android.hardware.vibrator-V2-java", - "android.nfc.flags-aconfig-java", "app-compat-annotations", "framework-tethering.stubs.module_lib", "service-art.stubs.system_server", diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 898b69310fe1..31c9348c8127 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -45,7 +45,6 @@ import android.util.SparseArray; import com.android.internal.pm.pkg.component.ParsedMainComponent; import com.android.internal.util.function.pooled.PooledLambda; -import com.android.permission.persistence.RuntimePermissionsState; import com.android.server.pm.Installer.LegacyDexoptDisabledException; import com.android.server.pm.KnownPackages; import com.android.server.pm.PackageArchiver; @@ -1104,7 +1103,9 @@ public abstract class PackageManagerInternal { * Read legacy permission states for permissions migration to new permission subsystem. * Note that this api is supposed to be used for permissions state migration only. */ - public abstract RuntimePermissionsState getLegacyPermissionsState(@UserIdInt int userId); + // TODO: restore to com.android.permission.persistence.RuntimePermissionsState + // once Ravenwood includes Mainline stubs + public abstract Object getLegacyPermissionsState(@UserIdInt int userId); /** * @return permissions file version for the given user. diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index f2d9759a7cc9..f8f3d82556fa 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -886,9 +886,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL); } - synchronized (mStats) { - return mBatteryUsageStatsProvider.getBatteryUsageStats(mStats, queries); - } + return mBatteryUsageStatsProvider.getBatteryUsageStats(mStats, queries); } /** Register callbacks for statsd pulled atoms. */ @@ -2730,13 +2728,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub BatteryUsageStatsQuery query = builder.build(); synchronized (mStats) { mStats.prepareForDumpLocked(); - BatteryUsageStats batteryUsageStats = - mBatteryUsageStatsProvider.getBatteryUsageStats(mStats, query); - if (proto) { - batteryUsageStats.dumpToProto(fd); - } else { - batteryUsageStats.dump(pw, ""); - } + } + BatteryUsageStats batteryUsageStats = + mBatteryUsageStatsProvider.getBatteryUsageStats(mStats, query); + if (proto) { + batteryUsageStats.dumpToProto(fd); + } else { + batteryUsageStats.dump(pw, ""); } } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index b500ff1da28b..3e1edf2a4876 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -120,6 +120,7 @@ public class SettingsToPropertiesMapper { static final String[] sDeviceConfigAconfigScopes = new String[] { "accessibility", "android_core_networking", + "aoc", "app_widgets", "arc_next", "avic", @@ -179,6 +180,7 @@ public class SettingsToPropertiesMapper { "tv_system_ui", "vibrator", "virtual_devices", + "wallet_integration", "wear_calling_messaging", "wear_connectivity", "wear_esim_carriers", diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index a770b66b2506..2ed079ab0c62 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -29,3 +29,10 @@ flag { description: "Disable BOOT_COMPLETED broadcast FGS start for certain types" bug: "296558535" } + +flag { + name: "bfgs_managed_network_access" + namespace: "backstage_power" + description: "Restrict network access for certain applications in BFGS process state" + bug: "304347838" +} diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 344673793700..7780b3906b9f 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1180,6 +1180,8 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.pkgOps.put(packageName, new Ops(packageName, uidState)); } + + createSandboxUidStateIfNotExistsForAppLocked(uid); } } } @@ -1261,6 +1263,8 @@ public class AppOpsService extends IAppOpsService.Stub { ops.put(code, new Op(uidState, packageName, code, uid)); } } + + createSandboxUidStateIfNotExistsForAppLocked(uid); } /** @@ -4011,6 +4015,11 @@ public class AppOpsService extends IAppOpsService.Stub { return uidState; } + private void createSandboxUidStateIfNotExistsForAppLocked(int uid) { + final int sandboxUid = Process.toSdkSandboxUid(uid); + getUidStateLocked(sandboxUid, true); + } + private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) { synchronized (this) { getUidStateTracker().updateAppWidgetVisibility(uidPackageNames, visible); diff --git a/services/core/java/com/android/server/appop/AudioRestrictionManager.java b/services/core/java/com/android/server/appop/AudioRestrictionManager.java index be870373af63..b9ccc5389337 100644 --- a/services/core/java/com/android/server/appop/AudioRestrictionManager.java +++ b/services/core/java/com/android/server/appop/AudioRestrictionManager.java @@ -43,7 +43,7 @@ public class AudioRestrictionManager { static { SparseBooleanArray audioMutedUsages = new SparseBooleanArray(); SparseBooleanArray vibrationMutedUsages = new SparseBooleanArray(); - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.SDK_USAGES.toArray()) { final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage); if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION || suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL || diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index b1706ed61e36..2f7d99fcbc4b 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -1595,8 +1595,8 @@ public class AudioDeviceBroker { sendILMsg(MSG_IL_BTA2DP_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs); } - /*package*/ void setLeAudioTimeout(String address, int device, int delayMs) { - sendILMsg(MSG_IL_BTLEAUDIO_TIMEOUT, SENDMSG_QUEUE, device, address, delayMs); + /*package*/ void setLeAudioTimeout(String address, int device, int codec, int delayMs) { + sendIILMsg(MSG_IIL_BTLEAUDIO_TIMEOUT, SENDMSG_QUEUE, device, codec, address, delayMs); } /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) { @@ -1794,8 +1794,9 @@ public class AudioDeviceBroker { return; } @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = - mBtHelper.getA2dpCodecWithFallbackToSBC( - btInfo.mDevice, "MSG_L_SET_BT_ACTIVE_DEVICE"); + mBtHelper.getCodecWithFallback(btInfo.mDevice, + btInfo.mProfile, btInfo.mIsLeOutput, + "MSG_L_SET_BT_ACTIVE_DEVICE"); mDeviceInventory.onSetBtActiveDevice(btInfo, codec, (btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput) @@ -1819,22 +1820,24 @@ public class AudioDeviceBroker { case MSG_IL_BTA2DP_TIMEOUT: // msg.obj == address of BTA2DP device synchronized (mDeviceStateLock) { - mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1); + mDeviceInventory.onMakeA2dpDeviceUnavailableNow( + (String) msg.obj, msg.arg1); } break; - case MSG_IL_BTLEAUDIO_TIMEOUT: + case MSG_IIL_BTLEAUDIO_TIMEOUT: // msg.obj == address of LE Audio device synchronized (mDeviceStateLock) { mDeviceInventory.onMakeLeAudioDeviceUnavailableNow( - (String) msg.obj, msg.arg1); + (String) msg.obj, msg.arg1, msg.arg2); } break; case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: { final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; synchronized (mDeviceStateLock) { @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = - mBtHelper.getA2dpCodecWithFallbackToSBC( - btInfo.mDevice, "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE"); + mBtHelper.getCodecWithFallback(btInfo.mDevice, + btInfo.mProfile, btInfo.mIsLeOutput, + "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE"); mDeviceInventory.onBluetoothDeviceConfigChange( btInfo, codec, BtHelper.EVENT_DEVICE_CONFIG_CHANGE); } @@ -2084,7 +2087,7 @@ public class AudioDeviceBroker { private static final int MSG_IL_SAVE_NDEF_DEVICE_FOR_STRATEGY = 47; private static final int MSG_IL_SAVE_REMOVE_NDEF_DEVICE_FOR_STRATEGY = 48; - private static final int MSG_IL_BTLEAUDIO_TIMEOUT = 49; + private static final int MSG_IIL_BTLEAUDIO_TIMEOUT = 49; private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52; private static final int MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL = 53; @@ -2104,7 +2107,7 @@ public class AudioDeviceBroker { case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: case MSG_L_SET_BT_ACTIVE_DEVICE: case MSG_IL_BTA2DP_TIMEOUT: - case MSG_IL_BTLEAUDIO_TIMEOUT: + case MSG_IIL_BTLEAUDIO_TIMEOUT: case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: case MSG_TOGGLE_HDMI: case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: @@ -2196,7 +2199,7 @@ public class AudioDeviceBroker { case MSG_L_SET_BT_ACTIVE_DEVICE: case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: case MSG_IL_BTA2DP_TIMEOUT: - case MSG_IL_BTLEAUDIO_TIMEOUT: + case MSG_IIL_BTLEAUDIO_TIMEOUT: case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: if (sLastDeviceConnectMsgTime >= time) { // add a little delay to make sure messages are ordered as expected diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index e9b102bc67b8..e503f1f2c8c2 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -689,9 +689,11 @@ public class AudioDeviceInventory { case BluetoothProfile.LE_AUDIO: case BluetoothProfile.LE_AUDIO_BROADCAST: if (switchToUnavailable) { - makeLeAudioDeviceUnavailableNow(address, btInfo.mAudioSystemDevice); + makeLeAudioDeviceUnavailableNow(address, + btInfo.mAudioSystemDevice, di.mDeviceCodecFormat); } else if (switchToAvailable) { - makeLeAudioDeviceAvailable(btInfo, streamType, "onSetBtActiveDevice"); + makeLeAudioDeviceAvailable( + btInfo, streamType, codec, "onSetBtActiveDevice"); } break; default: throw new IllegalArgumentException("Invalid profile " @@ -752,12 +754,13 @@ public class AudioDeviceInventory { if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) { - boolean a2dpCodecChange = false; - if (btInfo.mProfile == BluetoothProfile.A2DP) { + boolean codecChange = false; + if (btInfo.mProfile == BluetoothProfile.A2DP + || btInfo.mProfile == BluetoothProfile.LE_AUDIO) { if (di.mDeviceCodecFormat != codec) { di.mDeviceCodecFormat = codec; mConnectedDevices.replace(key, di); - a2dpCodecChange = true; + codecChange = true; } final int res = mAudioSystem.handleDeviceConfigChange( btInfo.mAudioSystemDevice, address, BtHelper.getName(btDevice), codec); @@ -782,7 +785,7 @@ public class AudioDeviceInventory { } } - if (!a2dpCodecChange) { + if (!codecChange) { updateBluetoothPreferredModes_l(btDevice /*connectedDevice*/); } } @@ -796,9 +799,9 @@ public class AudioDeviceInventory { } } - /*package*/ void onMakeLeAudioDeviceUnavailableNow(String address, int device) { + /*package*/ void onMakeLeAudioDeviceUnavailableNow(String address, int device, int codec) { synchronized (mDevicesLock) { - makeLeAudioDeviceUnavailableNow(address, device); + makeLeAudioDeviceUnavailableNow(address, device, codec); } } @@ -1335,6 +1338,27 @@ public class AudioDeviceInventory { } } + private static boolean devicesListEqual(@NonNull List<AudioDeviceAttributes> list1, + @NonNull List<AudioDeviceAttributes> list2) { + if (list1.size() != list2.size()) { + return false; + } + // This assumes a given device is only present once in a list + for (AudioDeviceAttributes d1 : list1) { + boolean found = false; + for (AudioDeviceAttributes d2 : list2) { + if (d1.equalTypeAddress(d2)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } + private int setDevicesRole( ArrayMap<Pair<Integer, Integer>, List<AudioDeviceAttributes>> rolesMap, AudioSystemInterface addOp, @@ -1342,31 +1366,26 @@ public class AudioDeviceInventory { int useCase, int role, @NonNull List<AudioDeviceAttributes> devices) { synchronized (rolesMap) { Pair<Integer, Integer> key = new Pair<>(useCase, role); - List<AudioDeviceAttributes> roleDevices = new ArrayList<>(); - List<AudioDeviceAttributes> appliedDevices = new ArrayList<>(); - if (rolesMap.containsKey(key)) { - roleDevices = rolesMap.get(key); - boolean equal = false; - if (roleDevices.size() == devices.size()) { - roleDevices.retainAll(devices); - equal = roleDevices.size() == devices.size(); - } - if (!equal) { - clearOp.deviceRoleAction(useCase, role, null); - roleDevices.clear(); - appliedDevices.addAll(devices); + if (devicesListEqual(devices, rolesMap.get(key))) { + // NO OP: no change in preference + return AudioSystem.SUCCESS; } - } else { - appliedDevices.addAll(devices); - } - if (appliedDevices.isEmpty()) { + } else if (devices.isEmpty()) { + // NO OP: no preference to no preference return AudioSystem.SUCCESS; } - final int status = addOp.deviceRoleAction(useCase, role, appliedDevices); - if (status == AudioSystem.SUCCESS) { - roleDevices.addAll(appliedDevices); - rolesMap.put(key, roleDevices); + int status; + if (devices.isEmpty()) { + status = clearOp.deviceRoleAction(useCase, role, null); + if (status == AudioSystem.SUCCESS) { + rolesMap.remove(key); + } + } else { + status = addOp.deviceRoleAction(useCase, role, devices); + if (status == AudioSystem.SUCCESS) { + rolesMap.put(key, devices); + } } return status; } @@ -1641,11 +1660,12 @@ public class AudioDeviceInventory { } synchronized (mDevicesLock) { - final ArraySet<String> toRemove = new ArraySet<>(); + final ArraySet<Pair<String, Integer>> toRemove = new ArraySet<>(); // Disconnect ALL DEVICE_OUT_BLE_HEADSET or DEVICE_OUT_BLE_BROADCAST devices mConnectedDevices.values().forEach(deviceInfo -> { if (deviceInfo.mDeviceType == device) { - toRemove.add(deviceInfo.mDeviceAddress); + toRemove.add( + new Pair<>(deviceInfo.mDeviceAddress, deviceInfo.mDeviceCodecFormat)); } }); new MediaMetrics.Item(mMetricsId + "disconnectLeAudio") @@ -1655,8 +1675,8 @@ public class AudioDeviceInventory { final int delay = checkSendBecomingNoisyIntentInt(device, AudioService.CONNECTION_STATE_DISCONNECTED, AudioSystem.DEVICE_NONE); - toRemove.stream().forEach(deviceAddress -> - makeLeAudioDeviceUnavailableLater(deviceAddress, device, delay) + toRemove.stream().forEach(entry -> + makeLeAudioDeviceUnavailableLater(entry.first, device, entry.second, delay) ); } } @@ -2200,7 +2220,8 @@ public class AudioDeviceInventory { @GuardedBy("mDevicesLock") private void makeLeAudioDeviceAvailable( - AudioDeviceBroker.BtDeviceInfo btInfo, int streamType, String eventSource) { + AudioDeviceBroker.BtDeviceInfo btInfo, int streamType, + @AudioSystem.AudioFormatNativeEnumForBtCodec int codec, String eventSource) { final int volumeIndex = btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10; final int device = btInfo.mAudioSystemDevice; @@ -2234,7 +2255,7 @@ public class AudioDeviceInventory { AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name); final int res = AudioSystem.setDeviceConnectionState(ada, - AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioSystem.DEVICE_STATE_AVAILABLE, codec); if (res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "APM failed to make available LE Audio device addr=" + address @@ -2249,7 +2270,7 @@ public class AudioDeviceInventory { // Reset LEA suspend state each time a new sink is connected mDeviceBroker.clearLeAudioSuspended(true /* internalOnly */); mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address), - new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT, + new DeviceInfo(device, name, address, codec, peerAddress, groupId)); mDeviceBroker.postAccessoryPlugMediaUnmute(device); setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false); @@ -2272,13 +2293,14 @@ public class AudioDeviceInventory { } @GuardedBy("mDevicesLock") - private void makeLeAudioDeviceUnavailableNow(String address, int device) { + private void makeLeAudioDeviceUnavailableNow(String address, int device, + @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) { AudioDeviceAttributes ada = null; if (device != AudioSystem.DEVICE_NONE) { ada = new AudioDeviceAttributes(device, address); final int res = AudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_UNAVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT); + codec); if (res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( @@ -2303,7 +2325,8 @@ public class AudioDeviceInventory { } @GuardedBy("mDevicesLock") - private void makeLeAudioDeviceUnavailableLater(String address, int device, int delayMs) { + private void makeLeAudioDeviceUnavailableLater( + String address, int device, int codec, int delayMs) { // prevent any activity on the LEA output to avoid unwanted // reconnection of the sink. mDeviceBroker.setLeAudioSuspended( @@ -2311,7 +2334,7 @@ public class AudioDeviceInventory { // the device will be made unavailable later, so consider it disconnected right away mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address)); // send the delayed message to make the device unavailable later - mDeviceBroker.setLeAudioTimeout(address, device, delayMs); + mDeviceBroker.setLeAudioTimeout(address, device, codec, delayMs); } @GuardedBy("mDevicesLock") diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 7b9621581adf..a078d08a2c8f 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -26,6 +26,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothLeAudio; +import android.bluetooth.BluetoothLeAudioCodecConfig; import android.bluetooth.BluetoothLeAudioCodecStatus; import android.bluetooth.BluetoothProfile; import android.content.Context; @@ -250,35 +251,73 @@ public class BtHelper { } } - /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getA2dpCodec( - @NonNull BluetoothDevice device) { - if (mA2dp == null) { - return AudioSystem.AUDIO_FORMAT_DEFAULT; - } - BluetoothCodecStatus btCodecStatus = null; - try { - btCodecStatus = mA2dp.getCodecStatus(device); - } catch (Exception e) { - Log.e(TAG, "Exception while getting status of " + device, e); - } - if (btCodecStatus == null) { - return AudioSystem.AUDIO_FORMAT_DEFAULT; - } - final BluetoothCodecConfig btCodecConfig = btCodecStatus.getCodecConfig(); - if (btCodecConfig == null) { - return AudioSystem.AUDIO_FORMAT_DEFAULT; + /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getCodec( + @NonNull BluetoothDevice device, @AudioService.BtProfile int profile) { + switch (profile) { + case BluetoothProfile.A2DP: { + if (mA2dp == null) { + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + BluetoothCodecStatus btCodecStatus = null; + try { + btCodecStatus = mA2dp.getCodecStatus(device); + } catch (Exception e) { + Log.e(TAG, "Exception while getting status of " + device, e); + } + if (btCodecStatus == null) { + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + final BluetoothCodecConfig btCodecConfig = btCodecStatus.getCodecConfig(); + if (btCodecConfig == null) { + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + return AudioSystem.bluetoothA2dpCodecToAudioFormat(btCodecConfig.getCodecType()); + } + case BluetoothProfile.LE_AUDIO: { + if (mLeAudio == null) { + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + BluetoothLeAudioCodecStatus btLeCodecStatus = null; + int groupId = mLeAudio.getGroupId(device); + try { + btLeCodecStatus = mLeAudio.getCodecStatus(groupId); + } catch (Exception e) { + Log.e(TAG, "Exception while getting status of " + device, e); + } + if (btLeCodecStatus == null) { + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + BluetoothLeAudioCodecConfig btLeCodecConfig = + btLeCodecStatus.getOutputCodecConfig(); + if (btLeCodecConfig == null) { + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + return AudioSystem.bluetoothLeCodecToAudioFormat(btLeCodecConfig.getCodecType()); + } + default: + return AudioSystem.AUDIO_FORMAT_DEFAULT; } - return AudioSystem.bluetoothCodecToAudioFormat(btCodecConfig.getCodecType()); } /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec - int getA2dpCodecWithFallbackToSBC( - @NonNull BluetoothDevice device, @NonNull String source) { - @AudioSystem.AudioFormatNativeEnumForBtCodec int codec = getA2dpCodec(device); + int getCodecWithFallback( + @NonNull BluetoothDevice device, @AudioService.BtProfile int profile, + boolean isLeOutput, @NonNull String source) { + // For profiles other than A2DP and LE Audio output, the audio codec format must be + // AUDIO_FORMAT_DEFAULT as native audio policy manager expects a specific audio format + // only if audio HW module selection based on format is supported for the device type. + if (!(profile == BluetoothProfile.A2DP + || (profile == BluetoothProfile.LE_AUDIO && isLeOutput))) { + return AudioSystem.AUDIO_FORMAT_DEFAULT; + } + @AudioSystem.AudioFormatNativeEnumForBtCodec int codec = + getCodec(device, profile); if (codec == AudioSystem.AUDIO_FORMAT_DEFAULT) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( - "getA2dpCodec DEFAULT from " + source + " fallback to SBC")); - return AudioSystem.AUDIO_FORMAT_SBC; + "getCodec DEFAULT from " + source + " fallback to " + + (profile == BluetoothProfile.A2DP ? "SBC" : "LC3"))); + return profile == BluetoothProfile.A2DP + ? AudioSystem.AUDIO_FORMAT_SBC : AudioSystem.AUDIO_FORMAT_LC3; } return codec; } diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index 61e4f36a34ed..4f7f31dfa7dc 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -1016,6 +1016,11 @@ public class SpatializerHelper { if (mSpat == null) { mSpatCallback = new SpatializerCallback(); mSpat = AudioSystem.getSpatializer(mSpatCallback); + if (mSpat == null) { + Log.e(TAG, "createSpat(): No Spatializer found"); + postReset(); + return; + } try { //TODO: register heatracking callback only when sensors are registered if (mIsHeadTrackingSupported) { diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java index 745222873698..95a047faef07 100644 --- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java +++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java @@ -116,8 +116,10 @@ public final class BiometricContextProvider implements BiometricContext { service.setBiometicContextListener(new IBiometricContextListener.Stub() { @Override public void onFoldChanged(int foldState) { - mFoldState = foldState; - // no need to notify, not sent to HAL + if (mFoldState != foldState) { + mFoldState = foldState; + notifyChanged(); + } } @Override @@ -254,6 +256,7 @@ public final class BiometricContextProvider implements BiometricContext { + "isAwake: " + isAwake() + ", " + "isDisplayOn: " + isDisplayOn() + ", " + "dock: " + getDockedState() + ", " - + "rotation: " + getCurrentRotation() + "]"; + + "rotation: " + getCurrentRotation() + ", " + + "foldState: " + mFoldState + "]"; } } diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java index f78ca43253f6..b4e0dff615f5 100644 --- a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java +++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java @@ -23,6 +23,7 @@ import android.hardware.biometrics.AuthenticateOptions; import android.hardware.biometrics.IBiometricContextListener; import android.hardware.biometrics.common.AuthenticateReason; import android.hardware.biometrics.common.DisplayState; +import android.hardware.biometrics.common.FoldState; import android.hardware.biometrics.common.OperationContext; import android.hardware.biometrics.common.OperationReason; import android.hardware.biometrics.common.WakeReason; @@ -250,6 +251,7 @@ public class OperationContextExt { OperationContextExt update(@NonNull BiometricContext biometricContext, boolean isCrypto) { mAidlContext.isAod = biometricContext.isAod(); mAidlContext.displayState = toAidlDisplayState(biometricContext.getDisplayState()); + mAidlContext.foldState = toAidlFoldState(biometricContext.getFoldState()); mAidlContext.isCrypto = isCrypto; setFirstSessionId(biometricContext); @@ -276,6 +278,19 @@ public class OperationContextExt { return DisplayState.UNKNOWN; } + @FoldState + private static int toAidlFoldState(@IBiometricContextListener.FoldState int state) { + switch (state) { + case IBiometricContextListener.FoldState.FULLY_CLOSED: + return FoldState.FULLY_CLOSED; + case IBiometricContextListener.FoldState.FULLY_OPENED: + return FoldState.FULLY_OPENED; + case IBiometricContextListener.FoldState.HALF_OPENED: + return FoldState.HALF_OPENED; + } + return FoldState.UNKNOWN; + } + private void setFirstSessionId(@NonNull BiometricContext biometricContext) { if (mIsBP) { mSessionInfo = biometricContext.getBiometricPromptSessionInfo(); diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 5bb5c53f6d5e..a7965441274c 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -52,7 +52,6 @@ import android.hardware.display.DisplayManager; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.media.AudioManager; -import android.nfc.INfcAdapter; import android.nfc.NfcAdapter; import android.nfc.NfcManager; import android.os.Binder; @@ -1281,45 +1280,19 @@ public class CameraServiceProxy extends SystemService } } - // TODO(b/303286040): Remove the raw INfcAdapter usage once |ENABLE_NFC_MAINLINE_FLAG| is - // rolled out. - private static final String NFC_SERVICE_BINDER_NAME = "nfc"; - // Flags arguments to NFC adapter to enable/disable NFC - public static final int DISABLE_POLLING_FLAGS = 0x1000; - public static final int ENABLE_POLLING_FLAGS = 0x0000; - private void setNfcReaderModeUsingINfcAdapter(boolean enablePolling) { - IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME); - if (nfcServiceBinder == null) { + private void notifyNfcService(boolean enablePolling) { + NfcManager nfcManager = mContext.getSystemService(NfcManager.class); + if (nfcManager == null) { Slog.w(TAG, "Could not connect to NFC service to notify it of camera state"); return; } - INfcAdapter nfcAdapterRaw = INfcAdapter.Stub.asInterface(nfcServiceBinder); - int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS; - if (DEBUG) Slog.v(TAG, "Setting NFC reader mode to flags " + flags); - try { - nfcAdapterRaw.setReaderMode(nfcInterfaceToken, null, flags, null); - } catch (RemoteException e) { - Slog.w(TAG, "Could not notify NFC service, remote exception: " + e); - } - } - - private void notifyNfcService(boolean enablePolling) { - if (android.nfc.Flags.enableNfcMainline()) { - NfcManager nfcManager = mContext.getSystemService(NfcManager.class); - if (nfcManager == null) { - Slog.w(TAG, "Could not connect to NFC service to notify it of camera state"); - return; - } - NfcAdapter nfcAdapter = nfcManager.getDefaultAdapter(); - if (nfcAdapter == null) { - Slog.w(TAG, "Could not connect to NFC service to notify it of camera state"); - return; - } - if (DEBUG) Slog.v(TAG, "Setting NFC reader mode. enablePolling: " + enablePolling); - nfcAdapter.setReaderMode(enablePolling); - } else { - setNfcReaderModeUsingINfcAdapter(enablePolling); + NfcAdapter nfcAdapter = nfcManager.getDefaultAdapter(); + if (nfcAdapter == null) { + Slog.w(TAG, "Could not connect to NFC service to notify it of camera state"); + return; } + if (DEBUG) Slog.v(TAG, "Setting NFC reader mode. enablePolling: " + enablePolling); + nfcAdapter.setReaderMode(enablePolling); } private static int[] toArray(Collection<Integer> c) { diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index b394fb5b3afe..56a94ec06ad4 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -56,6 +56,7 @@ import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -67,7 +68,6 @@ import android.os.Parcel; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.DeviceConfig; @@ -116,8 +116,6 @@ import java.util.function.Consumer; public class ClipboardService extends SystemService { private static final String TAG = "ClipboardService"; - private static final boolean IS_EMULATOR = - SystemProperties.getBoolean("ro.boot.qemu", false); @VisibleForTesting public static final long DEFAULT_CLIPBOARD_TIMEOUT_MILLIS = 3600000; @@ -193,7 +191,7 @@ public class ClipboardService extends SystemService { mAutofillInternal = LocalServices.getService(AutofillManagerInternal.class); final IBinder permOwner = mUgmInternal.newUriPermissionOwner("clipboard"); mPermissionOwner = permOwner; - if (IS_EMULATOR) { + if (Build.IS_EMULATOR) { mEmulatorClipboardMonitor = new EmulatorClipboardMonitor((clip) -> { synchronized (mLock) { Clipboard clipboard = getClipboardLocked(0, DEVICE_ID_DEFAULT); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index aef224843b2f..c5170585a1b3 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -56,7 +56,6 @@ import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityManager; -import android.net.DnsResolver; import android.net.INetd; import android.net.INetworkManagementEventObserver; import android.net.Ikev2VpnProfile; @@ -67,8 +66,6 @@ import android.net.IpSecManager.IpSecTunnelInterface; import android.net.IpSecTransform; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.LocalSocket; -import android.net.LocalSocketAddress; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkAgentConfig; @@ -109,7 +106,6 @@ import android.net.vcn.VcnTransportInfo; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Bundle; -import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; @@ -120,7 +116,6 @@ import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; -import android.os.SystemService; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -160,11 +155,8 @@ import com.android.server.vcn.util.PersistableBundleUtils; import libcore.io.IoUtils; -import java.io.File; import java.io.FileDescriptor; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -190,8 +182,6 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledFuture; @@ -451,10 +441,6 @@ public class Vpn { // The user id of initiating VPN. private final int mUserId; - interface RetryScheduler { - void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException; - } - private static class CarrierConfigInfo { public final String mccMnc; public final int keepaliveDelaySec; @@ -483,26 +469,6 @@ public class Vpn { return Binder.getCallingUid() == Process.SYSTEM_UID; } - public void startService(final String serviceName) { - SystemService.start(serviceName); - } - - public void stopService(final String serviceName) { - SystemService.stop(serviceName); - } - - public boolean isServiceRunning(final String serviceName) { - return SystemService.isRunning(serviceName); - } - - public boolean isServiceStopped(final String serviceName) { - return SystemService.isStopped(serviceName); - } - - public File getStateFile() { - return new File("/data/misc/vpn/state"); - } - public DeviceIdleInternal getDeviceIdleInternal() { return LocalServices.getService(DeviceIdleInternal.class); } @@ -511,104 +477,6 @@ public class Vpn { return VpnConfig.getIntentForStatusPanel(context); } - public void sendArgumentsToDaemon( - final String daemon, final LocalSocket socket, final String[] arguments, - final RetryScheduler retryScheduler) throws IOException, InterruptedException { - final LocalSocketAddress address = new LocalSocketAddress( - daemon, LocalSocketAddress.Namespace.RESERVED); - - // Wait for the socket to connect. - while (true) { - try { - socket.connect(address); - break; - } catch (Exception e) { - // ignore - } - retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); - } - socket.setSoTimeout(500); - - final OutputStream out = socket.getOutputStream(); - for (String argument : arguments) { - byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); - if (bytes.length >= 0xFFFF) { - throw new IllegalArgumentException("Argument is too large"); - } - out.write(bytes.length >> 8); - out.write(bytes.length); - out.write(bytes); - retryScheduler.checkInterruptAndDelay(false /* sleepLonger */); - } - out.write(0xFF); - out.write(0xFF); - - // Wait for End-of-File. - final InputStream in = socket.getInputStream(); - while (true) { - try { - if (in.read() == -1) { - break; - } - } catch (Exception e) { - // ignore - } - retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); - } - } - - @NonNull - public InetAddress resolve(final String endpoint) - throws ExecutionException, InterruptedException { - try { - return InetAddresses.parseNumericAddress(endpoint); - } catch (IllegalArgumentException e) { - // Endpoint is not numeric : fall through and resolve - } - - final CancellationSignal cancellationSignal = new CancellationSignal(); - try { - final DnsResolver resolver = DnsResolver.getInstance(); - final CompletableFuture<InetAddress> result = new CompletableFuture(); - final DnsResolver.Callback<List<InetAddress>> cb = - new DnsResolver.Callback<List<InetAddress>>() { - @Override - public void onAnswer(@NonNull final List<InetAddress> answer, - final int rcode) { - if (answer.size() > 0) { - result.complete(answer.get(0)); - } else { - result.completeExceptionally( - new UnknownHostException(endpoint)); - } - } - - @Override - public void onError(@Nullable final DnsResolver.DnsException error) { - // Unfortunately UnknownHostException doesn't accept a cause, so - // print a message here instead. Only show the summary, not the - // full stack trace. - Log.e(TAG, "Async dns resolver error : " + error); - result.completeExceptionally(new UnknownHostException(endpoint)); - } - }; - resolver.query(null /* network, null for default */, endpoint, - DnsResolver.FLAG_EMPTY, r -> r.run(), cancellationSignal, cb); - return result.get(); - } catch (final ExecutionException e) { - Log.e(TAG, "Cannot resolve VPN endpoint : " + endpoint + ".", e); - throw e; - } catch (final InterruptedException e) { - Log.e(TAG, "Legacy VPN was interrupted while resolving the endpoint", e); - cancellationSignal.cancel(); - throw e; - } - } - - public boolean isInterfacePresent(final Vpn vpn, final String iface) { - return vpn.jniCheck(iface) != 0; - } - /** * @see ParcelFileDescriptor#adoptFd(int) */ diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index f09fcea69a88..2cca72e4c883 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1978,8 +1978,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call || sdrAnimateValue != currentSdrBrightness)) { boolean skipAnimation = initialRampSkip || hasBrightnessBuckets || !isDisplayContentVisible || brightnessIsTemporary; - if (!skipAnimation && BrightnessSynchronizer.floatEquals( - sdrAnimateValue, currentSdrBrightness)) { + final boolean isHdrOnlyChange = BrightnessSynchronizer.floatEquals( + sdrAnimateValue, currentSdrBrightness); + if (mFlags.isFastHdrTransitionsEnabled() && !skipAnimation && isHdrOnlyChange) { // SDR brightness is unchanged, so animate quickly as this is only impacting // a likely minority amount of display content // ie, the highlights of an HDR video or UltraHDR image diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index 5310e43eaf1b..810ac08e32c1 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -1602,8 +1602,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal || sdrAnimateValue != currentSdrBrightness)) { boolean skipAnimation = initialRampSkip || hasBrightnessBuckets || !isDisplayContentVisible || brightnessIsTemporary; - if (!skipAnimation && BrightnessSynchronizer.floatEquals( - sdrAnimateValue, currentSdrBrightness)) { + final boolean isHdrOnlyChange = BrightnessSynchronizer.floatEquals( + sdrAnimateValue, currentSdrBrightness); + if (mFlags.isFastHdrTransitionsEnabled() && !skipAnimation && isHdrOnlyChange) { // SDR brightness is unchanged, so animate quickly as this is only impacting // a likely minority amount of display content // ie, the highlights of an HDR video or UltraHDR image diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java index f579dbd16592..bd5e189a5404 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -101,6 +101,10 @@ public class DisplayManagerFlags { Flags.FLAG_AUTO_BRIGHTNESS_MODES, Flags::autoBrightnessModes); + private final FlagState mFastHdrTransitions = new FlagState( + Flags.FLAG_FAST_HDR_TRANSITIONS, + Flags::fastHdrTransitions); + /** Returns whether connected display management is enabled or not. */ public boolean isConnectedDisplayManagementEnabled() { return mConnectedDisplayManagementFlagState.isEnabled(); @@ -205,6 +209,10 @@ public class DisplayManagerFlags { return mAutoBrightnessModesFlagState.isEnabled(); } + public boolean isFastHdrTransitionsEnabled() { + return mFastHdrTransitions.isEnabled(); + } + /** * dumps all flagstates * @param pw printWriter @@ -226,6 +234,7 @@ public class DisplayManagerFlags { pw.println(" " + mVsyncProximityVote); pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState); pw.println(" " + mAutoBrightnessModesFlagState); + pw.println(" " + mFastHdrTransitions); } private static class FlagState { diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig index 1b4d74cdff1f..7a723a3290a9 100644 --- a/services/core/java/com/android/server/display/feature/display_flags.aconfig +++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig @@ -144,3 +144,12 @@ flag { bug: "293613040" is_fixed_read_only: true } + +flag { + name: "fast_hdr_transitions" + namespace: "display_manager" + description: "Feature flag for fast transitions into/out of HDR" + bug: "292124102" + is_fixed_read_only: true +} + diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java index 6147c10f85d5..f3532e5ce7e9 100644 --- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java +++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java @@ -182,7 +182,7 @@ final class NewDeviceAction extends HdmiCecFeatureAction { .setVendorId(mVendorId) .setDisplayName(mDisplayName) .build(); - localDevice().mService.getHdmiCecNetwork().addCecDevice(deviceInfo); + localDevice().mService.getHdmiCecNetwork().updateCecDevice(deviceInfo); // Consume CEC messages we already got for this newly found device. tv().processDelayedMessages(mDeviceLogicalAddress); diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java index 35c61204d251..d359280c2a6f 100644 --- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java +++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java @@ -467,8 +467,7 @@ public abstract class IContextHubWrapper { } public byte[] getUuid() throws RemoteException { - //TODO(b/247124878): return the UUID defined in this file when the API is put in use - throw new RemoteException("This API is not implemented yet."); + return UUID; } @Override diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index 4bac872dbaa9..17f2fcc5b9d8 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -155,43 +155,45 @@ class LockSettingsShellCommand extends ShellCommand { try (final PrintWriter pw = getOutPrintWriter();) { pw.println("lockSettings service commands:"); pw.println(""); - pw.println("NOTE: when lock screen is set, all commands require the --old <CREDENTIAL>" - + " argument."); + pw.println("NOTE: when a secure lock screen is set, most commands require the"); + pw.println("--old <CREDENTIAL> option."); pw.println(""); pw.println(" help"); pw.println(" Prints this help text."); pw.println(""); - pw.println(" get-disabled [--old <CREDENTIAL>] [--user USER_ID]"); - pw.println(" Checks whether lock screen is disabled."); + pw.println(" get-disabled [--user USER_ID]"); + pw.println(" Prints true if the lock screen is completely disabled, i.e. set to None."); + pw.println(" Otherwise prints false."); pw.println(""); - pw.println(" set-disabled [--old <CREDENTIAL>] [--user USER_ID] <true|false>"); - pw.println(" When true, disables lock screen."); + pw.println(" set-disabled [--user USER_ID] <true|false>"); + pw.println(" Sets whether the lock screen is disabled. If the lock screen is secure, this"); + pw.println(" has no immediate effect. I.e. this can only change between Swipe and None."); pw.println(""); pw.println(" set-pattern [--old <CREDENTIAL>] [--user USER_ID] <PATTERN>"); - pw.println(" Sets the lock screen as pattern, using the given PATTERN to unlock."); + pw.println(" Sets a secure lock screen that uses the given PATTERN. PATTERN is a series"); + pw.println(" of digits 1-9 that identify the cells of the pattern."); pw.println(""); pw.println(" set-pin [--old <CREDENTIAL>] [--user USER_ID] <PIN>"); - pw.println(" Sets the lock screen as PIN, using the given PIN to unlock."); + pw.println(" Sets a secure lock screen that uses the given PIN."); pw.println(""); pw.println(" set-password [--old <CREDENTIAL>] [--user USER_ID] <PASSWORD>"); - pw.println(" Sets the lock screen as password, using the given PASSWORD to unlock."); + pw.println(" Sets a secure lock screen that uses the given PASSWORD."); pw.println(""); pw.println(" clear [--old <CREDENTIAL>] [--user USER_ID]"); - pw.println(" Clears the lock credentials."); + pw.println(" Clears the lock credential."); pw.println(""); pw.println(" verify [--old <CREDENTIAL>] [--user USER_ID]"); - pw.println(" Verifies the lock credentials."); + pw.println(" Verifies the lock credential."); pw.println(""); pw.println(" remove-cache [--user USER_ID]"); pw.println(" Removes cached unified challenge for the managed profile."); pw.println(""); pw.println(" set-resume-on-reboot-provider-package <package_name>"); - pw.println(" Sets the package name for server based resume on reboot service " - + "provider."); + pw.println(" Sets the package name for server based resume on reboot service provider."); pw.println(""); pw.println(" require-strong-auth [--user USER_ID] <reason>"); - pw.println(" Requires the strong authentication. The current supported reasons: " - + "STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN."); + pw.println(" Requires strong authentication. The current supported reasons:"); + pw.println(" STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN."); pw.println(""); } } diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java index 1641d4a6ed46..87158cd6fe29 100644 --- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java +++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java @@ -23,6 +23,7 @@ import static android.service.notification.NotificationServiceProto.RULE_TYPE_MA import static android.service.notification.NotificationServiceProto.RULE_TYPE_UNKNOWN; import android.annotation.NonNull; +import android.app.Flags; import android.app.NotificationManager; import android.content.pm.PackageManager; import android.os.Process; @@ -502,6 +503,13 @@ class ZenModeEventLogger { ZenModeConfig.getZenPolicySenders(mNewPolicy.allowMessagesFrom())); proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, mNewPolicy.allowConversationsFrom()); + + if (Flags.modesApi()) { + proto.write(DNDPolicyProto.ALLOW_CHANNELS, + mNewPolicy.allowPriorityChannels() + ? ZenPolicy.CHANNEL_TYPE_PRIORITY + : ZenPolicy.CHANNEL_TYPE_NONE); + } } else { Log.wtf(TAG, "attempted to write zen mode log event with null policy"); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 89d820050b03..d0ded63162db 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -1519,7 +1519,7 @@ public class ZenModeHelper { final boolean muteEverything = zenSilence || (zenPriorityOnly && ZenModeConfig.areAllZenBehaviorSoundsMuted(mConsolidatedPolicy)); - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.SDK_USAGES.toArray()) { final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage); if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) { applyRestrictions(zenPriorityOnly, false /*mute*/, usage); diff --git a/services/core/java/com/android/server/pdb/TEST_MAPPING b/services/core/java/com/android/server/pdb/TEST_MAPPING deleted file mode 100644 index e5f154a3d3c1..000000000000 --- a/services/core/java/com/android/server/pdb/TEST_MAPPING +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postsubmit": [ - { - "name": " PersistentDataBlockServiceTest" - } - ] -} diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java index af6a002e66c4..b23ccb8bf826 100644 --- a/services/core/java/com/android/server/pm/ApkChecksums.java +++ b/services/core/java/com/android/server/pm/ApkChecksums.java @@ -397,6 +397,9 @@ public class ApkChecksums { @Nullable Certificate[] trustedInstallers, Map<Integer, ApkChecksum> checksums, @NonNull Injector injector) { + if (!file.exists()) { + return; + } final String filePath = file.getAbsolutePath(); // Always available: FSI or IncFs. diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index ba2cf1dcc215..1a6529732a02 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -690,6 +690,9 @@ final class InstallPackageHelper { pkgSetting.setInstallReason(installReason, userId); pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId); pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId); + // Clear any existing archive state. + pkgSetting.setArchiveTimeMillis(0, userId); + pkgSetting.setArchiveState(null, userId); mPm.mSettings.writePackageRestrictionsLPr(userId); mPm.mSettings.writeKernelMappingLPr(pkgSetting); installed = true; @@ -2263,6 +2266,9 @@ final class InstallPackageHelper { ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName); } + // Clear any existing archive state. + ps.setArchiveState(null, userId); + ps.setArchiveTimeMillis(0, userId); } else if (allUsers != null) { // The caller explicitly specified INSTALL_ALL_USERS flag. // Thus, updating the settings to install the app for all users. @@ -2285,6 +2291,9 @@ final class InstallPackageHelper { ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId, installerPackageName); } + // Clear any existing archive state. + ps.setArchiveState(null, currentUserId); + ps.setArchiveTimeMillis(0, currentUserId); } else { ps.setInstalled(false, currentUserId); } diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index fb311dadd36c..e3bab3f243c3 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -24,6 +24,8 @@ import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap; import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; +import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS; +import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.DELETE_KEEP_DATA; import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT; @@ -38,6 +40,7 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; +import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IIntentReceiver; @@ -51,6 +54,7 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.DeleteFlags; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; @@ -118,6 +122,15 @@ public class PackageArchiver { private static final String ACTION_UNARCHIVE_DIALOG = "com.android.intent.action.UNARCHIVE_DIALOG"; + private static final String ACTION_UNARCHIVE_ERROR_DIALOG = + "com.android.intent.action.UNARCHIVE_ERROR_DIALOG"; + + private static final String EXTRA_REQUIRED_BYTES = + "com.android.content.pm.extra.UNARCHIVE_EXTRA_REQUIRED_BYTES"; + private static final String EXTRA_INSTALLER_PACKAGE_NAME = + "com.android.content.pm.extra.UNARCHIVE_INSTALLER_PACKAGE_NAME"; + private static final String EXTRA_INSTALLER_TITLE = + "com.android.content.pm.extra.UNARCHIVE_INSTALLER_TITLE"; private final Context mContext; private final PackageManagerService mPm; @@ -142,7 +155,8 @@ public class PackageArchiver { @NonNull String packageName, @NonNull String callerPackageName, @NonNull IntentSender intentSender, - @NonNull UserHandle userHandle) { + @NonNull UserHandle userHandle, + @DeleteFlags int flags) { Objects.requireNonNull(packageName); Objects.requireNonNull(callerPackageName); Objects.requireNonNull(intentSender); @@ -183,7 +197,7 @@ public class PackageArchiver { new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), callerPackageName, - DELETE_ARCHIVE | DELETE_KEEP_DATA, + DELETE_ARCHIVE | DELETE_KEEP_DATA | flags, intentSender, userId, binderUid); @@ -305,11 +319,14 @@ public class PackageArchiver { /** Creates archived state for the package and user. */ private CompletableFuture<ArchiveState> createArchiveState(String packageName, int userId) throws PackageManager.NameNotFoundException { - PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(), + Computer snapshot = mPm.snapshotComputer(); + PackageStateInternal ps = getPackageState(packageName, snapshot, Binder.getCallingUid(), userId); verifyNotSystemApp(ps.getFlags()); String responsibleInstallerPackage = getResponsibleInstallerPackage(ps); verifyInstaller(responsibleInstallerPackage, userId); + ApplicationInfo installerInfo = snapshot.getApplicationInfo( + responsibleInstallerPackage, /* flags= */ 0, userId); verifyOptOutStatus(packageName, UserHandle.getUid(userId, UserHandle.getUid(userId, ps.getAppId()))); @@ -320,7 +337,7 @@ public class PackageArchiver { try { archiveState.complete( createArchiveStateInternal(packageName, userId, mainActivities, - responsibleInstallerPackage)); + installerInfo.loadLabel(mContext.getPackageManager()).toString())); } catch (IOException e) { archiveState.completeExceptionally(e); } @@ -328,8 +345,17 @@ public class PackageArchiver { return archiveState; } - static ArchiveState createArchiveState(@NonNull ArchivedPackageParcel archivedPackage, + @Nullable + ArchiveState createArchiveState(@NonNull ArchivedPackageParcel archivedPackage, int userId, String installerPackage) { + ApplicationInfo installerInfo = mPm.snapshotComputer().getApplicationInfo( + installerPackage, /* flags= */ 0, userId); + if (installerInfo == null) { + // Should never happen because we just fetched the installerInfo. + Slog.e(TAG, "Couldnt find installer " + installerPackage); + return null; + } + try { var packageName = archivedPackage.packageName; var mainActivities = archivedPackage.archivedActivities; @@ -346,7 +372,8 @@ public class PackageArchiver { archiveActivityInfos.add(activityInfo); } - return new ArchiveState(archiveActivityInfos, installerPackage); + return new ArchiveState(archiveActivityInfos, + installerInfo.loadLabel(mContext.getPackageManager()).toString()); } catch (IOException e) { Slog.e(TAG, "Failed to create archive state", e); return null; @@ -354,7 +381,7 @@ public class PackageArchiver { } ArchiveState createArchiveStateInternal(String packageName, int userId, - List<LauncherActivityInfo> mainActivities, String installerPackage) + List<LauncherActivityInfo> mainActivities, String installerTitle) throws IOException { final int iconSize = mContext.getSystemService( ActivityManager.class).getLauncherLargeIconSize(); @@ -372,7 +399,7 @@ public class PackageArchiver { archiveActivityInfos.add(activityInfo); } - return new ArchiveState(archiveActivityInfos, installerPackage); + return new ArchiveState(archiveActivityInfos, installerTitle); } // TODO(b/298452477) Handle monochrome icons. @@ -412,14 +439,14 @@ public class PackageArchiver { return iconFile.toPath(); } - private void verifyInstaller(String installerPackage, int userId) + private void verifyInstaller(String installerPackageName, int userId) throws PackageManager.NameNotFoundException { - if (TextUtils.isEmpty(installerPackage)) { + if (TextUtils.isEmpty(installerPackageName)) { throw new PackageManager.NameNotFoundException("No installer found"); } // Allow shell for easier development. if ((Binder.getCallingUid() != Process.SHELL_UID) - && !verifySupportsUnarchival(installerPackage, userId)) { + && !verifySupportsUnarchival(installerPackageName, userId)) { throw new PackageManager.NameNotFoundException("Installer does not support unarchival"); } } @@ -588,7 +615,7 @@ public class PackageArchiver { final Intent broadcastIntent = new Intent(); broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName); - broadcastIntent.putExtra(PackageInstaller.EXTRA_UNARCHIVE_STATUS, + broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION); broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent); sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent); @@ -782,6 +809,83 @@ public class PackageArchiver { : ps.getInstallSource().mUpdateOwnerPackageName; } + void notifyUnarchivalListener(int status, String installerPackageName, String appPackageName, + long requiredStorageBytes, @Nullable PendingIntent userActionIntent, + IntentSender unarchiveIntentSender, int userId) { + final Intent broadcastIntent = new Intent(); + broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, appPackageName); + broadcastIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); + + if (status != UNARCHIVAL_OK) { + final Intent dialogIntent = createErrorDialogIntent(status, installerPackageName, + appPackageName, + requiredStorageBytes, userActionIntent, userId); + if (dialogIntent == null) { + // Error already logged. + return; + } + broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent); + } + + final BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setPendingIntentBackgroundActivityStartMode( + MODE_BACKGROUND_ACTIVITY_START_DENIED); + try { + unarchiveIntentSender.sendIntent(mContext, 0, broadcastIntent, /* onFinished= */ null, + /* handler= */ null, /* requiredPermission= */ null, + options.toBundle()); + } catch (IntentSender.SendIntentException e) { + Slog.e(TAG, TextUtils.formatSimple("Failed to send unarchive intent"), e); + } + } + + @Nullable + private Intent createErrorDialogIntent(int status, String installerPackageName, + String appPackageName, + long requiredStorageBytes, PendingIntent userActionIntent, int userId) { + final Intent dialogIntent = new Intent(ACTION_UNARCHIVE_ERROR_DIALOG); + dialogIntent.putExtra(EXTRA_UNARCHIVE_STATUS, status); + if (requiredStorageBytes > 0) { + dialogIntent.putExtra(EXTRA_REQUIRED_BYTES, requiredStorageBytes); + } + // Note that the userActionIntent is provided by the installer and is used only by the + // system package installer as a follow-up action after the user confirms the dialog. + if (userActionIntent != null) { + dialogIntent.putExtra(Intent.EXTRA_INTENT, userActionIntent); + } + dialogIntent.putExtra(EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName); + // We fetch this label from the archive state because the installer might not be installed + // anymore in an edge case. + String installerTitle = getInstallerTitle(appPackageName, userId); + if (installerTitle == null) { + // Error already logged. + return null; + } + dialogIntent.putExtra(EXTRA_INSTALLER_TITLE, installerTitle); + return dialogIntent; + } + + private String getInstallerTitle(String appPackageName, int userId) { + PackageStateInternal packageState; + try { + packageState = getPackageState(appPackageName, + mPm.snapshotComputer(), + Process.SYSTEM_UID, userId); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, TextUtils.formatSimple( + "notifyUnarchivalListener: Couldn't fetch package state for %s.", + appPackageName), e); + return null; + } + ArchiveState archiveState = packageState.getUserStateOrDefault(userId).getArchiveState(); + if (archiveState == null) { + Slog.e(TAG, TextUtils.formatSimple("notifyUnarchivalListener: App not archived %s.", + appPackageName)); + return null; + } + return archiveState.getInstallerTitle(); + } + @NonNull private static PackageStateInternal getPackageState(String packageName, Computer snapshot, int callingUid, int userId) diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 882e05dd778b..7d6dd62153c1 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -16,9 +16,10 @@ package com.android.server.pm; -import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_DELETED_BY_DO; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; +import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_DISABLED; +import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_NO_CONNECTIVITY; import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_USER_ACTION_NEEDED; @@ -66,6 +67,7 @@ import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageInstaller.UnarchivalStatus; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.DeleteFlags; import android.content.pm.ParceledListSlice; import android.content.pm.VersionedPackage; import android.content.pm.parsing.FrameworkParsingPackageUtils; @@ -1389,11 +1391,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, statusReceiver, versionedPackage.getPackageName(), canSilentlyInstallPackage, userId); - if (mContext.checkCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES) + final boolean shouldShowConfirmationDialog = + (flags & PackageManager.DELETE_SHOW_DIALOG) != 0; + if (!shouldShowConfirmationDialog + && mContext.checkCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) { // Sweet, call straight through! mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); - } else if (canSilentlyInstallPackage) { + } else if (!shouldShowConfirmationDialog && canSilentlyInstallPackage) { // Allow the device owner and affiliated profile owner to silently delete packages // Need to clear the calling identity to get DELETE_PACKAGES permission final long ident = Binder.clearCallingIdentity(); @@ -1418,6 +1423,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null)); intent.putExtra(PackageInstaller.EXTRA_CALLBACK, new PackageManager.UninstallCompleteCallback(adapter.getBinder().asBinder())); + if ((flags & PackageManager.DELETE_ARCHIVE) != 0) { + // Delete flags are passed to the uninstaller activity so it can be preserved + // in the follow-up uninstall operation after the user confirmation + intent.putExtra(PackageInstaller.EXTRA_DELETE_FLAGS, flags); + } adapter.onUserActionRequired(intent); } } @@ -1630,9 +1640,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @NonNull String packageName, @NonNull String callerPackageName, @NonNull IntentSender intentSender, - @NonNull UserHandle userHandle) { + @NonNull UserHandle userHandle, + @DeleteFlags int flags) { mPackageArchiver.requestArchive(packageName, callerPackageName, intentSender, - userHandle); + userHandle, flags); } @Override @@ -1703,7 +1714,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements }); } - // TODO(b/307299702) Implement error dialog and propagate userActionIntent. @Override public void reportUnarchivalStatus( int unarchiveId, @@ -1746,8 +1756,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // Execute expensive calls outside the sync block. mPm.mHandler.post( - () -> notifyUnarchivalListener(status, session.params.appPackageName, - unarchiveIntentSender)); + () -> mPackageArchiver.notifyUnarchivalListener(status, + session.getInstallerPackageName(), + session.params.appPackageName, requiredStorageBytes, userActionIntent, + unarchiveIntentSender, userId)); session.params.unarchiveIntentSender = null; if (status != UNARCHIVAL_OK) { Binder.withCleanCallingIdentity(session::abandon); @@ -1776,29 +1788,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements UNARCHIVAL_ERROR_USER_ACTION_NEEDED, UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE, UNARCHIVAL_ERROR_NO_CONNECTIVITY, + UNARCHIVAL_ERROR_INSTALLER_DISABLED, + UNARCHIVAL_ERROR_INSTALLER_UNINSTALLED, UNARCHIVAL_GENERIC_ERROR).contains(status)) { throw new IllegalStateException("Invalid status code passed " + status); } } - private void notifyUnarchivalListener(int status, String packageName, - IntentSender unarchiveIntentSender) { - final Intent fillIn = new Intent(); - fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName); - fillIn.putExtra(PackageInstaller.EXTRA_UNARCHIVE_STATUS, status); - // TODO(b/307299702) Attach failure dialog with EXTRA_INTENT and requiredStorageBytes here. - final BroadcastOptions options = BroadcastOptions.makeBasic(); - options.setPendingIntentBackgroundActivityStartMode( - MODE_BACKGROUND_ACTIVITY_START_DENIED); - try { - unarchiveIntentSender.sendIntent(mContext, 0, fillIn, /* onFinished= */ null, - /* handler= */ null, /* requiredPermission= */ null, - options.toBundle()); - } catch (SendIntentException e) { - Slog.e(TAG, TextUtils.formatSimple("Failed to send unarchive intent"), e); - } - } - private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, int installerUid) { int count = 0; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index adb6906a2915..5daada94d815 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1534,8 +1534,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService return; } for (int userId : userIds) { - var archiveState = PackageArchiver.createArchiveState(archivePackage, userId, - responsibleInstallerPackage); + var archiveState = mInstallerService.mPackageArchiver.createArchiveState( + archivePackage, userId, responsibleInstallerPackage); if (archiveState == null) { continue; } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index fc662038d5d5..215e9528a35e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -4639,7 +4639,7 @@ class PackageManagerShellCommand extends ShellCommand { try { mInterface.getPackageInstaller().requestArchive(packageName, /* callerPackageName= */ "", receiver.getIntentSender(), - new UserHandle(translatedUserId)); + new UserHandle(translatedUserId), 0); } catch (Exception e) { pw.println("Failure [" + e.getMessage() + "]"); return 1; diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 293b87317ced..26dc57649ddd 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -770,6 +770,11 @@ public class PackageSetting extends SettingBase implements PackageStateInternal onChanged(); } + void setArchiveState(ArchiveState archiveState, int userId) { + modifyUserState(userId).setArchiveState(archiveState); + onChanged(); + } + void setArchiveTimeMillis(long value, int userId) { modifyUserState(userId).setArchiveTimeMillis(value); onChanged(); diff --git a/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java index dbf404736655..28818f7d1c6b 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java +++ b/services/core/java/com/android/server/pm/permission/PermissionMigrationHelperImpl.java @@ -93,7 +93,7 @@ public class PermissionMigrationHelperImpl implements PermissionMigrationHelper Map<Integer, Map<String, LegacyPermissionState>> appIdPermissionStates = new ArrayMap<>(); RuntimePermissionsState legacyState = - mPackageManagerInternal.getLegacyPermissionsState(userId); + (RuntimePermissionsState) mPackageManagerInternal.getLegacyPermissionsState(userId); PackageManagerLocal packageManagerLocal = LocalManagerRegistry.getManager(PackageManagerLocal.class); diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING index 05a0e85d790f..e64704a84cdf 100644 --- a/services/core/java/com/android/server/power/TEST_MAPPING +++ b/services/core/java/com/android/server/power/TEST_MAPPING @@ -45,6 +45,17 @@ {"include-filter": "com.android.server.power"}, {"exclude-annotation": "org.junit.Ignore"} ] + }, + { + "name": "CtsStatsdAtomHostTestCases", + "options": [ + {"exclude-annotation": "androidx.test.filters.FlakyTest"}, + {"exclude-annotation": "org.junit.Ignore"}, + {"include-filter": "android.cts.statsdatom.powermanager"} + ], + "file_patterns": [ + "(/|^)ThermalManagerService.java" + ] } ] } diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index d17207b8f261..99653ae1cd72 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -16,8 +16,17 @@ package com.android.server.power; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; +import static com.android.internal.util.FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__NO_TEMPERATURE_THRESHOLD; +import static com.android.internal.util.FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS_CALLED__API_STATUS__FEATURE_NOT_SUPPORTED; +import static com.android.internal.util.FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS_CALLED__API_STATUS__HAL_NOT_READY; +import static com.android.internal.util.FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS_CALLED__API_STATUS__SUCCESS; +import static com.android.internal.util.FrameworkStatsLog.THERMAL_STATUS_CALLED__API_STATUS__HAL_NOT_READY; +import static com.android.internal.util.FrameworkStatsLog.THERMAL_STATUS_CALLED__API_STATUS__SUCCESS; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.StatsManager; import android.content.Context; import android.hardware.thermal.IThermal; import android.hardware.thermal.IThermalChangedCallback; @@ -48,11 +57,13 @@ import android.os.Temperature; import android.util.ArrayMap; import android.util.EventLog; import android.util.Slog; +import android.util.StatsEvent; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.FgThread; import com.android.server.SystemService; @@ -122,6 +133,8 @@ public class ThermalManagerService extends SystemService { @VisibleForTesting final TemperatureWatcher mTemperatureWatcher = new TemperatureWatcher(); + private final Context mContext; + public ThermalManagerService(Context context) { this(context, null); } @@ -129,6 +142,7 @@ public class ThermalManagerService extends SystemService { @VisibleForTesting ThermalManagerService(Context context, @Nullable ThermalHalWrapper halWrapper) { super(context); + mContext = context; mHalWrapper = halWrapper; if (halWrapper != null) { halWrapper.setCallback(this::onTemperatureChangedCallback); @@ -146,6 +160,9 @@ public class ThermalManagerService extends SystemService { if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { onActivityManagerReady(); } + if (phase == SystemService.PHASE_BOOT_COMPLETED) { + registerStatsCallbacks(); + } } private void onActivityManagerReady() { @@ -326,6 +343,31 @@ public class ThermalManagerService extends SystemService { } } + private void registerStatsCallbacks() { + final StatsManager statsManager = mContext.getSystemService(StatsManager.class); + if (statsManager != null) { + statsManager.setPullAtomCallback( + FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS, + null, // use default PullAtomMetadata values + DIRECT_EXECUTOR, + this::onPullAtom); + } + } + + private int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) { + if (atomTag == FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS) { + final float[] thresholds; + synchronized (mTemperatureWatcher.mSamples) { + thresholds = Arrays.copyOf(mTemperatureWatcher.mHeadroomThresholds, + mTemperatureWatcher.mHeadroomThresholds.length); + } + data.add( + FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS, + thresholds)); + } + return android.app.StatsManager.PULL_SUCCESS; + } + @VisibleForTesting final IThermalService.Stub mService = new IThermalService.Stub() { @Override @@ -449,6 +491,12 @@ public class ThermalManagerService extends SystemService { synchronized (mLock) { final long token = Binder.clearCallingIdentity(); try { + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_STATUS_CALLED, + Binder.getCallingUid(), + mHalReady.get() + ? THERMAL_STATUS_CALLED__API_STATUS__SUCCESS + : THERMAL_STATUS_CALLED__API_STATUS__HAL_NOT_READY, + thermalSeverityToStatsdStatus(mStatus)); return mStatus; } finally { Binder.restoreCallingIdentity(token); @@ -493,6 +541,9 @@ public class ThermalManagerService extends SystemService { @Override public float getThermalHeadroom(int forecastSeconds) { if (!mHalReady.get()) { + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_CALLED, getCallingUid(), + FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__HAL_NOT_READY, + Float.NaN); return Float.NaN; } @@ -500,6 +551,9 @@ public class ThermalManagerService extends SystemService { if (DEBUG) { Slog.d(TAG, "Invalid forecastSeconds: " + forecastSeconds); } + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_CALLED, getCallingUid(), + FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__INVALID_ARGUMENT, + Float.NaN); return Float.NaN; } @@ -509,12 +563,21 @@ public class ThermalManagerService extends SystemService { @Override public float[] getThermalHeadroomThresholds() { if (!mHalReady.get()) { + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS_CALLED, + Binder.getCallingUid(), + THERMAL_HEADROOM_THRESHOLDS_CALLED__API_STATUS__HAL_NOT_READY); throw new IllegalStateException("Thermal HAL connection is not initialized"); } if (!Flags.allowThermalHeadroomThresholds()) { + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS_CALLED, + Binder.getCallingUid(), + THERMAL_HEADROOM_THRESHOLDS_CALLED__API_STATUS__FEATURE_NOT_SUPPORTED); throw new UnsupportedOperationException("Thermal headroom thresholds not enabled"); } synchronized (mTemperatureWatcher.mSamples) { + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_THRESHOLDS_CALLED, + Binder.getCallingUid(), + THERMAL_HEADROOM_THRESHOLDS_CALLED__API_STATUS__SUCCESS); return Arrays.copyOf(mTemperatureWatcher.mHeadroomThresholds, mTemperatureWatcher.mHeadroomThresholds.length); } @@ -544,6 +607,27 @@ public class ThermalManagerService extends SystemService { }; + private static int thermalSeverityToStatsdStatus(int severity) { + switch (severity) { + case PowerManager.THERMAL_STATUS_NONE: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__NONE; + case PowerManager.THERMAL_STATUS_LIGHT: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__LIGHT; + case PowerManager.THERMAL_STATUS_MODERATE: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__MODERATE; + case PowerManager.THERMAL_STATUS_SEVERE: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__SEVERE; + case PowerManager.THERMAL_STATUS_CRITICAL: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__CRITICAL; + case PowerManager.THERMAL_STATUS_EMERGENCY: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__EMERGENCY; + case PowerManager.THERMAL_STATUS_SHUTDOWN: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__SHUTDOWN; + default: + return FrameworkStatsLog.THERMAL_STATUS_CALLED__STATUS__NONE; + } + } + private static void dumpItemsLocked(PrintWriter pw, String prefix, Collection<?> items) { for (Iterator iterator = items.iterator(); iterator.hasNext();) { @@ -1492,13 +1576,15 @@ public class ThermalManagerService extends SystemService { threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE]; if (!Float.isNaN(severeThreshold)) { mSevereThresholds.put(threshold.name, severeThreshold); - for (int severity = ThrottlingSeverity.LIGHT; - severity <= ThrottlingSeverity.SHUTDOWN; severity++) { - if (Flags.allowThermalHeadroomThresholds() - && threshold.hotThrottlingThresholds.length > severity) { - updateHeadroomThreshold(severity, - threshold.hotThrottlingThresholds[severity], - severeThreshold); + if (Flags.allowThermalHeadroomThresholds()) { + for (int severity = ThrottlingSeverity.LIGHT; + severity <= ThrottlingSeverity.SHUTDOWN; severity++) { + if (severity != ThrottlingSeverity.SEVERE + && threshold.hotThrottlingThresholds.length > severity) { + updateHeadroomThreshold(severity, + threshold.hotThrottlingThresholds[severity], + severeThreshold); + } } } } @@ -1506,11 +1592,15 @@ public class ThermalManagerService extends SystemService { } } - // For a older device with multiple SKIN sensors, we will set a severity's headroom + // For an older device with multiple SKIN sensors, we will set a severity's headroom // threshold based on the minimum value of all as a workaround. void updateHeadroomThreshold(int severity, float threshold, float severeThreshold) { if (!Float.isNaN(threshold)) { synchronized (mSamples) { + if (severity == ThrottlingSeverity.SEVERE) { + mHeadroomThresholds[severity] = 1.0f; + return; + } float headroom = normalizeTemperature(threshold, severeThreshold); if (Float.isNaN(mHeadroomThresholds[severity])) { mHeadroomThresholds[severity] = headroom; @@ -1620,6 +1710,10 @@ public class ThermalManagerService extends SystemService { // to sample, return early if (mSamples.isEmpty()) { Slog.e(TAG, "No temperature samples found"); + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_CALLED, + Binder.getCallingUid(), + FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__NO_TEMPERATURE, + Float.NaN); return Float.NaN; } @@ -1627,16 +1721,22 @@ public class ThermalManagerService extends SystemService { // so return early if (mSevereThresholds.isEmpty()) { Slog.e(TAG, "No temperature thresholds found"); + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_CALLED, + Binder.getCallingUid(), + THERMAL_HEADROOM_CALLED__API_STATUS__NO_TEMPERATURE_THRESHOLD, + Float.NaN); return Float.NaN; } float maxNormalized = Float.NaN; + int noThresholdSampleCount = 0; for (Map.Entry<String, ArrayList<Sample>> entry : mSamples.entrySet()) { String name = entry.getKey(); ArrayList<Sample> samples = entry.getValue(); Float threshold = mSevereThresholds.get(name); if (threshold == null) { + noThresholdSampleCount++; Slog.e(TAG, "No threshold found for " + name); continue; } @@ -1659,7 +1759,17 @@ public class ThermalManagerService extends SystemService { maxNormalized = normalized; } } - + if (noThresholdSampleCount == mSamples.size()) { + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_CALLED, + Binder.getCallingUid(), + THERMAL_HEADROOM_CALLED__API_STATUS__NO_TEMPERATURE_THRESHOLD, + Float.NaN); + } else { + FrameworkStatsLog.write(FrameworkStatsLog.THERMAL_HEADROOM_CALLED, + Binder.getCallingUid(), + FrameworkStatsLog.THERMAL_HEADROOM_CALLED__API_STATUS__SUCCESS, + maxNormalized); + } return maxNormalized; } } diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index c17d6ab4c85b..7c833cbe57d4 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -32,6 +32,8 @@ import android.os.PerformanceHintManager; import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; +import android.os.WorkDuration; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.SparseIntArray; @@ -196,6 +198,9 @@ public final class HintManagerService extends SystemService { private static native void nativeSetMode(long halPtr, int mode, boolean enabled); + private static native void nativeReportActualWorkDuration(long halPtr, + WorkDuration[] workDurations); + /** Wrapper for HintManager.nativeInit */ public void halInit() { nativeInit(); @@ -253,6 +258,10 @@ public final class HintManagerService extends SystemService { nativeSetMode(halPtr, mode, enabled); } + /** Wrapper for HintManager.nativeReportActualWorkDuration */ + public void halReportActualWorkDuration(long halPtr, WorkDuration[] workDurations) { + nativeReportActualWorkDuration(halPtr, workDurations); + } } @VisibleForTesting @@ -629,6 +638,56 @@ public final class HintManagerService extends SystemService { } } + @Override + public void reportActualWorkDuration2(WorkDuration[] workDurations) { + synchronized (this) { + if (mHalSessionPtr == 0 || !mUpdateAllowed) { + return; + } + Preconditions.checkArgument(workDurations.length != 0, "the count" + + " of work durations shouldn't be 0."); + for (WorkDuration workDuration : workDurations) { + validateWorkDuration(workDuration); + } + mNativeWrapper.halReportActualWorkDuration(mHalSessionPtr, workDurations); + } + } + + void validateWorkDuration(WorkDuration workDuration) { + if (DEBUG) { + Slogf.d(TAG, "WorkDuration(" + workDuration.getTimestampNanos() + ", " + + workDuration.getWorkPeriodStartTimestampNanos() + ", " + + workDuration.getActualTotalDurationNanos() + ", " + + workDuration.getActualCpuDurationNanos() + ", " + + workDuration.getActualGpuDurationNanos() + ")"); + } + + // Allow work period start timestamp to be zero in system server side because + // legacy API call will use zero value. It can not be estimated with the timestamp + // the sample is received because the samples could stack up. + if (workDuration.getWorkPeriodStartTimestampNanos() < 0) { + throw new IllegalArgumentException( + TextUtils.formatSimple( + "Work period start timestamp (%d) should be greater than 0", + workDuration.getWorkPeriodStartTimestampNanos())); + } + if (workDuration.getActualTotalDurationNanos() <= 0) { + throw new IllegalArgumentException( + TextUtils.formatSimple("Actual total duration (%d) should be greater than 0", + workDuration.getActualTotalDurationNanos())); + } + if (workDuration.getActualCpuDurationNanos() <= 0) { + throw new IllegalArgumentException( + TextUtils.formatSimple("Actual CPU duration (%d) should be greater than 0", + workDuration.getActualCpuDurationNanos())); + } + if (workDuration.getActualGpuDurationNanos() < 0) { + throw new IllegalArgumentException( + TextUtils.formatSimple("Actual GPU duration (%d) should be non negative", + workDuration.getActualGpuDurationNanos())); + } + } + private void onProcStateChanged(boolean updateAllowed) { updateHintAllowed(updateAllowed); } diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java index b8d26d9cac42..698f6ea4b443 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -49,6 +49,7 @@ import android.os.BatteryUsageStatsQuery; import android.os.Binder; import android.os.BluetoothBatteryStats; import android.os.Build; +import android.os.ConditionVariable; import android.os.Handler; import android.os.IBatteryPropertiesRegistrar; import android.os.Looper; @@ -137,7 +138,6 @@ import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.net.module.util.NetworkCapabilitiesUtils; -import com.android.server.power.optimization.Flags; import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes; import libcore.util.EmptyArray; @@ -10543,7 +10543,7 @@ public class BatteryStatsImpl extends BatteryStats { final int batteryConsumerProcessState = mapUidProcessStateToBatteryConsumerProcessState(uidRunningState); - if (mBsi.mSystemReady && Flags.streamlinedBatteryStats()) { + if (mBsi.mSystemReady && mBsi.mPowerStatsCollectorEnabled) { mBsi.mHistory.recordProcessStateChange(elapsedRealtimeMs, uptimeMs, mUid, batteryConsumerProcessState); } @@ -11712,6 +11712,10 @@ public class BatteryStatsImpl extends BatteryStats { // Store the empty state to disk to ensure consistency writeSyncLocked(); + if (mPowerStatsCollectorEnabled) { + schedulePowerStatsSampleCollection(); + } + // Flush external data, gathering snapshots, but don't process it since it is pre-reset data mIgnoreNextExternalStats = true; mExternalSync.scheduleSync("reset", ExternalStatsSync.UPDATE_ON_RESET); @@ -15762,6 +15766,16 @@ public class BatteryStatsImpl extends BatteryStats { } /** + * Schedules an immediate collection of PowerStats samples and awaits the result. + */ + public void collectPowerStatsSamples() { + schedulePowerStatsSampleCollection(); + ConditionVariable done = new ConditionVariable(); + mHandler.post(done::open); + done.block(); + } + + /** * Grabs one sample of PowerStats and prints it. */ public void dumpStatsSample(PrintWriter pw) { diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index 391dd77e3506..096c5e6697b7 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -126,6 +126,10 @@ public class BatteryUsageStatsProvider { */ public List<BatteryUsageStats> getBatteryUsageStats(BatteryStatsImpl stats, List<BatteryUsageStatsQuery> queries) { + if (mPowerStatsExporterEnabled) { + stats.collectPowerStatsSamples(); + } + ArrayList<BatteryUsageStats> results = new ArrayList<>(queries.size()); synchronized (stats) { stats.prepareForDumpLocked(); @@ -168,15 +172,16 @@ public class BatteryUsageStatsProvider { & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS) != 0); final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold(); - final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder( - stats.getCustomEnergyConsumerNames(), includePowerModels, - includeProcessStateData, minConsumedPowerThreshold); - // TODO(b/188068523): use a monotonic clock to ensure resilience of order and duration - // of batteryUsageStats sessions to wall-clock adjustments - batteryUsageStatsBuilder.setStatsStartTimestamp(stats.getStartClockTime()); - batteryUsageStatsBuilder.setStatsEndTimestamp(currentTimeMs); - + final BatteryUsageStats.Builder batteryUsageStatsBuilder; synchronized (stats) { + batteryUsageStatsBuilder = new BatteryUsageStats.Builder( + stats.getCustomEnergyConsumerNames(), includePowerModels, + includeProcessStateData, minConsumedPowerThreshold); + + // TODO(b/188068523): use a monotonic clock to ensure resilience of order and duration + // of batteryUsageStats sessions to wall-clock adjustments + batteryUsageStatsBuilder.setStatsStartTimestamp(stats.getStartClockTime()); + batteryUsageStatsBuilder.setStatsEndTimestamp(currentTimeMs); SparseArray<? extends BatteryStats.Uid> uidStats = stats.getUidStats(); for (int i = uidStats.size() - 1; i >= 0; i--) { final BatteryStats.Uid uid = uidStats.valueAt(i); diff --git a/services/core/java/com/android/server/power/stats/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/PowerStatsExporter.java index 70c24d58bb2a..1f6f11320f1b 100644 --- a/services/core/java/com/android/server/power/stats/PowerStatsExporter.java +++ b/services/core/java/com/android/server/power/stats/PowerStatsExporter.java @@ -60,6 +60,7 @@ public class PowerStatsExporter { */ public void exportAggregatedPowerStats(BatteryUsageStats.Builder batteryUsageStatsBuilder, long monotonicStartTime, long monotonicEndTime) { + boolean hasStoredSpans = false; long maxEndTime = monotonicStartTime; List<PowerStatsSpan.Metadata> spans = mPowerStatsStore.getTableOfContents(); for (int i = spans.size() - 1; i >= 0; i--) { @@ -99,13 +100,14 @@ public class PowerStatsExporter { } List<PowerStatsSpan.Section> sections = span.getSections(); for (int k = 0; k < sections.size(); k++) { + hasStoredSpans = true; PowerStatsSpan.Section section = sections.get(k); populateBatteryUsageStatsBuilder(batteryUsageStatsBuilder, ((AggregatedPowerStatsSection) section).getAggregatedPowerStats()); } } - if (maxEndTime < monotonicEndTime - mBatterySessionTimeSpanSlackMillis) { + if (!hasStoredSpans || maxEndTime < monotonicEndTime - mBatterySessionTimeSpanSlackMillis) { mPowerStatsAggregator.aggregatePowerStats(maxEndTime, monotonicEndTime, stats -> populateBatteryUsageStatsBuilder(batteryUsageStatsBuilder, stats)); } diff --git a/services/core/java/com/android/server/power/stats/PowerStatsStore.java b/services/core/java/com/android/server/power/stats/PowerStatsStore.java index 7123bcb2d095..7bcdc7129d10 100644 --- a/services/core/java/com/android/server/power/stats/PowerStatsStore.java +++ b/services/core/java/com/android/server/power/stats/PowerStatsStore.java @@ -171,7 +171,7 @@ public class PowerStatsStore { try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) { return PowerStatsSpan.read(inputStream, parser, mSectionReader, sectionTypes); } catch (IOException | XmlPullParserException e) { - Slog.wtf(TAG, "Cannot read PowerStatsSpan file: " + file); + Slog.wtf(TAG, "Cannot read PowerStatsSpan file: " + file, e); } } finally { unlockStoreDirectory(); diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java index 8b57f87f5df3..8e9c889c8ef3 100644 --- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java +++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java @@ -38,6 +38,7 @@ import android.speech.IRecognitionServiceManagerCallback; import android.speech.IRecognitionSupportCallback; import android.speech.RecognitionService; import android.speech.SpeechRecognizer; +import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; @@ -253,6 +254,7 @@ final class SpeechRecognitionManagerServiceImpl extends @GuardedBy("mLock") private void incrementSessionCountForUidLocked(int uid) { mSessionCountByUid.put(uid, mSessionCountByUid.get(uid, 0) + 1); + Log.i(TAG, "Client " + uid + " has opened " + mSessionCountByUid.get(uid, 0) + " sessions"); } @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 940feb580a96..e876241f385e 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -4871,7 +4871,7 @@ public class StatsPullAtomService extends SystemService { } private int pullCachedAppsHighWatermark(int atomTag, List<StatsEvent> pulledData) { - pulledData.add(LocalServices.getService(ActivityManagerInternal.class) + pulledData.add((StatsEvent) LocalServices.getService(ActivityManagerInternal.class) .getCachedAppsHighWatermarkStats(atomTag, true)); return StatsManager.PULL_SUCCESS; } diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING index 358618a71cbc..004d79964354 100644 --- a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING +++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING @@ -10,10 +10,7 @@ }, { "name": "FrameworksTimeServicesTests" - } - ], - // TODO(b/182461754): Change to "presubmit" when go/test-mapping-slo-guide allows. - "postsubmit": [ + }, { "name": "CtsLocationTimeZoneManagerHostTest" } diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 2bf7075d081c..d172d3fd4139 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -1598,8 +1598,22 @@ public class TrustManagerService extends SystemService { fout.printf(" User \"%s\" (id=%d, flags=%#x)", user.name, user.id, user.flags); if (!user.supportsSwitchToByUser()) { - fout.println("(managed profile)"); - fout.println(" disabled because switching to this user is not possible."); + final boolean locked; + if (user.isProfile()) { + if (mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id)) { + fout.print(" (profile with separate challenge)"); + locked = isDeviceLockedInner(user.id); + } else { + fout.print(" (profile with unified challenge)"); + locked = isDeviceLockedInner(resolveProfileParent(user.id)); + } + } else { + fout.println(" (user that cannot be switched to)"); + locked = isDeviceLockedInner(user.id); + } + fout.println(": deviceLocked=" + dumpBool(locked)); + fout.println( + " Trust agents disabled because switching to this user is not possible."); return; } if (isCurrent) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 6e9219a75324..0d06f5b256b0 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3390,7 +3390,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (currentFocusedApp != null && currentFocusedApp.task == task && topFocusedDisplayId == mDisplayContent.getDisplayId()) { final Task topFocusableTask = mDisplayContent.getTask( - (t) -> t.isLeafTask() && t.isFocusable(), true /* traverseTopToBottom */); + (t) -> t.isLeafTask() && t.isFocusable() && !t.inPinnedWindowingMode(), + true /* traverseTopToBottom */); if (task == topFocusableTask) { if (currentFocusedApp == this) { ProtoLog.d(WM_DEBUG_FOCUS, "moveFocusableActivityToTop: already on top " diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 6f5c676187e1..b8b102faa7d4 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5280,6 +5280,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Applies latest configuration and/or visibility updates if needed. */ boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { + if (starting == null && mTaskSupervisor.isRootVisibilityUpdateDeferred()) { + return true; + } boolean kept = true; final Task mainRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); // mainRootTask is null during startup. diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index e5604eca3df0..424394872821 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -2857,12 +2857,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return false; } - /** Applies the new configuration for the changed displays. */ - void applyDisplayChangeIfNeeded() { + /** + * Applies the new configuration for the changed displays. Returns the activities that should + * check whether to deliver the new configuration to clients. + */ + @Nullable + ArrayList<ActivityRecord> applyDisplayChangeIfNeeded() { + ArrayList<ActivityRecord> activitiesMayChange = null; for (int i = mParticipants.size() - 1; i >= 0; --i) { final WindowContainer<?> wc = mParticipants.valueAt(i); final DisplayContent dc = wc.asDisplayContent(); if (dc == null || !mChanges.get(dc).hasChanged()) continue; + final int originalSeq = dc.getConfiguration().seq; dc.sendNewConfiguration(); // Set to ready if no other change controls the ready state. But if there is, such as // if an activity is pausing, it will call setReady(ar, false) and wait for the next @@ -2871,7 +2877,22 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (!mReadyTrackerOld.mUsed) { setReady(dc, true); } + if (originalSeq == dc.getConfiguration().seq) continue; + // If the update is deferred, sendNewConfiguration won't deliver new configuration to + // clients, then it is the caller's responsibility to deliver the changes. + if (mController.mAtm.mTaskSupervisor.isRootVisibilityUpdateDeferred()) { + if (activitiesMayChange == null) { + activitiesMayChange = new ArrayList<>(); + } + final ArrayList<ActivityRecord> visibleActivities = activitiesMayChange; + dc.forAllActivities(r -> { + if (r.isVisibleRequested()) { + visibleActivities.add(r); + } + }); + } } + return activitiesMayChange; } boolean getLegacyIsReady() { diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java new file mode 100644 index 000000000000..e82dc37c2b6a --- /dev/null +++ b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java @@ -0,0 +1,448 @@ +/* + * Copyright 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.server.wm; + +import static android.graphics.Matrix.MSCALE_X; +import static android.graphics.Matrix.MSCALE_Y; +import static android.graphics.Matrix.MSKEW_X; +import static android.graphics.Matrix.MSKEW_Y; + +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TPL; + +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.IntArray; +import android.util.Pair; +import android.util.Size; +import android.view.InputWindowHandle; +import android.window.ITrustedPresentationListener; +import android.window.TrustedPresentationThresholds; +import android.window.WindowInfosListener; + +import com.android.internal.protolog.common.ProtoLog; +import com.android.server.wm.utils.RegionUtils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Optional; + +/** + * Class to handle TrustedPresentationListener registrations in a thread safe manner. This class + * also takes care of cleaning up listeners when the remote process dies. + */ +public class TrustedPresentationListenerController { + + // Should only be accessed by the posting to the handler + private class Listeners { + private final class ListenerDeathRecipient implements IBinder.DeathRecipient { + IBinder mListenerBinder; + int mInstances; + + ListenerDeathRecipient(IBinder listenerBinder) { + mListenerBinder = listenerBinder; + mInstances = 0; + try { + mListenerBinder.linkToDeath(this, 0); + } catch (RemoteException ignore) { + } + } + + void addInstance() { + mInstances++; + } + + // return true if there are no instances alive + boolean removeInstance() { + mInstances--; + if (mInstances > 0) { + return false; + } + mListenerBinder.unlinkToDeath(this, 0); + return true; + } + + public void binderDied() { + mHandler.post(() -> { + mUniqueListeners.remove(mListenerBinder); + removeListeners(mListenerBinder, Optional.empty()); + }); + } + } + + // tracks binder deaths for cleanup + ArrayMap<IBinder, ListenerDeathRecipient> mUniqueListeners = new ArrayMap<>(); + ArrayMap<IBinder /*window*/, ArrayList<TrustedPresentationInfo>> mWindowToListeners = + new ArrayMap<>(); + + void register(IBinder window, ITrustedPresentationListener listener, + TrustedPresentationThresholds thresholds, int id) { + var listenersForWindow = mWindowToListeners.computeIfAbsent(window, + iBinder -> new ArrayList<>()); + listenersForWindow.add(new TrustedPresentationInfo(thresholds, id, listener)); + + // register death listener + var listenerBinder = listener.asBinder(); + var deathRecipient = mUniqueListeners.computeIfAbsent(listenerBinder, + ListenerDeathRecipient::new); + deathRecipient.addInstance(); + } + + void unregister(ITrustedPresentationListener trustedPresentationListener, int id) { + var listenerBinder = trustedPresentationListener.asBinder(); + var deathRecipient = mUniqueListeners.get(listenerBinder); + if (deathRecipient == null) { + ProtoLog.e(WM_DEBUG_TPL, "unregister failed, couldn't find" + + " deathRecipient for %s with id=%d", trustedPresentationListener, id); + return; + } + + if (deathRecipient.removeInstance()) { + mUniqueListeners.remove(listenerBinder); + } + removeListeners(listenerBinder, Optional.of(id)); + } + + boolean isEmpty() { + return mWindowToListeners.isEmpty(); + } + + ArrayList<TrustedPresentationInfo> get(IBinder windowToken) { + return mWindowToListeners.get(windowToken); + } + + private void removeListeners(IBinder listenerBinder, Optional<Integer> id) { + for (int i = mWindowToListeners.size() - 1; i >= 0; i--) { + var listeners = mWindowToListeners.valueAt(i); + for (int j = listeners.size() - 1; j >= 0; j--) { + var listener = listeners.get(j); + if (listener.mListener.asBinder() == listenerBinder && (id.isEmpty() + || listener.mId == id.get())) { + listeners.remove(j); + } + } + if (listeners.isEmpty()) { + mWindowToListeners.removeAt(i); + } + } + } + } + + private final Object mHandlerThreadLock = new Object(); + private HandlerThread mHandlerThread; + private Handler mHandler; + + private WindowInfosListener mWindowInfosListener; + + Listeners mRegisteredListeners = new Listeners(); + + private InputWindowHandle[] mLastWindowHandles; + + private final Object mIgnoredWindowTokensLock = new Object(); + + private final ArraySet<IBinder> mIgnoredWindowTokens = new ArraySet<>(); + + private void startHandlerThreadIfNeeded() { + synchronized (mHandlerThreadLock) { + if (mHandler == null) { + mHandlerThread = new HandlerThread("WindowInfosListenerForTpl"); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } + } + } + + void addIgnoredWindowTokens(IBinder token) { + synchronized (mIgnoredWindowTokensLock) { + mIgnoredWindowTokens.add(token); + } + } + + void removeIgnoredWindowTokens(IBinder token) { + synchronized (mIgnoredWindowTokensLock) { + mIgnoredWindowTokens.remove(token); + } + } + + void registerListener(IBinder window, ITrustedPresentationListener listener, + TrustedPresentationThresholds thresholds, int id) { + startHandlerThreadIfNeeded(); + mHandler.post(() -> { + ProtoLog.d(WM_DEBUG_TPL, "Registering listener=%s with id=%d for window=%s with %s", + listener, id, window, thresholds); + + mRegisteredListeners.register(window, listener, thresholds, id); + registerWindowInfosListener(); + // Update the initial state for the new registered listener + computeTpl(mLastWindowHandles); + }); + } + + void unregisterListener(ITrustedPresentationListener listener, int id) { + startHandlerThreadIfNeeded(); + mHandler.post(() -> { + ProtoLog.d(WM_DEBUG_TPL, "Unregistering listener=%s with id=%d", + listener, id); + + mRegisteredListeners.unregister(listener, id); + if (mRegisteredListeners.isEmpty()) { + unregisterWindowInfosListener(); + } + }); + } + + void dump(PrintWriter pw) { + final String innerPrefix = " "; + pw.println("TrustedPresentationListenerController:"); + pw.println(innerPrefix + "Active unique listeners (" + + mRegisteredListeners.mUniqueListeners.size() + "):"); + for (int i = 0; i < mRegisteredListeners.mWindowToListeners.size(); i++) { + pw.println( + innerPrefix + " window=" + mRegisteredListeners.mWindowToListeners.keyAt(i)); + final var listeners = mRegisteredListeners.mWindowToListeners.valueAt(i); + for (int j = 0; j < listeners.size(); j++) { + final var listener = listeners.get(j); + pw.println(innerPrefix + innerPrefix + " listener=" + listener.mListener.asBinder() + + " id=" + listener.mId + + " thresholds=" + listener.mThresholds); + } + } + } + + private void registerWindowInfosListener() { + if (mWindowInfosListener != null) { + return; + } + + mWindowInfosListener = new WindowInfosListener() { + @Override + public void onWindowInfosChanged(InputWindowHandle[] windowHandles, + DisplayInfo[] displayInfos) { + mHandler.post(() -> computeTpl(windowHandles)); + } + }; + mLastWindowHandles = mWindowInfosListener.register().first; + } + + private void unregisterWindowInfosListener() { + if (mWindowInfosListener == null) { + return; + } + + mWindowInfosListener.unregister(); + mWindowInfosListener = null; + mLastWindowHandles = null; + } + + private void computeTpl(InputWindowHandle[] windowHandles) { + mLastWindowHandles = windowHandles; + if (mLastWindowHandles == null || mLastWindowHandles.length == 0 + || mRegisteredListeners.isEmpty()) { + return; + } + + Rect tmpRect = new Rect(); + Matrix tmpInverseMatrix = new Matrix(); + float[] tmpMatrix = new float[9]; + Region coveredRegionsAbove = new Region(); + long currTimeMs = System.currentTimeMillis(); + ProtoLog.v(WM_DEBUG_TPL, "Checking %d windows", mLastWindowHandles.length); + + ArrayMap<ITrustedPresentationListener, Pair<IntArray, IntArray>> listenerUpdates = + new ArrayMap<>(); + ArraySet<IBinder> ignoredWindowTokens; + synchronized (mIgnoredWindowTokensLock) { + ignoredWindowTokens = new ArraySet<>(mIgnoredWindowTokens); + } + for (var windowHandle : mLastWindowHandles) { + if (ignoredWindowTokens.contains(windowHandle.getWindowToken())) { + ProtoLog.v(WM_DEBUG_TPL, "Skipping %s", windowHandle.name); + continue; + } + tmpRect.set(windowHandle.frame); + var listeners = mRegisteredListeners.get(windowHandle.getWindowToken()); + if (listeners != null) { + Region region = new Region(); + region.op(tmpRect, coveredRegionsAbove, Region.Op.DIFFERENCE); + windowHandle.transform.invert(tmpInverseMatrix); + tmpInverseMatrix.getValues(tmpMatrix); + float scaleX = (float) Math.sqrt(tmpMatrix[MSCALE_X] * tmpMatrix[MSCALE_X] + + tmpMatrix[MSKEW_X] * tmpMatrix[MSKEW_X]); + float scaleY = (float) Math.sqrt(tmpMatrix[MSCALE_Y] * tmpMatrix[MSCALE_Y] + + tmpMatrix[MSKEW_Y] * tmpMatrix[MSKEW_Y]); + + float fractionRendered = computeFractionRendered(region, new RectF(tmpRect), + windowHandle.contentSize, + scaleX, scaleY); + + checkIfInThreshold(listeners, listenerUpdates, fractionRendered, windowHandle.alpha, + currTimeMs); + } + + coveredRegionsAbove.op(tmpRect, Region.Op.UNION); + ProtoLog.v(WM_DEBUG_TPL, "coveredRegionsAbove updated with %s frame:%s region:%s", + windowHandle.name, tmpRect.toShortString(), coveredRegionsAbove); + } + + for (int i = 0; i < listenerUpdates.size(); i++) { + var updates = listenerUpdates.valueAt(i); + var listener = listenerUpdates.keyAt(i); + try { + listener.onTrustedPresentationChanged(updates.first.toArray(), + updates.second.toArray()); + } catch (RemoteException ignore) { + } + } + } + + private void addListenerUpdate( + ArrayMap<ITrustedPresentationListener, Pair<IntArray, IntArray>> listenerUpdates, + ITrustedPresentationListener listener, int id, boolean presentationState) { + var updates = listenerUpdates.get(listener); + if (updates == null) { + updates = new Pair<>(new IntArray(), new IntArray()); + listenerUpdates.put(listener, updates); + } + if (presentationState) { + updates.first.add(id); + } else { + updates.second.add(id); + } + } + + + private void checkIfInThreshold( + ArrayList<TrustedPresentationInfo> listeners, + ArrayMap<ITrustedPresentationListener, Pair<IntArray, IntArray>> listenerUpdates, + float fractionRendered, float alpha, long currTimeMs) { + ProtoLog.v(WM_DEBUG_TPL, "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d", + fractionRendered, alpha, currTimeMs); + for (int i = 0; i < listeners.size(); i++) { + var trustedPresentationInfo = listeners.get(i); + var listener = trustedPresentationInfo.mListener; + boolean lastState = trustedPresentationInfo.mLastComputedTrustedPresentationState; + boolean newState = + (alpha >= trustedPresentationInfo.mThresholds.mMinAlpha) && (fractionRendered + >= trustedPresentationInfo.mThresholds.mMinFractionRendered); + trustedPresentationInfo.mLastComputedTrustedPresentationState = newState; + + ProtoLog.v(WM_DEBUG_TPL, + "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f " + + "minFractionRendered=%f", + lastState, newState, alpha, trustedPresentationInfo.mThresholds.mMinAlpha, + fractionRendered, trustedPresentationInfo.mThresholds.mMinFractionRendered); + + if (lastState && !newState) { + // We were in the trusted presentation state, but now we left it, + // emit the callback if needed + if (trustedPresentationInfo.mLastReportedTrustedPresentationState) { + trustedPresentationInfo.mLastReportedTrustedPresentationState = false; + addListenerUpdate(listenerUpdates, listener, + trustedPresentationInfo.mId, /*presentationState*/ false); + ProtoLog.d(WM_DEBUG_TPL, "Adding untrusted state listener=%s with id=%d", + listener, trustedPresentationInfo.mId); + } + // Reset the timer + trustedPresentationInfo.mEnteredTrustedPresentationStateTime = -1; + } else if (!lastState && newState) { + // We were not in the trusted presentation state, but we entered it, begin the timer + // and make sure this gets called at least once more! + trustedPresentationInfo.mEnteredTrustedPresentationStateTime = currTimeMs; + mHandler.postDelayed(() -> { + computeTpl(mLastWindowHandles); + }, (long) (trustedPresentationInfo.mThresholds.mStabilityRequirementMs * 1.5)); + } + + // Has the timer elapsed, but we are still in the state? Emit a callback if needed + if (!trustedPresentationInfo.mLastReportedTrustedPresentationState && newState && ( + currTimeMs - trustedPresentationInfo.mEnteredTrustedPresentationStateTime + > trustedPresentationInfo.mThresholds.mStabilityRequirementMs)) { + trustedPresentationInfo.mLastReportedTrustedPresentationState = true; + addListenerUpdate(listenerUpdates, listener, + trustedPresentationInfo.mId, /*presentationState*/ true); + ProtoLog.d(WM_DEBUG_TPL, "Adding trusted state listener=%s with id=%d", + listener, trustedPresentationInfo.mId); + } + } + } + + private float computeFractionRendered(Region visibleRegion, RectF screenBounds, + Size contentSize, + float sx, float sy) { + ProtoLog.v(WM_DEBUG_TPL, + "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s " + + "scale=%f,%f", + visibleRegion, screenBounds, contentSize, sx, sy); + + if (contentSize.getWidth() == 0 || contentSize.getHeight() == 0) { + return -1; + } + if (screenBounds.width() == 0 || screenBounds.height() == 0) { + return -1; + } + + float fractionRendered = Math.min(sx * sy, 1.0f); + ProtoLog.v(WM_DEBUG_TPL, "fractionRendered scale=%f", fractionRendered); + + float boundsOverSourceW = screenBounds.width() / (float) contentSize.getWidth(); + float boundsOverSourceH = screenBounds.height() / (float) contentSize.getHeight(); + fractionRendered *= boundsOverSourceW * boundsOverSourceH; + ProtoLog.v(WM_DEBUG_TPL, "fractionRendered boundsOverSource=%f", fractionRendered); + // Compute the size of all the rects since they may be disconnected. + float[] visibleSize = new float[1]; + RegionUtils.forEachRect(visibleRegion, rect -> { + float size = rect.width() * rect.height(); + visibleSize[0] += size; + }); + + fractionRendered *= visibleSize[0] / (screenBounds.width() * screenBounds.height()); + return fractionRendered; + } + + private static class TrustedPresentationInfo { + boolean mLastComputedTrustedPresentationState = false; + boolean mLastReportedTrustedPresentationState = false; + long mEnteredTrustedPresentationStateTime = -1; + final TrustedPresentationThresholds mThresholds; + + final ITrustedPresentationListener mListener; + final int mId; + + private TrustedPresentationInfo(TrustedPresentationThresholds thresholds, int id, + ITrustedPresentationListener listener) { + mThresholds = thresholds; + mId = id; + mListener = listener; + checkValid(thresholds); + } + + private void checkValid(TrustedPresentationThresholds thresholds) { + if (thresholds.mMinAlpha <= 0 || thresholds.mMinFractionRendered <= 0 + || thresholds.mStabilityRequirementMs < 1) { + throw new IllegalArgumentException( + "TrustedPresentationThresholds values are invalid"); + } + } + } +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0d2c94d103fb..0c57036a3b02 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -303,9 +303,11 @@ import android.window.AddToSurfaceSyncGroupResult; import android.window.ClientWindowFrames; import android.window.ISurfaceSyncGroupCompletedListener; import android.window.ITaskFpsCallback; +import android.window.ITrustedPresentationListener; import android.window.ScreenCapture; import android.window.SystemPerformanceHinter; import android.window.TaskSnapshot; +import android.window.TrustedPresentationThresholds; import android.window.WindowContainerToken; import android.window.WindowContextInfo; @@ -764,6 +766,9 @@ public class WindowManagerService extends IWindowManager.Stub private final SurfaceSyncGroupController mSurfaceSyncGroupController = new SurfaceSyncGroupController(); + final TrustedPresentationListenerController mTrustedPresentationListenerController = + new TrustedPresentationListenerController(); + @VisibleForTesting final class SettingsObserver extends ContentObserver { private final Uri mDisplayInversionEnabledUri = @@ -7171,6 +7176,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(separator); } mSystemPerformanceHinter.dump(pw, ""); + mTrustedPresentationListenerController.dump(pw); } } @@ -9771,4 +9777,17 @@ public class WindowManagerService extends IWindowManager.Stub Binder.restoreCallingIdentity(origId); } } + + @Override + public void registerTrustedPresentationListener(IBinder window, + ITrustedPresentationListener listener, + TrustedPresentationThresholds thresholds, int id) { + mTrustedPresentationListenerController.registerListener(window, listener, thresholds, id); + } + + @Override + public void unregisterTrustedPresentationListener(ITrustedPresentationListener listener, + int id) { + mTrustedPresentationListenerController.unregisterListener(listener, id); + } } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 2af656942a2a..a872fd0baaae 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -570,8 +570,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mService.deferWindowLayout(); mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */); try { - if (transition != null) { - transition.applyDisplayChangeIfNeeded(); + final ArrayList<ActivityRecord> activitiesMayChange = + transition != null ? transition.applyDisplayChangeIfNeeded() : null; + if (activitiesMayChange != null) { + effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; } final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps(); final int hopSize = hops.size(); @@ -695,8 +697,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(r -> { r.ensureActivityConfiguration(0, PRESERVE_WINDOWS); + if (activitiesMayChange != null) { + activitiesMayChange.remove(r); + } }); } + // TODO(b/258618073): Combine with haveConfigChanges after confirming that there + // is no problem to always preserve window. Currently this uses the parameters + // as ATMS#ensureConfigAndVisibilityAfterUpdate. + if (activitiesMayChange != null) { + for (int i = activitiesMayChange.size() - 1; i >= 0; --i) { + final ActivityRecord ar = activitiesMayChange.get(i); + if (!ar.isVisibleRequested()) continue; + ar.ensureActivityConfiguration(0 /* globalChanges */, + !PRESERVE_WINDOWS, true /* ignoreVisibility */, + false /* isRequestedOrientationChanged */); + } + } } if (effects != 0) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e1f1f662c5aa..7bc7e2cb780b 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1189,6 +1189,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow); parentWindow.addChild(this, sWindowSubLayerComparator); } + + if (token.mRoundedCornerOverlay) { + mWmService.mTrustedPresentationListenerController.addIgnoredWindowTokens( + getWindowToken()); + } } @Override @@ -2393,6 +2398,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } mWmService.postWindowRemoveCleanupLocked(this); + + mWmService.mTrustedPresentationListenerController.removeIgnoredWindowTokens( + getWindowToken()); } @Override diff --git a/services/core/jni/com_android_server_hint_HintManagerService.cpp b/services/core/jni/com_android_server_hint_HintManagerService.cpp index 7edf445d7604..ccd9bd0a50ca 100644 --- a/services/core/jni/com_android_server_hint_HintManagerService.cpp +++ b/services/core/jni/com_android_server_hint_HintManagerService.cpp @@ -20,6 +20,7 @@ #include <aidl/android/hardware/power/IPower.h> #include <android-base/stringprintf.h> +#include <inttypes.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedPrimitiveArray.h> #include <powermanager/PowerHalController.h> @@ -38,6 +39,15 @@ using android::base::StringPrintf; namespace android { +static struct { + jclass clazz{}; + jfieldID workPeriodStartTimestampNanos{}; + jfieldID actualTotalDurationNanos{}; + jfieldID actualCpuDurationNanos{}; + jfieldID actualGpuDurationNanos{}; + jfieldID timestampNanos{}; +} gWorkDurationInfo; + static power::PowerHalController gPowerHalController; static std::unordered_map<jlong, std::shared_ptr<IPowerHintSession>> gSessionMap; static std::mutex gSessionMapLock; @@ -180,6 +190,26 @@ static void nativeSetMode(JNIEnv* env, jclass /* clazz */, jlong session_ptr, ji setMode(session_ptr, static_cast<SessionMode>(mode), enabled); } +static void nativeReportActualWorkDuration2(JNIEnv* env, jclass /* clazz */, jlong session_ptr, + jobjectArray jWorkDurations) { + int size = env->GetArrayLength(jWorkDurations); + std::vector<WorkDuration> workDurations(size); + for (int i = 0; i < size; i++) { + jobject workDuration = env->GetObjectArrayElement(jWorkDurations, i); + workDurations[i].workPeriodStartTimestampNanos = + env->GetLongField(workDuration, gWorkDurationInfo.workPeriodStartTimestampNanos); + workDurations[i].durationNanos = + env->GetLongField(workDuration, gWorkDurationInfo.actualTotalDurationNanos); + workDurations[i].cpuDurationNanos = + env->GetLongField(workDuration, gWorkDurationInfo.actualCpuDurationNanos); + workDurations[i].gpuDurationNanos = + env->GetLongField(workDuration, gWorkDurationInfo.actualGpuDurationNanos); + workDurations[i].timeStampNanos = + env->GetLongField(workDuration, gWorkDurationInfo.timestampNanos); + } + reportActualWorkDuration(session_ptr, workDurations); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sHintManagerServiceMethods[] = { /* name, signature, funcPtr */ @@ -194,9 +224,23 @@ static const JNINativeMethod sHintManagerServiceMethods[] = { {"nativeSendHint", "(JI)V", (void*)nativeSendHint}, {"nativeSetThreads", "(J[I)V", (void*)nativeSetThreads}, {"nativeSetMode", "(JIZ)V", (void*)nativeSetMode}, + {"nativeReportActualWorkDuration", "(J[Landroid/os/WorkDuration;)V", + (void*)nativeReportActualWorkDuration2}, }; int register_android_server_HintManagerService(JNIEnv* env) { + gWorkDurationInfo.clazz = env->FindClass("android/os/WorkDuration"); + gWorkDurationInfo.workPeriodStartTimestampNanos = + env->GetFieldID(gWorkDurationInfo.clazz, "mWorkPeriodStartTimestampNanos", "J"); + gWorkDurationInfo.actualTotalDurationNanos = + env->GetFieldID(gWorkDurationInfo.clazz, "mActualTotalDurationNanos", "J"); + gWorkDurationInfo.actualCpuDurationNanos = + env->GetFieldID(gWorkDurationInfo.clazz, "mActualCpuDurationNanos", "J"); + gWorkDurationInfo.actualGpuDurationNanos = + env->GetFieldID(gWorkDurationInfo.clazz, "mActualGpuDurationNanos", "J"); + gWorkDurationInfo.timestampNanos = + env->GetFieldID(gWorkDurationInfo.clazz, "mTimestampNanos", "J"); + return jniRegisterNativeMethods(env, "com/android/server/power/hint/" "HintManagerService$NativeWrapper", diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 627461a2c6ed..4a2e1cba5cce 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -65,6 +65,7 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.content.PackageMonitor; import com.android.server.credentials.metrics.ApiName; import com.android.server.credentials.metrics.ApiStatus; import com.android.server.infra.AbstractMasterSystemService; @@ -101,6 +102,13 @@ public final class CredentialManagerService private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API = "enable_credential_description_api"; + /** + * Value stored in autofill pref when credential provider is primary. This is + * used as a placeholder since a credman only provider will not have an + * autofill service. + */ + public static final String AUTOFILL_PLACEHOLDER_VALUE = "credential-provider"; + private final Context mContext; /** Cache of system service list per user id. */ @@ -194,6 +202,8 @@ public final class CredentialManagerService @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) { + updateProvidersWhenPackageRemoved(mContext, packageName); + List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); if (services == null) { return; @@ -216,8 +226,6 @@ public final class CredentialManagerService for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) { removeServiceFromCache(serviceToBeRemoved, userId); removeServiceFromSystemServicesCache(serviceToBeRemoved, userId); - removeServiceFromMultiModeSettings(serviceToBeRemoved.getComponentName() - .flattenToString(), userId); CredentialDescriptionRegistry.forUser(userId) .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName()); } @@ -1114,4 +1122,101 @@ public final class CredentialManagerService mRequestSessions.get(userId).put(token, requestSession); } } + + /** Updates the list of providers when an app is uninstalled. */ + public static void updateProvidersWhenPackageRemoved(Context context, String packageName) { + // Get the current providers. + String rawProviders = + Settings.Secure.getStringForUser( + context.getContentResolver(), + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + UserHandle.myUserId()); + if (rawProviders == null) { + Slog.w(TAG, "settings key is null"); + return; + } + + // Remove any providers from the primary setting that contain the package name + // being removed. + Set<String> primaryProviders = + getStoredProviders(rawProviders, packageName); + if (!Settings.Secure.putString( + context.getContentResolver(), + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + String.join(":", primaryProviders))) { + Slog.w(TAG, "Failed to remove primary package: " + packageName); + return; + } + + // Read the autofill provider so we don't accidentally erase it. + String autofillProvider = + Settings.Secure.getStringForUser( + context.getContentResolver(), + Settings.Secure.AUTOFILL_SERVICE, + UserHandle.myUserId()); + + // If there is an autofill provider and it is the placeholder indicating + // that the currently selected primary provider does not support autofill + // then we should wipe the setting to keep it in sync. + if (autofillProvider != null && primaryProviders.isEmpty()) { + if (autofillProvider.equals(AUTOFILL_PLACEHOLDER_VALUE)) { + if (!Settings.Secure.putString( + context.getContentResolver(), + Settings.Secure.AUTOFILL_SERVICE, + "")) { + Slog.w(TAG, "Failed to remove autofill package: " + packageName); + } + } else { + // If the existing autofill provider is from the app being removed + // then erase the autofill service setting. + ComponentName cn = ComponentName.unflattenFromString(autofillProvider); + if (cn != null && cn.getPackageName().equals(packageName)) { + if (!Settings.Secure.putString( + context.getContentResolver(), + Settings.Secure.AUTOFILL_SERVICE, + "")) { + Slog.w(TAG, "Failed to remove autofill package: " + packageName); + } + } + } + } + + // Read the credential providers to remove any reference of the removed app. + String rawCredentialProviders = + Settings.Secure.getStringForUser( + context.getContentResolver(), + Settings.Secure.CREDENTIAL_SERVICE, + UserHandle.myUserId()); + + // Remove any providers that belong to the removed app. + Set<String> credentialProviders = + getStoredProviders(rawCredentialProviders, packageName); + if (!Settings.Secure.putString( + context.getContentResolver(), + Settings.Secure.CREDENTIAL_SERVICE, + String.join(":", credentialProviders))) { + Slog.w(TAG, "Failed to remove secondary package: " + packageName); + } + } + + /** Gets the list of stored providers from a string removing any mention of package name. */ + public static Set<String> getStoredProviders(String rawProviders, String packageName) { + // If the app being removed matches any of the package names from + // this list then don't add it in the output. + Set<String> providers = new HashSet<>(); + for (String rawComponentName : rawProviders.split(":")) { + if (TextUtils.isEmpty(rawComponentName) + || rawComponentName.equals("null")) { + Slog.d(TAG, "provider component name is empty or null"); + continue; + } + + ComponentName cn = ComponentName.unflattenFromString(rawComponentName); + if (cn != null && !cn.getPackageName().equals(packageName)) { + providers.add(cn.flattenToString()); + } + } + + return providers; + } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 1919eb33c38c..59e95e7571d0 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -268,6 +268,8 @@ public final class SystemServer implements Dumpable { "com.android.server.backup.BackupManagerService$Lifecycle"; private static final String APPWIDGET_SERVICE_CLASS = "com.android.server.appwidget.AppWidgetService"; + private static final String ARC_PERSISTENT_DATA_BLOCK_SERVICE_CLASS = + "com.android.server.arc.persistent_data_block.ArcPersistentDataBlockService"; private static final String ARC_SYSTEM_HEALTH_SERVICE = "com.android.server.arc.health.ArcSystemHealthService"; private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS = @@ -1489,8 +1491,6 @@ public final class SystemServer implements Dumpable { boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice", false); - boolean isEmulator = SystemProperties.get("ro.boot.qemu").equals("1"); - boolean isWatch = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_WATCH); @@ -1892,6 +1892,12 @@ public final class SystemServer implements Dumpable { t.traceEnd(); } + if (Build.IS_ARC && SystemProperties.getInt("ro.boot.dev_mode", 0) == 1) { + t.traceBegin("StartArcPersistentDataBlock"); + mSystemServiceManager.startService(ARC_PERSISTENT_DATA_BLOCK_SERVICE_CLASS); + t.traceEnd(); + } + t.traceBegin("StartTestHarnessMode"); mSystemServiceManager.startService(TestHarnessModeService.class); t.traceEnd(); @@ -2318,7 +2324,7 @@ public final class SystemServer implements Dumpable { if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST) || mPackageManager.hasSystemFeature( PackageManager.FEATURE_USB_ACCESSORY) - || isEmulator) { + || Build.IS_EMULATOR) { // Manage USB host and device support t.traceBegin("StartUsbService"); mSystemServiceManager.startService(USB_SERVICE_CLASS); diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java index 693cafefa2c0..acd9dceb16d5 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java @@ -727,6 +727,7 @@ public final class DisplayPowerController2Test { } @Test + @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) public void testDisplayBrightnessHdr_SkipAnimationOnHdrAppearance() { Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, @@ -762,6 +763,7 @@ public final class DisplayPowerController2Test { } @Test + @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) public void testDisplayBrightnessHdr_SkipAnimationOnHdrRemoval() { Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index b22799377872..50b0e167ef99 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -1202,6 +1202,7 @@ public final class DisplayPowerControllerTest { } @Test + @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) public void testDisplayBrightnessHdr_SkipAnimationOnHdrAppearance() { Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, @@ -1236,6 +1237,7 @@ public final class DisplayPowerControllerTest { } @Test + @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) public void testDisplayBrightnessHdr_SkipAnimationOnHdrRemoval() { Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java index 72dc7259dc1f..4ba9d60a5abf 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java @@ -17,7 +17,6 @@ package com.android.server.am; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -44,6 +43,9 @@ import android.util.SparseArray; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.internal.util.FrameworkStatsLog; +import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.server.AlarmManagerInternal; import com.android.server.DropBoxManagerInternal; import com.android.server.LocalServices; @@ -85,6 +87,12 @@ public abstract class BaseBroadcastQueueTest { public final ApplicationExitInfoTest.ServiceThreadRule mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule(); + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .spyStatic(FrameworkStatsLog.class) + .spyStatic(ProcessList.class) + .build(); + @Mock AppOpsService mAppOpsService; @Mock @@ -140,6 +148,7 @@ public abstract class BaseBroadcastQueueTest { realAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper()); realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal()); realAms.mOomAdjuster = spy(realAms.mOomAdjuster); + ExtendedMockito.doNothing().when(() -> ProcessList.setOomAdj(anyInt(), anyInt(), anyInt())); realAms.mPackageManagerInt = mPackageManagerInt; realAms.mUsageStatsService = mUsageStatsManagerInt; realAms.mProcessesReady = true; diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 2378416f8bd0..c03799d8b41f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -79,11 +79,9 @@ import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.internal.util.FrameworkStatsLog; -import com.android.modules.utils.testing.ExtendedMockitoRule; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; @@ -112,11 +110,6 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest { BroadcastProcessQueue mHead; - @Rule - public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) - .spyStatic(FrameworkStatsLog.class) - .build(); - @Before public void setUp() throws Exception { super.setUp(); diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 646f4862d75d..79b39b82ee56 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -20,7 +20,9 @@ import static android.app.AppOpsManager.MODE_ERRORED; import static android.app.AppOpsManager.OP_COARSE_LOCATION; import static android.app.AppOpsManager.OP_FLAGS_ALL; import static android.app.AppOpsManager.OP_FLAG_SELF; +import static android.app.AppOpsManager.OP_READ_DEVICE_IDENTIFIERS; import static android.app.AppOpsManager.OP_READ_SMS; +import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS; import static android.app.AppOpsManager.OP_WIFI_SCAN; import static android.app.AppOpsManager.OP_WRITE_SMS; import static android.os.UserHandle.getAppId; @@ -49,8 +51,10 @@ import static org.mockito.ArgumentMatchers.nullable; import android.app.AppOpsManager; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; +import android.app.SyncNotedAppOp; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.os.Handler; import android.os.HandlerThread; @@ -58,6 +62,7 @@ import android.os.Process; import android.permission.PermissionManager; import android.provider.Settings; import android.util.ArrayMap; +import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -79,7 +84,6 @@ import org.junit.runner.RunWith; import org.mockito.quality.Strictness; import java.io.File; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -99,12 +103,15 @@ public class AppOpsServiceTest { private static final Context sContext = InstrumentationRegistry.getTargetContext(); private static final String sMyPackageName = sContext.getOpPackageName(); + private static final String sSdkSandboxPackageName = sContext.getPackageManager() + .getSdkSandboxPackageName(); private File mStorageFile; private File mRecentAccessesFile; private Handler mHandler; private AppOpsService mAppOpsService; private int mMyUid; + private int mSdkSandboxPackageUid; private long mTestStartMillis; private StaticMockitoSession mMockingSession; @@ -132,6 +139,7 @@ public class AppOpsServiceTest { handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); mMyUid = Process.myUid(); + mSdkSandboxPackageUid = resolveSdkSandboxPackageUid(); initializeStaticMocks(); @@ -152,6 +160,39 @@ public class AppOpsServiceTest { mMockingSession.finishMocking(); } + private static int resolveSdkSandboxPackageUid() { + try { + return sContext.getPackageManager().getPackageUid( + sSdkSandboxPackageName, + PackageManager.PackageInfoFlags.of(0) + ); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Can't resolve sandbox package uid", e); + return Process.INVALID_UID; + } + } + + private static void mockGetPackage( + PackageManagerInternal managerMock, + String packageName + ) { + AndroidPackage packageMock = mock(AndroidPackage.class); + when(managerMock.getPackage(packageName)).thenReturn(packageMock); + } + + private static void mockGetPackageStateInternal( + PackageManagerInternal managerMock, + String packageName, + int uid + ) { + PackageStateInternal packageStateInternalMock = mock(PackageStateInternal.class); + when(packageStateInternalMock.isPrivileged()).thenReturn(false); + when(packageStateInternalMock.getAppId()).thenReturn(uid); + when(packageStateInternalMock.getAndroidPackage()).thenReturn(mock(AndroidPackage.class)); + when(managerMock.getPackageStateInternal(packageName)) + .thenReturn(packageStateInternalMock); + } + private void initializeStaticMocks() { mMockingSession = mockitoSession() .strictness(Strictness.LENIENT) @@ -163,16 +204,11 @@ public class AppOpsServiceTest { // Mock LocalServices.getService(PackageManagerInternal.class).getPackageStateInternal // and getPackage dependency needed by AppOpsService PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class); - AndroidPackage mockMyPkg = mock(AndroidPackage.class); - when(mockMyPkg.getAttributions()).thenReturn(Collections.emptyList()); - PackageStateInternal mockMyPSInternal = mock(PackageStateInternal.class); - when(mockMyPSInternal.isPrivileged()).thenReturn(false); - when(mockMyPSInternal.getAppId()).thenReturn(mMyUid); - when(mockMyPSInternal.getAndroidPackage()).thenReturn(mockMyPkg); - - when(mockPackageManagerInternal.getPackageStateInternal(sMyPackageName)) - .thenReturn(mockMyPSInternal); - when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg); + mockGetPackage(mockPackageManagerInternal, sMyPackageName); + mockGetPackageStateInternal(mockPackageManagerInternal, sMyPackageName, mMyUid); + mockGetPackage(mockPackageManagerInternal, sSdkSandboxPackageName); + mockGetPackageStateInternal(mockPackageManagerInternal, sSdkSandboxPackageName, + mSdkSandboxPackageUid); when(mockPackageManagerInternal.getPackageUid(eq(sMyPackageName), anyLong(), eq(getUserId(mMyUid)))).thenReturn(mMyUid); doReturn(mockPackageManagerInternal).when( @@ -233,6 +269,21 @@ public class AppOpsServiceTest { assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED); } + @Test + public void testNoteOperationFromSdkSandbox() { + int sandboxUid = Process.toSdkSandboxUid(mMyUid); + + // Note an op that's allowed. + SyncNotedAppOp allowedResult = mAppOpsService.noteOperation(OP_TAKE_AUDIO_FOCUS, sandboxUid, + sSdkSandboxPackageName, null, false, null, false); + assertThat(allowedResult.getOpMode()).isEqualTo(MODE_ALLOWED); + + // Note another op that's not allowed. + SyncNotedAppOp erroredResult = mAppOpsService.noteOperation(OP_READ_DEVICE_IDENTIFIERS, + sandboxUid, sSdkSandboxPackageName, null, false, null, false); + assertThat(erroredResult.getOpMode()).isEqualTo(MODE_ERRORED); + } + /** * Tests the scenario where an operation's permission is controlled by another operation. * For example the results of a WIFI_SCAN can be used to infer the location of a user, so the diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java index e5291d31d524..eaf0ffdc3cbd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java @@ -113,7 +113,7 @@ public class JobSchedulerServiceTest { } @Before - public void setUp() { + public void setUp() throws Exception { mMockingSession = mockitoSession() .initMocks(this) .strictness(Strictness.LENIENT) @@ -178,6 +178,7 @@ public class JobSchedulerServiceTest { when(mContext.getSystemService(UiModeManager.class)).thenReturn(mock(UiModeManager.class)); mService = new TestJobSchedulerService(mContext); + mService.waitOnAsyncLoadingForTesting(); } @After diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java index 3ba5d1eccaa1..d4ef64703ae2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java @@ -109,6 +109,7 @@ public class BatteryControllerTest { mFlexibilityController = new FlexibilityController(mJobSchedulerService, mock(PrefetchController.class)); mBatteryController = new BatteryController(mJobSchedulerService, mFlexibilityController); + mBatteryController.startTrackingLocked(); verify(mContext).registerReceiver(receiverCaptor.capture(), ArgumentMatchers.argThat(filter -> diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java index debc69604690..4fb9472021c5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java @@ -70,6 +70,8 @@ import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobStore; +import libcore.junit.util.compat.CoreCompatChangeRule; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -269,19 +271,19 @@ public class FlexibilityControllerTest { @Test public void testOnConstantsUpdated_PercentsToDropConstraintsInvalidValues() { - JobInfo.Builder jb = createJob(0).setOverrideDeadline(100L); + JobInfo.Builder jb = createJob(0).setOverrideDeadline(HOUR_IN_MILLIS); JobStatus js = createJobStatus("testPercentsToDropConstraintsConfig", jb); - js.enqueueTime = 100L; - assertEquals(150L, + js.enqueueTime = JobSchedulerService.sElapsedRealtimeClock.millis(); + assertEquals(js.enqueueTime + HOUR_IN_MILLIS / 2, mFlexibilityController.getNextConstraintDropTimeElapsedLocked(js)); setDeviceConfigString(KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS, "10,20a,030,40"); - assertEquals(150L, + assertEquals(js.enqueueTime + HOUR_IN_MILLIS / 2, mFlexibilityController.getNextConstraintDropTimeElapsedLocked(js)); setDeviceConfigString(KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS, "10,40"); - assertEquals(150L, + assertEquals(js.enqueueTime + HOUR_IN_MILLIS / 2, mFlexibilityController.getNextConstraintDropTimeElapsedLocked(js)); setDeviceConfigString(KEY_PERCENTS_TO_DROP_NUM_FLEXIBLE_CONSTRAINTS, "50,40,10,40"); - assertEquals(150L, + assertEquals(js.enqueueTime + HOUR_IN_MILLIS / 2, mFlexibilityController.getNextConstraintDropTimeElapsedLocked(js)); } @@ -369,7 +371,7 @@ public class FlexibilityControllerTest { @Test public void testCurPercent() { - long deadline = 1000; + long deadline = 100 * MINUTE_IN_MILLIS; long nowElapsed; JobInfo.Builder jb = createJob(0).setOverrideDeadline(deadline); JobStatus js = createJobStatus("time", jb); @@ -377,17 +379,17 @@ public class FlexibilityControllerTest { assertEquals(FROZEN_TIME, mFlexibilityController.getLifeCycleBeginningElapsedLocked(js)); assertEquals(deadline + FROZEN_TIME, mFlexibilityController.getLifeCycleEndElapsedLocked(js, FROZEN_TIME)); - nowElapsed = 600 + FROZEN_TIME; + nowElapsed = FROZEN_TIME + 60 * MINUTE_IN_MILLIS; JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); assertEquals(60, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); - nowElapsed = 1400; + nowElapsed = FROZEN_TIME + 130 * MINUTE_IN_MILLIS; JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); assertEquals(100, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); - nowElapsed = 950 + FROZEN_TIME; + nowElapsed = FROZEN_TIME + 95 * MINUTE_IN_MILLIS; JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); assertEquals(95, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); @@ -395,8 +397,8 @@ public class FlexibilityControllerTest { nowElapsed = FROZEN_TIME; JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); - long delay = 100; - deadline = 1100; + long delay = MINUTE_IN_MILLIS; + deadline = 101 * MINUTE_IN_MILLIS; jb = createJob(0).setOverrideDeadline(deadline).setMinimumLatency(delay); js = createJobStatus("time", jb); @@ -405,18 +407,18 @@ public class FlexibilityControllerTest { assertEquals(deadline + FROZEN_TIME, mFlexibilityController.getLifeCycleEndElapsedLocked(js, FROZEN_TIME + delay)); - nowElapsed = 600 + FROZEN_TIME + delay; + nowElapsed = FROZEN_TIME + delay + 60 * MINUTE_IN_MILLIS; JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); assertEquals(60, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); - nowElapsed = 1400; + nowElapsed = FROZEN_TIME + 130 * MINUTE_IN_MILLIS; JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); assertEquals(100, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); - nowElapsed = 950 + FROZEN_TIME + delay; + nowElapsed = FROZEN_TIME + delay + 95 * MINUTE_IN_MILLIS; JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC); assertEquals(95, mFlexibilityController.getCurPercentOfLifecycleLocked(js, nowElapsed)); @@ -541,20 +543,20 @@ public class FlexibilityControllerTest { @Test public void testGetLifeCycleEndElapsedLocked_NonPrefetch() { // deadline - JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000L); + JobInfo.Builder jb = createJob(0).setOverrideDeadline(HOUR_IN_MILLIS); JobStatus js = createJobStatus("time", jb); - assertEquals(1000L + FROZEN_TIME, + assertEquals(HOUR_IN_MILLIS + FROZEN_TIME, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0)); // no deadline jb = createJob(0); js = createJobStatus("time", jb); - assertEquals(100L + DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS, + assertEquals(FROZEN_TIME + DEFAULT_FALLBACK_FLEXIBILITY_DEADLINE_MS, mFlexibilityController.getLifeCycleEndElapsedLocked(js, 100L)); } @Test public void testGetLifeCycleEndElapsedLocked_Rescheduled() { - JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000L); + JobInfo.Builder jb = createJob(0).setOverrideDeadline(HOUR_IN_MILLIS); JobStatus js = createJobStatus("time", jb); js = new JobStatus( js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 0, @@ -693,6 +695,7 @@ public class FlexibilityControllerTest { } @Test + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testExceptions_ShortWindow() { JobInfo.Builder jb = createJob(0); jb.setMinimumLatency(1); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java index 92aa982c3dd1..8397b87706d6 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java @@ -16,6 +16,8 @@ package com.android.server.job.controllers; +import static android.text.format.DateUtils.HOUR_IN_MILLIS; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; @@ -261,7 +263,7 @@ public class JobStatusTest { public void testMediaBackupExemption_lateConstraint() { final JobInfo triggerContentJob = new JobInfo.Builder(42, TEST_JOB_COMPONENT) .addTriggerContentUri(new JobInfo.TriggerContentUri(IMAGES_MEDIA_URI, 0)) - .setOverrideDeadline(12) + .setOverrideDeadline(HOUR_IN_MILLIS) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .build(); when(mJobSchedulerInternal.getCloudMediaProviderPackage(eq(0))).thenReturn(TEST_PACKAGE); @@ -869,7 +871,7 @@ public class JobStatusTest { public void testWouldBeReadyWithConstraint_RequestedOverrideDeadline() { final JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar")) - .setOverrideDeadline(300_000) + .setOverrideDeadline(HOUR_IN_MILLIS) .build(); final JobStatus job = createJobStatus(jobInfo); @@ -1025,7 +1027,7 @@ public class JobStatusTest { final JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar")) .setRequiresCharging(true) - .setOverrideDeadline(300_000) + .setOverrideDeadline(HOUR_IN_MILLIS) .addTriggerContentUri(new JobInfo.TriggerContentUri( MediaStore.Images.Media.INTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)) diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java index 4329b6fbc8e3..1a95d66dd2b0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java @@ -158,6 +158,7 @@ public class PrefetchControllerTest { ArgumentCaptor<EstimatedLaunchTimeChangedListener> eltListenerCaptor = ArgumentCaptor.forClass(EstimatedLaunchTimeChangedListener.class); mPrefetchController = new PrefetchController(mJobSchedulerService); + mPrefetchController.startTrackingLocked(); mPcConstants = mPrefetchController.getPcConstants(); setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS); diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 27efcfabea0c..8fb7bd2a6643 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -48,6 +48,8 @@ import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobSchedulerService.Constants; +import libcore.junit.util.compat.CoreCompatChangeRule; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -141,6 +143,7 @@ public class TimeControllerTest { } @Test + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testMaybeStartTrackingJobLocked_AlreadySatisfied() { JobStatus delaySatisfied = createJobStatus( "testMaybeStartTrackingJobLocked_AlreadySatisfied", @@ -294,6 +297,7 @@ public class TimeControllerTest { runTestMaybeStartTrackingJobLocked_DeadlineInOrder(); } + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) private void runTestMaybeStartTrackingJobLocked_DeadlineInOrder() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -319,6 +323,7 @@ public class TimeControllerTest { } @Test + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testMaybeStartTrackingJobLocked_DeadlineInOrder_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -357,6 +362,7 @@ public class TimeControllerTest { runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder(); } + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) private void runTestMaybeStartTrackingJobLocked_DeadlineReverseOrder() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -387,6 +393,7 @@ public class TimeControllerTest { } @Test + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testMaybeStartTrackingJobLocked_DeadlineReverseOrder_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -535,6 +542,7 @@ public class TimeControllerTest { runTestCheckExpiredDeadlinesAndResetAlarm(); } + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) private void runTestCheckExpiredDeadlinesAndResetAlarm() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -585,6 +593,7 @@ public class TimeControllerTest { } @Test + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testCheckExpiredDeadlinesAndResetAlarm_SomeNotReady() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -740,6 +749,7 @@ public class TimeControllerTest { } @Test + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testEvaluateStateLocked_Deadline() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java index 733a43329478..3e73aa30b1cd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java @@ -45,6 +45,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; @@ -92,6 +93,7 @@ public class PackageArchiverTest { private static final String PACKAGE = "com.example"; private static final String CALLER_PACKAGE = "com.caller"; private static final String INSTALLER_PACKAGE = "com.installer"; + private static final String INSTALLER_LABEL = "Installer"; private static final Path ICON_PATH = Path.of("icon.png"); @Rule @@ -198,6 +200,10 @@ public class PackageArchiverTest { when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getResourcesForApplication(eq(PACKAGE))).thenReturn( mock(Resources.class)); + ApplicationInfo installerAi = mock(ApplicationInfo.class); + when(mComputer.getApplicationInfo(eq(INSTALLER_PACKAGE), anyLong(), anyInt())).thenReturn( + installerAi); + when(installerAi.loadLabel(any())).thenReturn(INSTALLER_LABEL); when(mInstallerService.createSessionInternal(any(), any(), any(), anyInt(), anyInt())).thenReturn(1); when(mInstallerService.getExistingDraftSessionId(anyInt(), any(), anyInt())).thenReturn( @@ -222,7 +228,7 @@ public class PackageArchiverTest { Exception e = assertThrows( SecurityException.class, () -> mArchiveManager.requestArchive(PACKAGE, "different", mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e).hasMessageThat().isEqualTo( String.format( "The UID %s of callerPackageName set by the caller doesn't match the " @@ -239,7 +245,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( String.format("Package %s not found.", PACKAGE)); @@ -249,7 +255,8 @@ public class PackageArchiverTest { public void archiveApp_packageNotInstalledForUser() throws IntentSender.SendIntentException { mPackageSetting.modifyUserState(UserHandle.CURRENT.getIdentifier()).setInstalled(false); - mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + 0); rule.mocks().getHandler().flush(); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -279,7 +286,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found"); } @@ -293,7 +300,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( "Installer does not support unarchival"); @@ -307,7 +314,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( TextUtils.formatSimple("The app %s does not have a main activity.", PACKAGE)); @@ -319,7 +326,8 @@ public class PackageArchiverTest { doThrow(e).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt(), anyInt()); - mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + 0); rule.mocks().getHandler().flush(); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -342,15 +350,16 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( TextUtils.formatSimple("The app %s is opted out of archiving.", PACKAGE)); } @Test - public void archiveApp_success() { - mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); + public void archiveApp_withNoAdditionalFlags_success() { + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + 0); rule.mocks().getHandler().flush(); verify(mInstallerService).uninstall( @@ -363,6 +372,23 @@ public class PackageArchiverTest { } @Test + public void archiveApp_withAdditionalFlags_success() { + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + PackageManager.DELETE_SHOW_DIALOG); + rule.mocks().getHandler().flush(); + + verify(mInstallerService).uninstall( + eq(new VersionedPackage(PACKAGE, PackageManager.VERSION_CODE_HIGHEST)), + eq(CALLER_PACKAGE), + eq(DELETE_ARCHIVE | DELETE_KEEP_DATA | PackageManager.DELETE_SHOW_DIALOG), + eq(mIntentSender), + eq(UserHandle.CURRENT.getIdentifier()), anyInt()); + assertThat(mPackageSetting.readUserState( + UserHandle.CURRENT.getIdentifier()).getArchiveState()).isEqualTo( + createArchiveState()); + } + + @Test public void isAppArchivable_success() throws PackageManager.NameNotFoundException { assertThat(mArchiveManager.isAppArchivable(PACKAGE, UserHandle.CURRENT)).isTrue(); } @@ -545,7 +571,7 @@ public class PackageArchiverTest { ICON_PATH, null); activityInfos.add(activityInfo); } - return new ArchiveState(activityInfos, INSTALLER_PACKAGE); + return new ArchiveState(activityInfos, INSTALLER_LABEL); } private static List<LauncherActivityInfo> createLauncherActivities() { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java index 3b39160643d1..91140276cde0 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java @@ -588,6 +588,38 @@ public class FullScreenMagnificationGestureHandlerTest { } @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + public void testTwoFingerTap_StateIsActivated_shouldInDelegating() { + assumeTrue(mMgh.mIsSinglePanningEnabled); + mMgh.setSinglePanningEnabled(false); + goFromStateIdleTo(STATE_ACTIVATED); + allowEventDelegation(); + + send(downEvent()); + send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y)); + send(upEvent()); + fastForward(ViewConfiguration.getDoubleTapTimeout()); + + assertTrue(mMgh.mCurrentState == mMgh.mDelegatingState); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) + public void testTwoFingerTap_StateIsIdle_shouldInDelegating() { + assumeTrue(mMgh.mIsSinglePanningEnabled); + mMgh.setSinglePanningEnabled(false); + goFromStateIdleTo(STATE_IDLE); + allowEventDelegation(); + + send(downEvent()); + send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y)); + send(upEvent()); + fastForward(ViewConfiguration.getDoubleTapTimeout()); + + assertTrue(mMgh.mCurrentState == mMgh.mDelegatingState); + } + + @Test public void testMultiTap_outOfDistanceSlop_shouldInIdle() { // All delay motion events should be sent, if multi-tap with out of distance slop. // STATE_IDLE will check if tapCount() < 2. @@ -719,6 +751,20 @@ public class FullScreenMagnificationGestureHandlerTest { } @Test + public void testTwoFingerDown_twoPointerDownAndActivatedState_panningState() { + goFromStateIdleTo(STATE_ACTIVATED); + PointF pointer1 = DEFAULT_POINT; + PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y); + + send(downEvent()); + send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1)); + fastForward(ViewConfiguration.getTapTimeout()); + assertIn(STATE_PANNING); + + returnToNormalFrom(STATE_PANNING); + } + + @Test public void testActivatedWithTripleTap_invokeShowWindowPromptAction() { goFromStateIdleTo(STATE_ACTIVATED); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java index 437510595ecb..1b9e6fb6e247 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java @@ -179,6 +179,29 @@ public class BiometricContextProviderTest { } @Test + public void testSubscribesToFoldState() throws RemoteException { + final List<Integer> actual = new ArrayList<>(); + final List<Integer> expected = List.of(FoldState.FULLY_CLOSED, FoldState.FULLY_OPENED, + FoldState.UNKNOWN, FoldState.HALF_OPENED); + mProvider.subscribe(mOpContext, ctx -> { + assertThat(ctx).isSameInstanceAs(mOpContext.toAidlContext()); + assertThat(mProvider.getFoldState()).isEqualTo(ctx.foldState); + actual.add(ctx.foldState); + }); + + for (int v : expected) { + mListener.onFoldChanged(v); + } + + assertThat(actual).containsExactly( + FoldState.FULLY_CLOSED, + FoldState.FULLY_OPENED, + FoldState.UNKNOWN, + FoldState.HALF_OPENED + ).inOrder(); + } + + @Test public void testSubscribesToDisplayState() throws RemoteException { final List<Integer> actual = new ArrayList<>(); final List<Integer> expected = List.of(AuthenticateOptions.DISPLAY_STATE_AOD, diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java new file mode 100644 index 000000000000..fd1abff8610b --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java @@ -0,0 +1,181 @@ +/* + * 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.server.credentials; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.ComponentName; +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.security.cert.CertificateException; +import java.util.HashSet; +import java.util.Set; + +/** atest FrameworksServicesTests:com.android.server.credentials.CredentialManagerServiceTest */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class CredentialManagerServiceTest { + + Context mContext = null; + + @Before + public void setUp() throws CertificateException { + mContext = ApplicationProvider.getApplicationContext(); + } + + @Test + public void getStoredProviders_emptyValue_success() { + Set<String> providers = CredentialManagerService.getStoredProviders("", ""); + assertThat(providers.size()).isEqualTo(0); + } + + @Test + public void getStoredProviders_success() { + Set<String> providers = + CredentialManagerService.getStoredProviders( + "com.example.test/.TestActivity:com.example.test/.TestActivity2:" + + "com.example.test2/.TestActivity:blank", + "com.example.test"); + assertThat(providers.size()).isEqualTo(1); + assertThat(providers.contains("com.example.test2/com.example.test2.TestActivity")).isTrue(); + } + + @Test + public void onProviderRemoved_success() { + setSettingsKey( + Settings.Secure.AUTOFILL_SERVICE, + CredentialManagerService.AUTOFILL_PLACEHOLDER_VALUE); + setSettingsKey( + Settings.Secure.CREDENTIAL_SERVICE, + "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"); + setSettingsKey( + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + "com.example.test/com.example.test.TestActivity"); + + CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test"); + + assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); + assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) + .isEqualTo("com.example.test2/com.example.test2.TestActivity"); + assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY)).isEqualTo(""); + } + + @Test + public void onProviderRemoved_notPrimaryRemoved_success() { + final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; + final String testCredentialValue = + "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; + + setSettingsKey( + Settings.Secure.AUTOFILL_SERVICE, + CredentialManagerService.AUTOFILL_PLACEHOLDER_VALUE); + setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue); + setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); + + CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3"); + + // Since the provider removed was not a primary provider then we should do nothing. + assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)) + .isEqualTo(CredentialManagerService.AUTOFILL_PLACEHOLDER_VALUE); + assertCredentialPropertyEquals( + getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE), testCredentialValue); + assertCredentialPropertyEquals( + getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY), + testCredentialPrimaryValue); + } + + @Test + public void onProviderRemoved_isAlsoAutofillProvider_success() { + setSettingsKey( + Settings.Secure.AUTOFILL_SERVICE, + "com.example.test/com.example.test.AutofillProvider"); + setSettingsKey( + Settings.Secure.CREDENTIAL_SERVICE, + "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"); + setSettingsKey( + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + "com.example.test/com.example.test.TestActivity"); + + CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test"); + + assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); + assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) + .isEqualTo("com.example.test2/com.example.test2.TestActivity"); + assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY)).isEqualTo(""); + } + + @Test + public void onProviderRemoved_notPrimaryRemoved_isAlsoAutofillProvider_success() { + final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; + final String testCredentialValue = + "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; + final String testAutofillValue = "com.example.test/com.example.test.TestAutofillActivity"; + + setSettingsKey(Settings.Secure.AUTOFILL_SERVICE, testAutofillValue); + setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue); + setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); + + CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3"); + + // Since the provider removed was not a primary provider then we should do nothing. + assertCredentialPropertyEquals( + getSettingsKey(Settings.Secure.AUTOFILL_SERVICE), testAutofillValue); + assertCredentialPropertyEquals( + getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE), testCredentialValue); + assertCredentialPropertyEquals( + getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY), + testCredentialPrimaryValue); + } + + private void assertCredentialPropertyEquals(String actualValue, String newValue) { + Set<ComponentName> actualValueSet = new HashSet<>(); + for (String rawComponentName : actualValue.split(":")) { + ComponentName cn = ComponentName.unflattenFromString(rawComponentName); + if (cn != null) { + actualValueSet.add(cn); + } + } + + Set<ComponentName> newValueSet = new HashSet<>(); + for (String rawComponentName : newValue.split(":")) { + ComponentName cn = ComponentName.unflattenFromString(rawComponentName); + if (cn != null) { + newValueSet.add(cn); + } + } + + assertThat(actualValueSet).isEqualTo(newValueSet); + } + + private void setSettingsKey(String key, String value) { + assertThat(Settings.Secure.putString(mContext.getContentResolver(), key, value)).isTrue(); + } + + private String getSettingsKey(String key) { + return Settings.Secure.getStringForUser( + mContext.getContentResolver(), key, UserHandle.myUserId()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java index 1726ec18e45b..a33f35aa11d3 100644 --- a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java +++ b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java @@ -29,6 +29,8 @@ import androidx.test.filters.FlakyTest; import com.android.server.job.MockBiasJobService.TestEnvironment; import com.android.server.job.MockBiasJobService.TestEnvironment.Event; +import libcore.junit.util.compat.CoreCompatChangeRule; + import java.util.ArrayList; @TargetApi(24) @@ -61,6 +63,7 @@ public class BiasSchedulingTest extends AndroidTestCase { } @FlakyTest(bugId = 293589359) + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testLowerBiasJobPreempted() throws Exception { for (int i = 0; i < JobConcurrencyManager.MAX_CONCURRENCY_LIMIT; ++i) { JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent) @@ -92,6 +95,7 @@ public class BiasSchedulingTest extends AndroidTestCase { assertTrue("Lower bias jobs were not preempted.", wasJobHigherExecuted); } + @CoreCompatChangeRule.DisableCompatChanges({JobInfo.ENFORCE_MINIMUM_TIME_WINDOWS}) public void testHigherBiasJobNotPreempted() throws Exception { for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent) diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java index 46ead854bded..3069b673f8fc 100644 --- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java @@ -3,6 +3,7 @@ package com.android.server.job; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static com.android.server.job.JobStore.JOB_FILE_SPLIT_PREFIX; @@ -141,7 +142,7 @@ public class JobStoreTest { final JobInfo task2 = new Builder(12, mComponent) .setMinimumLatency(5000L) .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR) - .setOverrideDeadline(30000L) + .setOverrideDeadline(4 * HOUR_IN_MILLIS) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setPersisted(true) .build(); @@ -194,7 +195,7 @@ public class JobStoreTest { final JobInfo task2 = new Builder(12, mComponent) .setMinimumLatency(5000L) .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR) - .setOverrideDeadline(30000L) + .setOverrideDeadline(3 * HOUR_IN_MILLIS) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setPersisted(true) .build(); @@ -224,7 +225,7 @@ public class JobStoreTest { final JobInfo task2 = new Builder(12, mComponent) .setMinimumLatency(5000L) .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR) - .setOverrideDeadline(30000L) + .setOverrideDeadline(5 * HOUR_IN_MILLIS) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setPersisted(true) .build(); @@ -330,7 +331,6 @@ public class JobStoreTest { @Test public void testMaybeWriteStatusToDisk() throws Exception { int taskId = 5; - long runByMillis = 20000L; // 20s long runFromMillis = 2000L; // 2s long initialBackoff = 10000L; // 10s @@ -338,7 +338,7 @@ public class JobStoreTest { .setRequiresCharging(true) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .setBackoffCriteria(initialBackoff, JobInfo.BACKOFF_POLICY_EXPONENTIAL) - .setOverrideDeadline(runByMillis) + .setOverrideDeadline(6 * HOUR_IN_MILLIS) .setMinimumLatency(runFromMillis) .setPersisted(true) .build(); @@ -379,7 +379,7 @@ public class JobStoreTest { final JobInfo task2 = new Builder(12, mComponent) .setMinimumLatency(5000L) .setBackoffCriteria(15000L, JobInfo.BACKOFF_POLICY_LINEAR) - .setOverrideDeadline(30000L) + .setOverrideDeadline(7 * HOUR_IN_MILLIS) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setPersisted(true) .build(); @@ -542,7 +542,7 @@ public class JobStoreTest { @Test public void testBiasPersisted() throws Exception { JobInfo.Builder b = new Builder(92, mComponent) - .setOverrideDeadline(5000) + .setOverrideDeadline(8 * HOUR_IN_MILLIS) .setBias(42) .setPersisted(true); final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null, null); @@ -613,7 +613,7 @@ public class JobStoreTest { @Test public void testPriorityPersisted() throws Exception { final JobInfo job = new Builder(92, mComponent) - .setOverrideDeadline(5000) + .setOverrideDeadline(9 * HOUR_IN_MILLIS) .setPriority(JobInfo.PRIORITY_MIN) .setPersisted(true) .build(); @@ -634,13 +634,13 @@ public class JobStoreTest { @Test public void testNonPersistedTaskIsNotPersisted() throws Exception { JobInfo.Builder b = new Builder(42, mComponent) - .setOverrideDeadline(10000) + .setOverrideDeadline(10 * HOUR_IN_MILLIS) .setPersisted(false); JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null, null); mTaskStoreUnderTest.add(jsNonPersisted); b = new Builder(43, mComponent) - .setOverrideDeadline(10000) + .setOverrideDeadline(11 * HOUR_IN_MILLIS) .setPersisted(true); JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null, null); diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java index 44dad593810a..32bbc7a618d1 100644 --- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java @@ -482,6 +482,35 @@ public class ThermalManagerServiceTest { } @Test + public void testGetThermalHeadroomThresholdsOnDefaultHalResult() throws Exception { + TemperatureWatcher watcher = mService.mTemperatureWatcher; + ArrayList<TemperatureThreshold> thresholds = new ArrayList<>(); + mFakeHal.mTemperatureThresholdList = thresholds; + watcher.updateThresholds(); + synchronized (watcher.mSamples) { + assertArrayEquals( + new float[]{Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, + Float.NaN}, + watcher.mHeadroomThresholds, 0.01f); + } + TemperatureThreshold nanThresholds = new TemperatureThreshold(); + nanThresholds.name = "nan"; + nanThresholds.type = Temperature.TYPE_SKIN; + nanThresholds.hotThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1]; + nanThresholds.coldThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1]; + Arrays.fill(nanThresholds.hotThrottlingThresholds, Float.NaN); + Arrays.fill(nanThresholds.coldThrottlingThresholds, Float.NaN); + thresholds.add(nanThresholds); + watcher.updateThresholds(); + synchronized (watcher.mSamples) { + assertArrayEquals( + new float[]{Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, + Float.NaN}, + watcher.mHeadroomThresholds, 0.01f); + } + } + + @Test public void testTemperatureWatcherGetSlopeOf() throws RemoteException { TemperatureWatcher watcher = mService.mTemperatureWatcher; List<TemperatureWatcher.Sample> samples = new ArrayList<>(); diff --git a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java index d09aa89179b8..ffb3bce33a27 100644 --- a/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/hint/HintManagerServiceTest.java @@ -44,6 +44,7 @@ import android.os.IBinder; import android.os.IHintSession; import android.os.PerformanceHintManager; import android.os.Process; +import android.os.WorkDuration; import android.util.Log; import com.android.server.FgThread; @@ -89,6 +90,11 @@ public class HintManagerServiceTest { private static final long[] DURATIONS_ZERO = new long[] {}; private static final long[] TIMESTAMPS_ZERO = new long[] {}; private static final long[] TIMESTAMPS_TWO = new long[] {1L, 2L}; + private static final WorkDuration[] WORK_DURATIONS_THREE = new WorkDuration[] { + new WorkDuration(1L, 11L, 8L, 4L, 1L), + new WorkDuration(2L, 13L, 8L, 6L, 2L), + new WorkDuration(3L, 333333333L, 8L, 333333333L, 3L), + }; @Mock private Context mContext; @Mock private HintManagerService.NativeWrapper mNativeWrapperMock; @@ -593,4 +599,56 @@ public class HintManagerServiceTest { } a.close(); } + + @Test + public void testReportActualWorkDuration2() throws Exception { + HintManagerService service = createService(); + IBinder token = new Binder(); + + AppHintSession a = (AppHintSession) service.getBinderServiceInstance() + .createHintSession(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION); + + a.updateTargetWorkDuration(100L); + a.reportActualWorkDuration2(WORK_DURATIONS_THREE); + verify(mNativeWrapperMock, times(1)).halReportActualWorkDuration(anyLong(), + eq(WORK_DURATIONS_THREE)); + + assertThrows(IllegalArgumentException.class, () -> { + a.reportActualWorkDuration2(new WorkDuration[] {}); + }); + + assertThrows(IllegalArgumentException.class, () -> { + a.reportActualWorkDuration2( + new WorkDuration[] {new WorkDuration(-1L, 11L, 8L, 4L, 1L)}); + }); + + assertThrows(IllegalArgumentException.class, () -> { + a.reportActualWorkDuration2(new WorkDuration[] {new WorkDuration(1L, 0L, 8L, 4L, 1L)}); + }); + + assertThrows(IllegalArgumentException.class, () -> { + a.reportActualWorkDuration2(new WorkDuration[] {new WorkDuration(1L, 11L, 0L, 4L, 1L)}); + }); + + assertThrows(IllegalArgumentException.class, () -> { + a.reportActualWorkDuration2( + new WorkDuration[] {new WorkDuration(1L, 11L, 8L, -1L, 1L)}); + }); + + reset(mNativeWrapperMock); + // Set session to background, then the duration would not be updated. + service.mUidObserver.onUidStateChanged( + a.mUid, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0); + + // Using CountDownLatch to ensure above onUidStateChanged() job was digested. + final CountDownLatch latch = new CountDownLatch(1); + FgThread.getHandler().post(() -> { + latch.countDown(); + }); + latch.await(); + + assertFalse(service.mUidObserver.isUidForeground(a.mUid)); + a.reportActualWorkDuration2(WORK_DURATIONS_THREE); + verify(mNativeWrapperMock, never()).halReportActualWorkDuration(anyLong(), any(), any()); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java index 337dd22e8712..44dbe385a144 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.truth.Truth.assertThat; +import android.app.Flags; import android.app.Notification; import android.app.PendingIntent; import android.app.Person; @@ -33,6 +34,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; +import android.platform.test.flag.junit.SetFlagsRule; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -42,6 +44,7 @@ import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; import com.android.server.UiServiceTestCase; import com.google.common.base.Strings; @@ -54,6 +57,7 @@ import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; import com.google.common.truth.Expect; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -72,6 +76,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -83,15 +88,16 @@ import javax.annotation.Nullable; @RunWith(AndroidJUnit4.class) public class NotificationVisitUrisTest extends UiServiceTestCase { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final String TAG = "VisitUrisTest"; // Methods that are known to add Uris that are *NOT* verified. - // This list should be emptied! Items can be removed as bugs are fixed. + // This list should only be used temporarily if needed, and any element in this list should + // have a tracking bug associated. private static final Multimap<Class<?>, String> KNOWN_BAD = - ImmutableMultimap.<Class<?>, String>builder() - .put(Person.Builder.class, "setUri") // TODO: b/281044385 - .build(); + ImmutableMultimap.<Class<?>, String>builder().build(); // Types that we can't really produce. No methods receiving these parameters will be invoked. private static final ImmutableSet<Class<?>> UNUSABLE_TYPES = @@ -155,6 +161,12 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { @Before public void setUp() { mContext = InstrumentationRegistry.getInstrumentation().getContext(); + mSetFlagsRule.enableFlags(Flags.FLAG_VISIT_RISKY_URIS); + } + + @After + public void tearDown() { + SystemUiSystemPropertiesFlags.TEST_RESOLVER = null; } @Test // This is a meta-test, checks that the generators are not broken. @@ -229,13 +241,12 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { notification.visitUris(visitor); Mockito.verify(visitor, Mockito.atLeastOnce()).accept(visitedUriCaptor.capture()); - List<Uri> visitedUris = new ArrayList<>(visitedUriCaptor.getAllValues()); + Set<Uri> visitedUris = new HashSet<>(visitedUriCaptor.getAllValues()); visitedUris.remove(null); expect.withMessage(notificationTypeMessage) .that(visitedUris) - .containsAtLeastElementsIn(includedUris); - expect.that(KNOWN_BAD).isNotEmpty(); // Once empty, switch to containsExactlyElementsIn() + .containsExactlyElementsIn(includedUris); } private static Generated<Notification> buildNotification(Context context, @@ -520,7 +531,7 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { && !EXCLUDED_SETTERS.containsEntry(clazz, method.getName()) && !EXCLUDED_SETTERS_OVERLOADS.containsEntry(clazz, method) && Arrays.stream(method.getParameterTypes()) - .noneMatch(excludingParameterTypes::contains)) { + .noneMatch(excludingParameterTypes::contains)) { methods.put(method.getName(), method); } } @@ -535,14 +546,14 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { List<Method> excludedSetters = setters.stream().filter( m1 -> m1.getName().startsWith("set") && setters.stream().anyMatch( - m2 -> { - Class<?> param1 = m1.getParameterTypes()[0]; - Class<?> param2 = m2.getParameterTypes()[0]; - return m2.getName().startsWith("add") - && param1.isArray() - && !param2.isArray() && !param2.isPrimitive() - && param1.getComponentType().equals(param2); - })).toList(); + m2 -> { + Class<?> param1 = m1.getParameterTypes()[0]; + Class<?> param2 = m2.getParameterTypes()[0]; + return m2.getName().startsWith("add") + && param1.isArray() + && !param2.isArray() && !param2.isPrimitive() + && param1.getComponentType().equals(param2); + })).toList(); setters.removeAll(excludedSetters); return setters; @@ -597,9 +608,8 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { private static class SpecialParameterGenerator { private static final ImmutableSet<Class<?>> INTERESTING_CLASSES = - ImmutableSet.of( - Person.class, Uri.class, Icon.class, Intent.class, PendingIntent.class, - RemoteViews.class); + ImmutableSet.of(Person.class, Uri.class, Icon.class, Intent.class, + PendingIntent.class, RemoteViews.class); private static final ImmutableSet<Class<?>> MOCKED_CLASSES = ImmutableSet.of(); private static final ImmutableMap<Class<?>, Object> PRIMITIVE_VALUES = @@ -623,7 +633,7 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { } static boolean canGenerate(Class<?> clazz) { - return (INTERESTING_CLASSES.contains(clazz) && !clazz.equals(Person.class)) + return INTERESTING_CLASSES.contains(clazz) || MOCKED_CLASSES.contains(clazz) || clazz.equals(Context.class) || clazz.equals(Bundle.class) @@ -658,6 +668,17 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { return Icon.createWithContentUri(iconUri); } + if (clazz == Person.class) { + // TODO(b/310189261): Person.setUri takes a string instead of a URI. We should + // find a way to use the SpecialParameterGenerator instead of this custom one. + Uri personUri = generateUri( + where.plus(Person.Builder.class).plus("setUri", String.class)); + Uri iconUri = generateUri(where.plus(Person.Builder.class).plus("setIcon", + Icon.class).plus(Icon.class).plus("createWithContentUri", Uri.class)); + return new Person.Builder().setUri(personUri.toString()).setIcon( + Icon.createWithContentUri(iconUri)).setName("John Doe").build(); + } + if (clazz == Intent.class) { // TODO(b/281044385): Are Intent Uris (new Intent(String,Uri)) relevant? return new Intent("action"); @@ -717,9 +738,12 @@ public class NotificationVisitUrisTest extends UiServiceTestCase { private static class Location { private static class Item { - @Nullable private final Class<?> mMaybeClass; - @Nullable private final Executable mMaybeMethod; - @Nullable private final String mExtra; + @Nullable + private final Class<?> mMaybeClass; + @Nullable + private final Executable mMaybeMethod; + @Nullable + private final String mExtra; Item(@NonNull Class<?> clazz) { mMaybeClass = checkNotNull(clazz); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 97b6b98a0b08..4d25eaab1f49 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -524,7 +524,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); mZenModeHelper.applyRestrictions(); - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.getSdkUsages()) { if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) { // only mute audio, not vibrations verify(mAppOps, atLeastOnce()).setRestriction(eq(AppOpsManager.OP_PLAY_AUDIO), @@ -546,7 +546,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); mZenModeHelper.applyRestrictions(); - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.getSdkUsages()) { verify(mAppOps).setRestriction( eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(new String[]{PKG_O})); verify(mAppOps).setRestriction( @@ -561,7 +561,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); mZenModeHelper.applyRestrictions(); - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.getSdkUsages()) { verify(mAppOps).setRestriction( eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null)); verify(mAppOps).setRestriction( @@ -576,7 +576,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); mZenModeHelper.applyRestrictions(); - for (int usage : AudioAttributes.SDK_USAGES) { + for (int usage : AudioAttributes.getSdkUsages()) { verify(mAppOps).setRestriction( eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null)); verify(mAppOps).setRestriction( @@ -1052,6 +1052,88 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void testProtoWithAutoRuleCustomPolicy_classic() throws Exception { + setupZenConfig(); + // clear any automatic rules just to make sure + mZenModeHelper.mConfig.automaticRules = new ArrayMap<>(); + + // Add an automatic rule with a custom policy + ZenRule rule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS, CUSTOM_RULE_ID); + rule.zenPolicy = new ZenPolicy.Builder() + .allowAlarms(true) + .allowRepeatCallers(false) + .allowCalls(PEOPLE_TYPE_STARRED) + .build(); + mZenModeHelper.mConfig.automaticRules.put(rule.id, rule); + List<StatsEvent> events = new LinkedList<>(); + mZenModeHelper.pullRules(events); + + boolean foundCustomEvent = false; + for (StatsEvent ev : events) { + AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); + assertTrue(atom.hasDndModeRule()); + DNDModeProto cfg = atom.getDndModeRule(); + if (cfg.getUid() == CUSTOM_PKG_UID) { + foundCustomEvent = true; + // Check that the pieces of the policy are applied. + assertThat(cfg.hasPolicy()).isTrue(); + DNDPolicyProto policy = cfg.getPolicy(); + assertThat(policy.getAlarms().getNumber()).isEqualTo(DNDProtoEnums.STATE_ALLOW); + assertThat(policy.getRepeatCallers().getNumber()) + .isEqualTo(DNDProtoEnums.STATE_DISALLOW); + assertThat(policy.getCalls().getNumber()).isEqualTo(DNDProtoEnums.STATE_ALLOW); + assertThat(policy.getAllowCallsFrom().getNumber()) + .isEqualTo(DNDProtoEnums.PEOPLE_STARRED); + } + } + assertTrue("couldn't find custom rule", foundCustomEvent); + } + + @Test + public void testProtoWithAutoRuleCustomPolicy() throws Exception { + // allowChannels is only valid under modes_api. + mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); + + setupZenConfig(); + // clear any automatic rules just to make sure + mZenModeHelper.mConfig.automaticRules = new ArrayMap<>(); + + // Add an automatic rule with a custom policy + ZenRule rule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS, CUSTOM_RULE_ID); + rule.zenPolicy = new ZenPolicy.Builder() + .allowAlarms(true) + .allowRepeatCallers(false) + .allowCalls(PEOPLE_TYPE_STARRED) + .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE) + .build(); + mZenModeHelper.mConfig.automaticRules.put(rule.id, rule); + List<StatsEvent> events = new LinkedList<>(); + mZenModeHelper.pullRules(events); + + boolean foundCustomEvent = false; + for (StatsEvent ev : events) { + AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); + assertTrue(atom.hasDndModeRule()); + DNDModeProto cfg = atom.getDndModeRule(); + if (cfg.getUid() == CUSTOM_PKG_UID) { + foundCustomEvent = true; + // Check that the pieces of the policy are applied. + assertThat(cfg.hasPolicy()).isTrue(); + DNDPolicyProto policy = cfg.getPolicy(); + assertThat(policy.getAlarms().getNumber()).isEqualTo(DNDProtoEnums.STATE_ALLOW); + assertThat(policy.getRepeatCallers().getNumber()) + .isEqualTo(DNDProtoEnums.STATE_DISALLOW); + assertThat(policy.getCalls().getNumber()).isEqualTo(DNDProtoEnums.STATE_ALLOW); + assertThat(policy.getAllowCallsFrom().getNumber()) + .isEqualTo(DNDProtoEnums.PEOPLE_STARRED); + assertThat(policy.getAllowChannels().getNumber()) + .isEqualTo(DNDProtoEnums.CHANNEL_TYPE_NONE); + } + } + assertTrue("couldn't find custom rule", foundCustomEvent); + } + + @Test public void ruleUidsCached() throws Exception { setupZenConfig(); // one enabled automatic rule @@ -2722,6 +2804,55 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void testZenModeEventLog_policyAllowChannels() { + // when modes_api flag is on, ensure that any change in allow_channels gets logged, + // even when there are no other changes. + mTestFlagResolver.setFlagOverride(LOG_DND_STATE_EVENTS, true); + mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API); + + // Default zen config has allow channels = priority (aka on) + setupZenConfig(); + + // First just turn zen mode on + mZenModeHelper.setManualZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, null, "", + Process.SYSTEM_UID, true); + + // Now change only the channels part of the policy; want to confirm that this'll be + // reflected in the logs + ZenModeConfig newConfig = mZenModeHelper.mConfig.copy(); + newConfig.allowPriorityChannels = false; + mZenModeHelper.setNotificationPolicy(newConfig.toNotificationPolicy(), Process.SYSTEM_UID, + true); + + // Total events: one for turning on, one for changing policy + assertThat(mZenModeEventLogger.numLoggedChanges()).isEqualTo(2); + + // The first event is just turning DND on; make sure the policy is what we expect there + // before it changes in the next stage + assertThat(mZenModeEventLogger.getEventId(0)) + .isEqualTo(ZenModeEventLogger.ZenStateChangedEvent.DND_TURNED_ON.getId()); + DNDPolicyProto origDndProto = mZenModeEventLogger.getPolicyProto(0); + checkDndProtoMatchesSetupZenConfig(origDndProto); + assertThat(origDndProto.getAllowChannels().getNumber()) + .isEqualTo(DNDProtoEnums.CHANNEL_TYPE_PRIORITY); + + // Second message where we change the policy: + // - DND_POLICY_CHANGED (indicates only the policy changed and nothing else) + // - rule type: unknown (it's a policy change, not a rule change) + // - user action (because it comes from a "system" uid) + // - change is in allow channels, and final policy + assertThat(mZenModeEventLogger.getEventId(1)) + .isEqualTo(ZenModeEventLogger.ZenStateChangedEvent.DND_POLICY_CHANGED.getId()); + assertThat(mZenModeEventLogger.getChangedRuleType(1)) + .isEqualTo(DNDProtoEnums.UNKNOWN_RULE); + assertThat(mZenModeEventLogger.getIsUserAction(1)).isTrue(); + assertThat(mZenModeEventLogger.getPackageUid(1)).isEqualTo(Process.SYSTEM_UID); + DNDPolicyProto dndProto = mZenModeEventLogger.getPolicyProto(1); + assertThat(dndProto.getAllowChannels().getNumber()) + .isEqualTo(DNDProtoEnums.CHANNEL_TYPE_NONE); + } + + @Test public void testUpdateConsolidatedPolicy_defaultRulesOnly() { setupZenConfig(); @@ -3416,6 +3547,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { return rule; } + // TODO: b/310620812 - Update setup methods to include allowChannels() when MODES_API is inlined private void setupZenConfig() { mZenModeHelper.mZenMode = ZEN_MODE_OFF; mZenModeHelper.mConfig.allowAlarms = false; diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index c3074bb0fee8..a8d3fa110844 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -99,7 +99,7 @@ android:theme="@style/WhiteBackgroundTheme" android:exported="true"/> - <activity android:name="com.android.server.wm.TrustedPresentationCallbackTest$TestActivity" + <activity android:name="com.android.server.wm.TrustedPresentationListenerTest$TestActivity" android:exported="true" android:showWhenLocked="true" android:turnScreenOn="true" /> diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index f2e54bc572ae..7aa46a62b0f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -3727,6 +3727,24 @@ public class ActivityRecordTests extends WindowTestsBase { verify(task).moveTaskToBack(any()); } + /** + * Verifies the {@link ActivityRecord#moveFocusableActivityToTop} returns {@code false} if + * there's a PIP task on top. + */ + @Test + public void testMoveFocusableActivityToTop() { + // Create a Task + final Task task = createTask(mDisplayContent); + final ActivityRecord ar = createActivityRecord(task); + + // Create a PIP Task on top + final Task pipTask = createTask(mDisplayContent); + doReturn(true).when(pipTask).inPinnedWindowingMode(); + + // Verifies that the Task is not moving-to-top. + assertFalse(ar.moveFocusableActivityToTop("test")); + } + private ICompatCameraControlCallback getCompatCameraControlCallback() { return new ICompatCameraControlCallback.Stub() { @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index acce2e2633bd..71d2504e1746 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2086,15 +2086,17 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testShellTransitRotation() { - DisplayContent dc = createNewDisplay(); - dc.setLastHasContent(); + final DisplayContent dc = mDisplayContent; + // Create 2 visible activities to verify that they can both receive the new configuration. + final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); + doReturn(true).when(activity1).isSyncFinished(any()); + doReturn(true).when(activity2).isSyncFinished(any()); final TestTransitionPlayer testPlayer = registerTestTransitionPlayer(); final DisplayRotation dr = dc.getDisplayRotation(); - doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean()); - // Rotate 180 degree so the display doesn't have configuration change. This condition is - // used for the later verification of stop-freezing (without setting mWaitingForConfig). - doReturn((dr.getRotation() + 2) % 4).when(dr).rotationForOrientation(anyInt(), anyInt()); + spyOn(dr); + doReturn((dr.getRotation() + 1) % 4).when(dr).rotationForOrientation(anyInt(), anyInt()); mWm.mDisplayChangeController = new IDisplayChangeWindowController.Stub() { @Override @@ -2109,11 +2111,8 @@ public class DisplayContentTests extends WindowTestsBase { } }; - // kill any existing rotation animation (vestigial from test setup). - dc.setRotationAnimation(null); - final int origRot = dc.getConfiguration().windowConfiguration.getRotation(); - + dc.setLastHasContent(); mWm.updateRotation(true /* alwaysSendConfiguration */, false /* forceRelayout */); // Should create a transition request without performing rotation assertNotNull(testPlayer.mLastRequest); @@ -2122,6 +2121,10 @@ public class DisplayContentTests extends WindowTestsBase { // Once transition starts, rotation is applied and transition shows DC rotating. testPlayer.startTransition(); waitUntilHandlersIdle(); + verify(activity1).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(), + anyBoolean()); + verify(activity2).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(), + anyBoolean()); assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation()); assertNotNull(testPlayer.mLastReady); assertTrue(testPlayer.mController.isPlaying()); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java index 3b9ed2652610..ef427bb15039 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlViewHostTests.java @@ -137,7 +137,7 @@ public class SurfaceControlViewHostTests { wasVisible = waitForWindowVisible(mView2); if (!wasVisible) { - dumpWindowsOnScreen(TAG, "requestFocusWithMultipleWindows"); + dumpWindowsOnScreen(TAG, "requestFocusWithMultipleWindows-not visible"); } assertTrue("Failed to wait for view2", wasVisible); @@ -145,11 +145,21 @@ public class SurfaceControlViewHostTests { WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window, mScvh1.getInputTransferToken(), true); - assertTrue("Failed to gain focus for view1", waitForWindowFocus(mView1, true)); + + boolean gainedFocus = waitForWindowFocus(mView1, true); + if (!gainedFocus) { + dumpWindowsOnScreen(TAG, "requestFocusWithMultipleWindows-view1 not focus"); + } + assertTrue("Failed to gain focus for view1", gainedFocus); WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(window, mScvh2.getInputTransferToken(), true); - assertTrue("Failed to gain focus for view2", waitForWindowFocus(mView2, true)); + + gainedFocus = waitForWindowFocus(mView2, true); + if (!gainedFocus) { + dumpWindowsOnScreen(TAG, "requestFocusWithMultipleWindows-view2 not focus"); + } + assertTrue("Failed to gain focus for view2", gainedFocus); } private static class TestWindowlessWindowManager extends WindowlessWindowManager { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java index 267bec9cccd2..c876663dd749 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java @@ -40,6 +40,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.graphics.Color; import android.graphics.PixelFormat; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; @@ -167,7 +168,7 @@ public class TaskStackChangedListenerTest { @Presubmit public void testTaskDescriptionChanged() throws Exception { final Object[] params = new Object[2]; - final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch latch = new CountDownLatch(2); registerTaskStackChangedListener(new TaskStackListener() { int mTaskId = -1; @@ -510,6 +511,8 @@ public class TaskStackChangedListenerTest { protected void onPostResume() { super.onPostResume(); setTaskDescription(new TaskDescription("Test Label")); + // Sets the color of the status-bar should update the TaskDescription again. + getWindow().setStatusBarColor(Color.RED); synchronized (sLock) { // Hold the lock to ensure no one is trying to access fields of this Activity in // this test. diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java deleted file mode 100644 index c5dd447b5b0c..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.server.wm; - -import static android.server.wm.ActivityManagerTestBase.createFullscreenActivityScenarioRule; -import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.app.Activity; -import android.platform.test.annotations.Presubmit; -import android.server.wm.CtsWindowInfoUtils; -import android.view.SurfaceControl; -import android.view.SurfaceControl.TrustedPresentationThresholds; - -import androidx.annotation.GuardedBy; -import androidx.test.ext.junit.rules.ActivityScenarioRule; - -import com.android.server.wm.utils.CommonUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -import java.util.function.Consumer; - -/** - * TODO (b/287076178): Move these tests to - * {@link android.view.surfacecontrol.cts.TrustedPresentationCallbackTest} when API is made public - */ -@Presubmit -public class TrustedPresentationCallbackTest { - private static final String TAG = "TrustedPresentationCallbackTest"; - private static final int STABILITY_REQUIREMENT_MS = 500; - private static final long WAIT_TIME_MS = HW_TIMEOUT_MULTIPLIER * 2000L; - - private static final float FRACTION_VISIBLE = 0.1f; - - private final Object mResultsLock = new Object(); - @GuardedBy("mResultsLock") - private boolean mResult; - @GuardedBy("mResultsLock") - private boolean mReceivedResults; - - @Rule - public TestName mName = new TestName(); - - @Rule - public ActivityScenarioRule<TestActivity> mActivityRule = createFullscreenActivityScenarioRule( - TestActivity.class); - - private TestActivity mActivity; - - @Before - public void setup() { - mActivityRule.getScenario().onActivity(activity -> mActivity = activity); - } - - @After - public void tearDown() { - CommonUtils.waitUntilActivityRemoved(mActivity); - } - - @Test - public void testAddTrustedPresentationListenerOnWindow() throws InterruptedException { - TrustedPresentationThresholds thresholds = new TrustedPresentationThresholds( - 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS); - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - mActivity.getWindow().getRootSurfaceControl().addTrustedPresentationCallback(t, thresholds, - Runnable::run, inTrustedPresentationState -> { - synchronized (mResultsLock) { - mResult = inTrustedPresentationState; - mReceivedResults = true; - mResultsLock.notify(); - } - }); - t.apply(); - synchronized (mResultsLock) { - assertResults(); - } - } - - @Test - public void testRemoveTrustedPresentationListenerOnWindow() throws InterruptedException { - TrustedPresentationThresholds thresholds = new TrustedPresentationThresholds( - 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS); - Consumer<Boolean> trustedPresentationCallback = inTrustedPresentationState -> { - synchronized (mResultsLock) { - mResult = inTrustedPresentationState; - mReceivedResults = true; - mResultsLock.notify(); - } - }; - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - mActivity.getWindow().getRootSurfaceControl().addTrustedPresentationCallback(t, thresholds, - Runnable::run, trustedPresentationCallback); - t.apply(); - - synchronized (mResultsLock) { - if (!mReceivedResults) { - mResultsLock.wait(WAIT_TIME_MS); - } - assertResults(); - // reset the state - mReceivedResults = false; - } - - mActivity.getWindow().getRootSurfaceControl().removeTrustedPresentationCallback(t, - trustedPresentationCallback); - t.apply(); - - synchronized (mResultsLock) { - if (!mReceivedResults) { - mResultsLock.wait(WAIT_TIME_MS); - } - // Ensure we waited the full time and never received a notify on the result from the - // callback. - assertFalse("Should never have received a callback", mReceivedResults); - // results shouldn't have changed. - assertTrue(mResult); - } - } - - @GuardedBy("mResultsLock") - private void assertResults() throws InterruptedException { - mResultsLock.wait(WAIT_TIME_MS); - - if (!mReceivedResults) { - CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, "test " + mName.getMethodName()); - } - // Make sure we received the results and not just timed out - assertTrue("Timed out waiting for results", mReceivedResults); - assertTrue(mResult); - } - - public static class TestActivity extends Activity { - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java new file mode 100644 index 000000000000..96b66bfd3bc0 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationListenerTest.java @@ -0,0 +1,267 @@ +/* + * 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.server.wm; + +import static android.server.wm.ActivityManagerTestBase.createFullscreenActivityScenarioRule; +import static android.server.wm.BuildUtils.HW_TIMEOUT_MULTIPLIER; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; + +import android.app.Activity; +import android.os.SystemClock; +import android.platform.test.annotations.Presubmit; +import android.server.wm.CtsWindowInfoUtils; +import android.util.AndroidRuntimeException; +import android.util.Log; +import android.view.SurfaceControl; +import android.view.SurfaceControlViewHost; +import android.view.View; +import android.view.WindowManager; +import android.window.TrustedPresentationThresholds; + +import androidx.annotation.GuardedBy; +import androidx.annotation.NonNull; +import androidx.test.ext.junit.rules.ActivityScenarioRule; + +import com.android.server.wm.utils.CommonUtils; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** + * TODO (b/287076178): Move these tests to + * {@link android.view.surfacecontrol.cts.TrustedPresentationListenerTest} when API is made public + */ +@Presubmit +public class TrustedPresentationListenerTest { + private static final String TAG = "TrustedPresentationListenerTest"; + private static final int STABILITY_REQUIREMENT_MS = 500; + private static final long WAIT_TIME_MS = HW_TIMEOUT_MULTIPLIER * 2000L; + + private static final float FRACTION_VISIBLE = 0.1f; + + private final List<Boolean> mResults = Collections.synchronizedList(new ArrayList<>()); + private CountDownLatch mReceivedResults = new CountDownLatch(1); + + private TrustedPresentationThresholds mThresholds = new TrustedPresentationThresholds( + 1 /* minAlpha */, FRACTION_VISIBLE, STABILITY_REQUIREMENT_MS); + + @Rule + public TestName mName = new TestName(); + + @Rule + public ActivityScenarioRule<TestActivity> mActivityRule = createFullscreenActivityScenarioRule( + TestActivity.class); + + private TestActivity mActivity; + + private SurfaceControlViewHost.SurfacePackage mSurfacePackage = null; + + @Before + public void setup() { + mActivityRule.getScenario().onActivity(activity -> mActivity = activity); + mDefaultListener = new Listener(mReceivedResults); + } + + @After + public void tearDown() { + if (mSurfacePackage != null) { + new SurfaceControl.Transaction().remove(mSurfacePackage.getSurfaceControl()).apply( + true); + mSurfacePackage.release(); + } + CommonUtils.waitUntilActivityRemoved(mActivity); + + } + + private class Listener implements Consumer<Boolean> { + final CountDownLatch mLatch; + + Listener(CountDownLatch latch) { + mLatch = latch; + } + + @Override + public void accept(Boolean inTrustedPresentationState) { + Log.d(TAG, "onTrustedPresentationChanged " + inTrustedPresentationState); + mResults.add(inTrustedPresentationState); + mLatch.countDown(); + } + } + + private Consumer<Boolean> mDefaultListener; + + @Test + public void testAddTrustedPresentationListenerOnWindow() { + WindowManager windowManager = mActivity.getSystemService(WindowManager.class); + windowManager.registerTrustedPresentationListener( + mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, Runnable::run, + mDefaultListener); + assertResults(List.of(true)); + } + + @Test + public void testRemoveTrustedPresentationListenerOnWindow() throws InterruptedException { + WindowManager windowManager = mActivity.getSystemService(WindowManager.class); + windowManager.registerTrustedPresentationListener( + mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, Runnable::run, + mDefaultListener); + assertResults(List.of(true)); + // reset the latch + mReceivedResults = new CountDownLatch(1); + + windowManager.unregisterTrustedPresentationListener(mDefaultListener); + mReceivedResults.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS); + // Ensure we waited the full time and never received a notify on the result from the + // callback. + assertEquals("Should never have received a callback", mReceivedResults.getCount(), 1); + // results shouldn't have changed. + assertEquals(mResults, List.of(true)); + } + + @Test + public void testRemovingUnknownListenerIsANoop() { + WindowManager windowManager = mActivity.getSystemService(WindowManager.class); + assertNotNull(windowManager); + windowManager.unregisterTrustedPresentationListener(mDefaultListener); + } + + @Test + public void testAddDuplicateListenerThrowsException() { + WindowManager windowManager = mActivity.getSystemService(WindowManager.class); + assertNotNull(windowManager); + windowManager.registerTrustedPresentationListener( + mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, + Runnable::run, mDefaultListener); + assertThrows(AndroidRuntimeException.class, + () -> windowManager.registerTrustedPresentationListener( + mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, + Runnable::run, mDefaultListener)); + } + + @Test + public void testAddDuplicateThresholds() { + mReceivedResults = new CountDownLatch(2); + mDefaultListener = new Listener(mReceivedResults); + WindowManager windowManager = mActivity.getSystemService(WindowManager.class); + windowManager.registerTrustedPresentationListener( + mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, + Runnable::run, mDefaultListener); + + Consumer<Boolean> mNewListener = new Listener(mReceivedResults); + + windowManager.registerTrustedPresentationListener( + mActivity.getWindow().getDecorView().getWindowToken(), mThresholds, + Runnable::run, mNewListener); + assertResults(List.of(true, true)); + } + + private void waitForViewAttach(View view) { + final CountDownLatch viewAttached = new CountDownLatch(1); + view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(@NonNull View v) { + viewAttached.countDown(); + } + + @Override + public void onViewDetachedFromWindow(@NonNull View v) { + + } + }); + try { + viewAttached.await(2000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + if (!wait(viewAttached, 2000 /* waitTimeMs */)) { + fail("Couldn't attach view=" + view); + } + } + + @Test + public void testAddListenerToScvh() { + WindowManager windowManager = mActivity.getSystemService(WindowManager.class); + + var embeddedView = new View(mActivity); + mActivityRule.getScenario().onActivity(activity -> { + var attachedSurfaceControl = + mActivity.getWindow().getDecorView().getRootSurfaceControl(); + var scvh = new SurfaceControlViewHost(mActivity, mActivity.getDisplay(), + attachedSurfaceControl.getHostToken()); + mSurfacePackage = scvh.getSurfacePackage(); + scvh.setView(embeddedView, mActivity.getWindow().getDecorView().getWidth(), + mActivity.getWindow().getDecorView().getHeight()); + attachedSurfaceControl.buildReparentTransaction( + mSurfacePackage.getSurfaceControl()); + }); + + waitForViewAttach(embeddedView); + windowManager.registerTrustedPresentationListener(embeddedView.getWindowToken(), + mThresholds, + Runnable::run, mDefaultListener); + + assertResults(List.of(true)); + } + + private boolean wait(CountDownLatch latch, long waitTimeMs) { + while (true) { + long now = SystemClock.uptimeMillis(); + try { + return latch.await(waitTimeMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + long elapsedTime = SystemClock.uptimeMillis() - now; + waitTimeMs = Math.max(0, waitTimeMs - elapsedTime); + } + } + + } + + @GuardedBy("mResultsLock") + private void assertResults(List<Boolean> results) { + if (!wait(mReceivedResults, WAIT_TIME_MS)) { + try { + CtsWindowInfoUtils.dumpWindowsOnScreen(TAG, "test " + mName.getMethodName()); + } catch (InterruptedException e) { + Log.d(TAG, "Couldn't dump windows", e); + } + Assert.fail("Timed out waiting for results mReceivedResults.count=" + + mReceivedResults.getCount() + "mReceivedResults=" + mReceivedResults); + } + + // Make sure we received the results + assertEquals(results.toArray(), mResults.toArray()); + } + + public static class TestActivity extends Activity { + } +} diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index ddec8fa1d70a..a4877999ff6f 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -27,3 +27,16 @@ android_test { platform_apis: true, test_suites: ["device-tests"], } + +android_ravenwood_test { + name: "InternalTestsRavenwood", + static_libs: [ + "androidx.annotation_annotation", + "androidx.test.rules", + "platform-test-annotations", + ], + srcs: [ + "src/com/android/internal/util/ParcellingTests.java", + ], + auto_gen_config: true, +} diff --git a/tests/NetworkSecurityConfigTest/OWNERS b/tests/NetworkSecurityConfigTest/OWNERS index aa87958f1d53..90e1bed9fb26 100644 --- a/tests/NetworkSecurityConfigTest/OWNERS +++ b/tests/NetworkSecurityConfigTest/OWNERS @@ -1 +1,2 @@ include /services/core/java/com/android/server/net/OWNERS +include /core/java/android/security/net/OWNERS diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 412aa9bf88ab..275a0e21fedd 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -92,10 +92,6 @@ cc_library_host_static { srcs: [ "compile/IdAssigner.cpp", "compile/InlineXmlFormatParser.cpp", - "compile/NinePatch.cpp", - "compile/Png.cpp", - "compile/PngChunkFilter.cpp", - "compile/PngCrunch.cpp", "compile/PseudolocaleGenerator.cpp", "compile/Pseudolocalizer.cpp", "compile/XmlIdCollector.cpp", @@ -112,9 +108,7 @@ cc_library_host_static { "format/binary/XmlFlattener.cpp", "format/proto/ProtoDeserialize.cpp", "format/proto/ProtoSerialize.cpp", - "io/BigBufferStream.cpp", "io/File.cpp", - "io/FileStream.cpp", "io/FileSystem.cpp", "io/StringStream.cpp", "io/Util.cpp", diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index 6b1fd9ff11eb..d6502d82848f 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -18,12 +18,12 @@ #include "ResourceValues.h" #include "ValueVisitor.h" +#include "androidfw/BigBufferStream.h" #include "format/Archive.h" #include "format/binary/TableFlattener.h" #include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" #include "format/proto/ProtoSerialize.h" -#include "io/BigBufferStream.h" #include "io/Util.h" #include "xml/XmlDom.h" @@ -48,7 +48,7 @@ static ApkFormat DetermineApkFormat(io::IFileCollection* apk) { } // First try in proto format. - std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream(); + std::unique_ptr<android::InputStream> manifest_in = manifest_file->OpenInputStream(); if (manifest_in != nullptr) { pb::XmlNode pb_node; io::ProtoInputStreamReader proto_reader(manifest_in.get()); @@ -102,7 +102,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection( io::IFile* table_file = collection->FindFile(kProtoResourceTablePath); if (table_file != nullptr) { pb::ResourceTable pb_table; - std::unique_ptr<io::InputStream> in = table_file->OpenInputStream(); + std::unique_ptr<android::InputStream> in = table_file->OpenInputStream(); if (in == nullptr) { diag->Error(android::DiagMessage(source) << "failed to open " << kProtoResourceTablePath); return {}; @@ -129,7 +129,7 @@ std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection( return {}; } - std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream(); + std::unique_ptr<android::InputStream> manifest_in = manifest_file->OpenInputStream(); if (manifest_in == nullptr) { diag->Error(android::DiagMessage(source) << "failed to open " << kAndroidManifestPath); return {}; @@ -262,7 +262,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return false; } - io::BigBufferInputStream input_stream(&buffer); + android::BigBufferInputStream input_stream(&buffer); if (!io::CopyInputStreamToArchive(context, &input_stream, path, @@ -296,7 +296,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table } uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u; - io::BigBufferInputStream manifest_buffer_in(&buffer); + android::BigBufferInputStream manifest_buffer_in(&buffer); if (!io::CopyInputStreamToArchive(context, &manifest_buffer_in, path, compression_flags, writer)) { return false; @@ -321,7 +321,7 @@ std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_pat std::unique_ptr<xml::XmlResource> doc; if (format_ == ApkFormat::kProto) { - std::unique_ptr<io::InputStream> in = file->OpenInputStream(); + std::unique_ptr<android::InputStream> in = file->OpenInputStream(); if (!in) { diag->Error(android::DiagMessage() << "failed to open file"); return nullptr; diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index a0b4dab9b8e5..b351d6ee4f33 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -27,6 +27,7 @@ #include "Diagnostics.h" #include "android-base/stringprintf.h" #include "android-base/utf8.h" +#include "androidfw/FileStream.h" #include "androidfw/IDiagnostics.h" #include "androidfw/StringPiece.h" #include "cmd/ApkInfo.h" @@ -37,7 +38,6 @@ #include "cmd/Dump.h" #include "cmd/Link.h" #include "cmd/Optimize.h" -#include "io/FileStream.h" #include "trace/TraceBuffer.h" #include "util/Files.h" #include "util/Util.h" @@ -99,7 +99,7 @@ class MainCommand : public Command { */ class DaemonCommand : public Command { public: - explicit DaemonCommand(io::FileOutputStream* out, android::IDiagnostics* diagnostics) + explicit DaemonCommand(android::FileOutputStream* out, android::IDiagnostics* diagnostics) : Command("daemon", "m"), out_(out), diagnostics_(diagnostics) { SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n" "command. The end of an invocation is signaled by providing an empty line."); @@ -147,7 +147,7 @@ class DaemonCommand : public Command { } private: - io::FileOutputStream* out_; + android::FileOutputStream* out_; android::IDiagnostics* diagnostics_; std::optional<std::string> trace_folder_; }; @@ -167,7 +167,7 @@ int MainImpl(int argc, char** argv) { // Use a smaller buffer so that there is less latency for printing to stdout. constexpr size_t kStdOutBufferSize = 1024u; - aapt::io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + android::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); aapt::text::Printer printer(&fout); aapt::StdErrDiagnostics diagnostics; diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 728ba8aa4fdd..031dd5bb139c 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -25,13 +25,16 @@ #include "android-base/errors.h" #include "android-base/file.h" #include "android-base/utf8.h" +#include "androidfw/BigBufferStream.h" #include "androidfw/ConfigDescription.h" +#include "androidfw/FileStream.h" #include "androidfw/IDiagnostics.h" +#include "androidfw/Image.h" +#include "androidfw/Png.h" #include "androidfw/StringPiece.h" #include "cmd/Util.h" #include "compile/IdAssigner.h" #include "compile/InlineXmlFormatParser.h" -#include "compile/Png.h" #include "compile/PseudolocaleGenerator.h" #include "compile/XmlIdCollector.h" #include "format/Archive.h" @@ -39,8 +42,6 @@ #include "format/proto/ProtoSerialize.h" #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include "io/BigBufferStream.h" -#include "io/FileStream.h" #include "io/FileSystem.h" #include "io/StringStream.h" #include "io/Util.h" @@ -52,9 +53,9 @@ #include "xml/XmlDom.h" #include "xml/XmlPullParser.h" -using ::aapt::io::FileInputStream; using ::aapt::text::Printer; using ::android::ConfigDescription; +using ::android::FileInputStream; using ::android::StringPiece; using ::android::base::SystemErrorCodeToString; using ::google::protobuf::io::CopyingOutputStreamAdaptor; @@ -241,7 +242,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, } if (options.generate_text_symbols_path) { - io::FileOutputStream fout_text(options.generate_text_symbols_path.value()); + android::FileOutputStream fout_text(options.generate_text_symbols_path.value()); if (fout_text.HadError()) { context->GetDiagnostics()->Error(android::DiagMessage() @@ -307,7 +308,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, } static bool WriteHeaderAndDataToWriter(StringPiece output_path, const ResourceFile& file, - io::KnownSizeInputStream* in, IArchiveWriter* writer, + android::KnownSizeInputStream* in, IArchiveWriter* writer, android::IDiagnostics* diag) { TRACE_CALL(); // Start the entry so we can write the header. @@ -448,7 +449,7 @@ static bool CompileXml(IAaptContext* context, const CompileOptions& options, } if (options.generate_text_symbols_path) { - io::FileOutputStream fout_text(options.generate_text_symbols_path.value()); + android::FileOutputStream fout_text(options.generate_text_symbols_path.value()); if (fout_text.HadError()) { context->GetDiagnostics()->Error(android::DiagMessage() @@ -498,21 +499,22 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options, } android::BigBuffer crunched_png_buffer(4096); - io::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer); + android::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer); // Ensure that we only keep the chunks we care about if we end up // using the original PNG instead of the crunched one. const StringPiece content(reinterpret_cast<const char*>(data->data()), data->size()); - PngChunkFilter png_chunk_filter(content); - std::unique_ptr<Image> image = ReadPng(context, path_data.source, &png_chunk_filter); + android::PngChunkFilter png_chunk_filter(content); + android::SourcePathDiagnostics source_diag(path_data.source, context->GetDiagnostics()); + auto image = android::ReadPng(&png_chunk_filter, &source_diag); if (!image) { return false; } - std::unique_ptr<NinePatch> nine_patch; + std::unique_ptr<android::NinePatch> nine_patch; if (path_data.extension == "9.png") { std::string err; - nine_patch = NinePatch::Create(image->rows.get(), image->width, image->height, &err); + nine_patch = android::NinePatch::Create(image->rows.get(), image->width, image->height, &err); if (!nine_patch) { context->GetDiagnostics()->Error(android::DiagMessage() << err); return false; @@ -537,7 +539,8 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options, } // Write the crunched PNG. - if (!WritePng(context, image.get(), nine_patch.get(), &crunched_png_buffer_out, {})) { + if (!android::WritePng(image.get(), nine_patch.get(), &crunched_png_buffer_out, {}, + &source_diag, context->IsVerbose())) { return false; } @@ -557,7 +560,7 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options, png_chunk_filter.Rewind(); android::BigBuffer filtered_png_buffer(4096); - io::BigBufferOutputStream filtered_png_buffer_out(&filtered_png_buffer); + android::BigBufferOutputStream filtered_png_buffer_out(&filtered_png_buffer); io::Copy(&filtered_png_buffer_out, &png_chunk_filter); buffer.AppendBuffer(std::move(filtered_png_buffer)); } @@ -567,7 +570,7 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options, // This will help catch exotic cases where the new code may generate larger PNGs. std::stringstream legacy_stream{std::string(content)}; android::BigBuffer legacy_buffer(4096); - Png png(context->GetDiagnostics()); + android::Png png(context->GetDiagnostics()); if (!png.process(path_data.source, &legacy_stream, &legacy_buffer, {})) { return false; } @@ -578,7 +581,7 @@ static bool CompilePng(IAaptContext* context, const CompileOptions& options, } } - io::BigBufferInputStream buffer_in(&buffer); + android::BigBufferInputStream buffer_in(&buffer); return WriteHeaderAndDataToWriter(output_path, res_file, &buffer_in, writer, context->GetDiagnostics()); } diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp index 8880089d0e20..9337cb913a0b 100644 --- a/tools/aapt2/cmd/Compile_test.cpp +++ b/tools/aapt2/cmd/Compile_test.cpp @@ -341,7 +341,7 @@ TEST_F(CompilerTest, RelativePathTest) { // Check resources.pb contains relative sources. io::IFile* proto_file = apk.get()->GetFileCollection()->FindFile("resources.pb"); - std::unique_ptr<io::InputStream> proto_stream = proto_file->OpenInputStream(); + std::unique_ptr<android::InputStream> proto_stream = proto_file->OpenInputStream(); io::ProtoInputStreamReader proto_reader(proto_stream.get()); pb::ResourceTable pb_table; proto_reader.ReadMessage(&pb_table); diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp index 387dcfe2ddf3..c132792d374b 100644 --- a/tools/aapt2/cmd/Convert.cpp +++ b/tools/aapt2/cmd/Convert.cpp @@ -24,13 +24,13 @@ #include "android-base/file.h" #include "android-base/macros.h" #include "android-base/stringprintf.h" +#include "androidfw/BigBufferStream.h" #include "androidfw/StringPiece.h" #include "cmd/Util.h" #include "format/binary/TableFlattener.h" #include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" #include "format/proto/ProtoSerialize.h" -#include "io/BigBufferStream.h" #include "io/Util.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" @@ -80,7 +80,7 @@ class BinaryApkSerializer : public IApkSerializer { return false; } - io::BigBufferInputStream input_stream(&buffer); + android::BigBufferInputStream input_stream(&buffer); return io::CopyInputStreamToArchive(context_, &input_stream, path, compression_flags, writer); } @@ -91,14 +91,14 @@ class BinaryApkSerializer : public IApkSerializer { return false; } - io::BigBufferInputStream input_stream(&buffer); + android::BigBufferInputStream input_stream(&buffer); return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath, ArchiveEntry::kAlign, writer); } bool SerializeFile(FileReference* file, IArchiveWriter* writer) override { if (file->type == ResourceFile::Type::kProtoXml) { - unique_ptr<io::InputStream> in = file->file->OpenInputStream(); + unique_ptr<android::InputStream> in = file->file->OpenInputStream(); if (in == nullptr) { context_->GetDiagnostics()->Error(android::DiagMessage(source_) << "failed to open file " << *file->path); diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index 864af06f187e..6fa9ecbfa544 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -19,19 +19,18 @@ #include <cinttypes> #include <vector> -#include "android-base/stringprintf.h" -#include "androidfw/ConfigDescription.h" -#include "androidfw/StringPiece.h" - #include "Debug.h" #include "Diagnostics.h" #include "LoadedApk.h" #include "Util.h" +#include "android-base/stringprintf.h" +#include "androidfw/ConfigDescription.h" +#include "androidfw/FileStream.h" +#include "androidfw/StringPiece.h" #include "format/Container.h" #include "format/binary/BinaryResourceParser.h" #include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" -#include "io/FileStream.h" #include "io/ZipArchive.h" #include "process/IResourceTableConsumer.h" #include "text/Printer.h" @@ -145,7 +144,7 @@ int DumpAPCCommand::Action(const std::vector<std::string>& args) { bool error = false; for (auto container : args) { - io::FileInputStream input(container); + android::FileInputStream input(container); if (input.HadError()) { context.GetDiagnostics()->Error(android::DiagMessage(container) << "failed to open file: " << input.GetError()); diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index 76d33d7aa3b2..119a59b28317 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -17,7 +17,7 @@ #ifndef AAPT2_DUMP_H #define AAPT2_DUMP_H -#include <io/FileStream.h> +#include <androidfw/FileStream.h> #include <io/ZipArchive.h> #include "Command.h" diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index c638873873dc..9ca546fc8d89 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -35,6 +35,8 @@ #include "android-base/expected.h" #include "android-base/file.h" #include "android-base/stringprintf.h" +#include "androidfw/BigBufferStream.h" +#include "androidfw/FileStream.h" #include "androidfw/IDiagnostics.h" #include "androidfw/Locale.h" #include "androidfw/StringPiece.h" @@ -48,8 +50,6 @@ #include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" #include "format/proto/ProtoSerialize.h" -#include "io/BigBufferStream.h" -#include "io/FileStream.h" #include "io/FileSystem.h" #include "io/Util.h" #include "io/ZipArchive.h" @@ -73,8 +73,8 @@ #include "util/Files.h" #include "xml/XmlDom.h" -using ::aapt::io::FileInputStream; using ::android::ConfigDescription; +using ::android::FileInputStream; using ::android::StringPiece; using ::android::base::expected; using ::android::base::StringPrintf; @@ -263,7 +263,7 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res, S return false; } - io::BigBufferInputStream input_stream(&buffer); + android::BigBufferInputStream input_stream(&buffer); return io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kCompress, writer); } break; @@ -284,7 +284,7 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res, S static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path, android::IDiagnostics* diag) { TRACE_CALL(); - FileInputStream fin(path); + android::FileInputStream fin(path); if (fin.HadError()) { diag->Error(android::DiagMessage(path) << "failed to load XML file: " << fin.GetError()); return {}; @@ -687,7 +687,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv static bool WriteStableIdMapToPath(android::IDiagnostics* diag, const std::unordered_map<ResourceName, ResourceId>& id_map, const std::string& id_map_path) { - io::FileOutputStream fout(id_map_path); + android::FileOutputStream fout(id_map_path); if (fout.HadError()) { diag->Error(android::DiagMessage(id_map_path) << "failed to open: " << fout.GetError()); return false; @@ -1197,7 +1197,7 @@ class Linker { return false; } - io::BigBufferInputStream input_stream(&buffer); + android::BigBufferInputStream input_stream(&buffer); return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath, ArchiveEntry::kAlign, writer); } break; @@ -1221,7 +1221,7 @@ class Linker { } std::string out_path; - std::unique_ptr<io::FileOutputStream> fout; + std::unique_ptr<android::FileOutputStream> fout; if (options_.generate_java_class_path) { out_path = options_.generate_java_class_path.value(); file::AppendPath(&out_path, file::PackageToPath(out_package)); @@ -1233,7 +1233,7 @@ class Linker { file::AppendPath(&out_path, "R.java"); - fout = util::make_unique<io::FileOutputStream>(out_path); + fout = util::make_unique<android::FileOutputStream>(out_path); if (fout->HadError()) { context_->GetDiagnostics()->Error(android::DiagMessage() << "failed writing to '" << out_path @@ -1242,9 +1242,9 @@ class Linker { } } - std::unique_ptr<io::FileOutputStream> fout_text; + std::unique_ptr<android::FileOutputStream> fout_text; if (out_text_symbols_path) { - fout_text = util::make_unique<io::FileOutputStream>(out_text_symbols_path.value()); + fout_text = util::make_unique<android::FileOutputStream>(out_text_symbols_path.value()); if (fout_text->HadError()) { context_->GetDiagnostics()->Error(android::DiagMessage() << "failed writing to '" << out_text_symbols_path.value() @@ -1386,7 +1386,7 @@ class Linker { file::AppendPath(&out_path, "Manifest.java"); - io::FileOutputStream fout(out_path); + android::FileOutputStream fout(out_path); if (fout.HadError()) { context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path << "': " << fout.GetError()); @@ -1412,7 +1412,7 @@ class Linker { } const std::string& out_path = out.value(); - io::FileOutputStream fout(out_path); + android::FileOutputStream fout(out_path); if (fout.HadError()) { context_->GetDiagnostics()->Error(android::DiagMessage() << "failed to open '" << out_path << "': " << fout.GetError()); @@ -1601,7 +1601,7 @@ class Linker { } } - std::unique_ptr<io::InputStream> input_stream = file->OpenInputStream(); + std::unique_ptr<android::InputStream> input_stream = file->OpenInputStream(); if (input_stream == nullptr) { context_->GetDiagnostics()->Error(android::DiagMessage(src) << "failed to open file"); return false; diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp index f045dad6d11a..762441ee1872 100644 --- a/tools/aapt2/cmd/Optimize.cpp +++ b/tools/aapt2/cmd/Optimize.cpp @@ -30,6 +30,7 @@ #include "ValueVisitor.h" #include "android-base/file.h" #include "android-base/stringprintf.h" +#include "androidfw/BigBufferStream.h" #include "androidfw/ConfigDescription.h" #include "androidfw/IDiagnostics.h" #include "androidfw/ResourceTypes.h" @@ -39,7 +40,6 @@ #include "filter/AbiFilter.h" #include "format/binary/TableFlattener.h" #include "format/binary/XmlFlattener.h" -#include "io/BigBufferStream.h" #include "io/Util.h" #include "optimize/MultiApkGenerator.h" #include "optimize/Obfuscator.h" @@ -249,7 +249,7 @@ class Optimizer { return false; } - io::BigBufferInputStream manifest_buffer_in(&manifest_buffer); + android::BigBufferInputStream manifest_buffer_in(&manifest_buffer); if (!io::CopyInputStreamToArchive(context_, &manifest_buffer_in, "AndroidManifest.xml", ArchiveEntry::kCompress, writer)) { return false; @@ -297,7 +297,7 @@ class Optimizer { return false; } - io::BigBufferInputStream table_buffer_in(&table_buffer); + android::BigBufferInputStream table_buffer_in(&table_buffer); return io::CopyInputStreamToArchive(context_, &table_buffer_in, "resources.arsc", ArchiveEntry::kAlign, writer); } diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp index a2b48187c24f..a5962292b5b0 100644 --- a/tools/aapt2/dump/DumpManifest.cpp +++ b/tools/aapt2/dump/DumpManifest.cpp @@ -29,8 +29,8 @@ #include "SdkConstants.h" #include "ValueVisitor.h" #include "androidfw/ConfigDescription.h" +#include "androidfw/FileStream.h" #include "io/File.h" -#include "io/FileStream.h" #include "process/IResourceTableConsumer.h" #include "xml/XmlDom.h" diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp index e9a93d8b12ad..91768a09ea59 100644 --- a/tools/aapt2/format/Archive.cpp +++ b/tools/aapt2/format/Archive.cpp @@ -91,7 +91,7 @@ class DirectoryWriter : public IArchiveWriter { return true; } - bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override { + bool WriteFile(StringPiece path, uint32_t flags, android::InputStream* in) override { if (!StartEntry(path, flags)) { return false; } @@ -182,7 +182,7 @@ class ZipFileWriter : public IArchiveWriter { return true; } - bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override { + bool WriteFile(StringPiece path, uint32_t flags, android::InputStream* in) override { while (true) { if (!StartEntry(path, flags)) { return false; diff --git a/tools/aapt2/format/Archive.h b/tools/aapt2/format/Archive.h index 6cde753a255d..3c3d0ab74c52 100644 --- a/tools/aapt2/format/Archive.h +++ b/tools/aapt2/format/Archive.h @@ -24,9 +24,9 @@ #include "androidfw/BigBuffer.h" #include "androidfw/IDiagnostics.h" +#include "androidfw/Streams.h" #include "androidfw/StringPiece.h" #include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include "io/Io.h" #include "util/Files.h" namespace aapt { @@ -46,7 +46,7 @@ class IArchiveWriter : public ::google::protobuf::io::CopyingOutputStream { public: virtual ~IArchiveWriter() = default; - virtual bool WriteFile(android::StringPiece path, uint32_t flags, io::InputStream* in) = 0; + virtual bool WriteFile(android::StringPiece path, uint32_t flags, android::InputStream* in) = 0; // Starts a new entry and allows caller to write bytes to it sequentially. // Only use StartEntry if code you do not control needs to write to a CopyingOutputStream. diff --git a/tools/aapt2/format/Archive_test.cpp b/tools/aapt2/format/Archive_test.cpp index fd50af92ceee..df105f8a83e5 100644 --- a/tools/aapt2/format/Archive_test.cpp +++ b/tools/aapt2/format/Archive_test.cpp @@ -95,7 +95,7 @@ void VerifyDirectory(const std::string& path, const std::string& file, const uin void VerifyZipFile(const std::string& output_path, const std::string& file, const uint8_t array[]) { std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr); - std::unique_ptr<io::InputStream> stream = zip->FindFile(file)->OpenInputStream(); + std::unique_ptr<android::InputStream> stream = zip->FindFile(file)->OpenInputStream(); std::vector<uint8_t> buffer; const void* data; diff --git a/tools/aapt2/format/Container.cpp b/tools/aapt2/format/Container.cpp index 1ff6c4996b91..cb4a225c73e7 100644 --- a/tools/aapt2/format/Container.cpp +++ b/tools/aapt2/format/Container.cpp @@ -94,7 +94,7 @@ bool ContainerWriter::AddResTableEntry(const pb::ResourceTable& table) { } bool ContainerWriter::AddResFileEntry(const pb::internal::CompiledFile& file, - io::KnownSizeInputStream* in) { + android::KnownSizeInputStream* in) { if (current_entry_count_ >= total_entry_count_) { error_ = "too many entries being serialized"; return false; @@ -264,7 +264,7 @@ std::string ContainerReaderEntry::GetError() const { return reader_->GetError(); } -ContainerReader::ContainerReader(io::InputStream* in) +ContainerReader::ContainerReader(android::InputStream* in) : in_(in), adaptor_(in), coded_in_(&adaptor_), diff --git a/tools/aapt2/format/Container.h b/tools/aapt2/format/Container.h index 121c592537bf..c5d567697a5a 100644 --- a/tools/aapt2/format/Container.h +++ b/tools/aapt2/format/Container.h @@ -22,9 +22,9 @@ #include "Resources.pb.h" #include "ResourcesInternal.pb.h" #include "androidfw/BigBuffer.h" +#include "androidfw/Streams.h" #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/zero_copy_stream.h" -#include "io/Io.h" #include "io/Util.h" namespace aapt { @@ -39,7 +39,7 @@ class ContainerWriter { explicit ContainerWriter(::google::protobuf::io::ZeroCopyOutputStream* out, size_t entry_count); bool AddResTableEntry(const pb::ResourceTable& table); - bool AddResFileEntry(const pb::internal::CompiledFile& file, io::KnownSizeInputStream* in); + bool AddResFileEntry(const pb::internal::CompiledFile& file, android::KnownSizeInputStream* in); bool HadError() const; std::string GetError() const; @@ -79,7 +79,7 @@ class ContainerReaderEntry { class ContainerReader { public: - explicit ContainerReader(io::InputStream* in); + explicit ContainerReader(android::InputStream* in); ContainerReaderEntry* Next(); @@ -91,7 +91,7 @@ class ContainerReader { friend class ContainerReaderEntry; - io::InputStream* in_; + android::InputStream* in_; io::ZeroCopyInputAdaptor adaptor_; ::google::protobuf::io::CodedInputStream coded_in_; size_t total_entry_count_; diff --git a/tools/aapt2/io/Data.h b/tools/aapt2/io/Data.h index db91a77a5ae6..29f523aeff1b 100644 --- a/tools/aapt2/io/Data.h +++ b/tools/aapt2/io/Data.h @@ -20,15 +20,14 @@ #include <memory> #include "android-base/macros.h" +#include "androidfw/Streams.h" #include "utils/FileMap.h" -#include "io/Io.h" - namespace aapt { namespace io { // Interface for a block of contiguous memory. An instance of this interface owns the data. -class IData : public KnownSizeInputStream { +class IData : public android::KnownSizeInputStream { public: virtual ~IData() = default; diff --git a/tools/aapt2/io/File.cpp b/tools/aapt2/io/File.cpp index b4f1ff3a5b49..4dfdb5bb8ad9 100644 --- a/tools/aapt2/io/File.cpp +++ b/tools/aapt2/io/File.cpp @@ -39,7 +39,7 @@ std::unique_ptr<IData> FileSegment::OpenAsData() { return {}; } -std::unique_ptr<io::InputStream> FileSegment::OpenInputStream() { +std::unique_ptr<android::InputStream> FileSegment::OpenInputStream() { return OpenAsData(); } diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h index 673d1b75e660..248756b51f2e 100644 --- a/tools/aapt2/io/File.h +++ b/tools/aapt2/io/File.h @@ -43,7 +43,7 @@ class IFile { // Returns nullptr on failure. virtual std::unique_ptr<IData> OpenAsData() = 0; - virtual std::unique_ptr<io::InputStream> OpenInputStream() = 0; + virtual std::unique_ptr<android::InputStream> OpenInputStream() = 0; // Returns the source of this file. This is for presentation to the user and // may not be a valid file system path (for example, it may contain a '@' sign to separate @@ -78,7 +78,7 @@ class FileSegment : public IFile { : file_(file), offset_(offset), len_(len) {} std::unique_ptr<IData> OpenAsData() override; - std::unique_ptr<io::InputStream> OpenInputStream() override; + std::unique_ptr<android::InputStream> OpenInputStream() override; const android::Source& GetSource() const override { return file_->GetSource(); diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp index 6a692e497816..03fabcc4dcce 100644 --- a/tools/aapt2/io/FileSystem.cpp +++ b/tools/aapt2/io/FileSystem.cpp @@ -22,9 +22,9 @@ #include <sys/stat.h> #include "android-base/errors.h" +#include "androidfw/FileStream.h" #include "androidfw/Source.h" #include "androidfw/StringPiece.h" -#include "io/FileStream.h" #include "util/Files.h" #include "util/Util.h" #include "utils/FileMap.h" @@ -49,8 +49,8 @@ std::unique_ptr<IData> RegularFile::OpenAsData() { return {}; } -std::unique_ptr<io::InputStream> RegularFile::OpenInputStream() { - return util::make_unique<FileInputStream>(source_.path); +std::unique_ptr<android::InputStream> RegularFile::OpenInputStream() { + return util::make_unique<android::FileInputStream>(source_.path); } const android::Source& RegularFile::GetSource() const { diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h index f975196b9cfa..d6ecfebab67d 100644 --- a/tools/aapt2/io/FileSystem.h +++ b/tools/aapt2/io/FileSystem.h @@ -30,7 +30,7 @@ class RegularFile : public IFile { explicit RegularFile(const android::Source& source); std::unique_ptr<IData> OpenAsData() override; - std::unique_ptr<io::InputStream> OpenInputStream() override; + std::unique_ptr<android::InputStream> OpenInputStream() override; const android::Source& GetSource() const override; bool GetModificationTime(struct tm* buf) const override; diff --git a/tools/aapt2/io/StringStream.cpp b/tools/aapt2/io/StringStream.cpp index 9c497882b99b..bb3911b20175 100644 --- a/tools/aapt2/io/StringStream.cpp +++ b/tools/aapt2/io/StringStream.cpp @@ -51,6 +51,23 @@ size_t StringInputStream::TotalSize() const { return str_.size(); } +bool StringInputStream::ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) { + if (byte_count == 0) { + return true; + } + if (offset < 0) { + return false; + } + if (offset > std::numeric_limits<off64_t>::max() - byte_count) { + return false; + } + if (offset + byte_count > str_.size()) { + return false; + } + memcpy(data, str_.data() + offset, byte_count); + return true; +} + StringOutputStream::StringOutputStream(std::string* str, size_t buffer_capacity) : str_(str), buffer_capacity_(buffer_capacity), diff --git a/tools/aapt2/io/StringStream.h b/tools/aapt2/io/StringStream.h index f7bdecca0dee..7e1abe583170 100644 --- a/tools/aapt2/io/StringStream.h +++ b/tools/aapt2/io/StringStream.h @@ -17,17 +17,16 @@ #ifndef AAPT_IO_STRINGSTREAM_H #define AAPT_IO_STRINGSTREAM_H -#include "io/Io.h" - #include <memory> #include "android-base/macros.h" +#include "androidfw/Streams.h" #include "androidfw/StringPiece.h" namespace aapt { namespace io { -class StringInputStream : public KnownSizeInputStream { +class StringInputStream : public android::KnownSizeInputStream { public: explicit StringInputStream(android::StringPiece str); @@ -47,6 +46,8 @@ class StringInputStream : public KnownSizeInputStream { size_t TotalSize() const override; + bool ReadFullyAtOffset(void* data, size_t byte_count, off64_t offset) override; + private: DISALLOW_COPY_AND_ASSIGN(StringInputStream); @@ -54,7 +55,7 @@ class StringInputStream : public KnownSizeInputStream { size_t offset_; }; -class StringOutputStream : public OutputStream { +class StringOutputStream : public android::OutputStream { public: explicit StringOutputStream(std::string* str, size_t buffer_capacity = 4096u); diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp index 79d8d527fe8b..9616e479eda0 100644 --- a/tools/aapt2/io/Util.cpp +++ b/tools/aapt2/io/Util.cpp @@ -26,8 +26,9 @@ using ::google::protobuf::io::ZeroCopyOutputStream; namespace aapt { namespace io { -bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path, - uint32_t compression_flags, IArchiveWriter* writer) { +bool CopyInputStreamToArchive(IAaptContext* context, android::InputStream* in, + std::string_view out_path, uint32_t compression_flags, + IArchiveWriter* writer) { TRACE_CALL(); if (context->IsVerbose()) { context->GetDiagnostics()->Note(android::DiagMessage() @@ -91,7 +92,7 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* prot return false; } -bool Copy(OutputStream* out, InputStream* in) { +bool Copy(android::OutputStream* out, android::InputStream* in) { TRACE_CALL(); const void* in_buffer; size_t in_len; @@ -110,7 +111,7 @@ bool Copy(OutputStream* out, InputStream* in) { return !in->HadError(); } -bool Copy(OutputStream* out, StringPiece in) { +bool Copy(android::OutputStream* out, StringPiece in) { const char* in_buffer = in.data(); size_t in_len = in.size(); while (in_len != 0) { @@ -129,7 +130,7 @@ bool Copy(OutputStream* out, StringPiece in) { return true; } -bool Copy(ZeroCopyOutputStream* out, InputStream* in) { +bool Copy(ZeroCopyOutputStream* out, android::InputStream* in) { OutputStreamAdaptor adaptor(out); return Copy(&adaptor, in); } diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h index 685f522a2e71..25aa8f8d1916 100644 --- a/tools/aapt2/io/Util.h +++ b/tools/aapt2/io/Util.h @@ -19,18 +19,19 @@ #include <string_view> +#include "androidfw/Streams.h" #include "format/Archive.h" #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/message.h" #include "io/File.h" -#include "io/Io.h" #include "process/IResourceTableConsumer.h" namespace aapt { namespace io { -bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path, - uint32_t compression_flags, IArchiveWriter* writer); +bool CopyInputStreamToArchive(IAaptContext* context, android::InputStream* in, + std::string_view out_path, uint32_t compression_flags, + IArchiveWriter* writer); bool CopyFileToArchive(IAaptContext* context, IFile* file, std::string_view out_path, uint32_t compression_flags, IArchiveWriter* writer); @@ -44,11 +45,11 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* prot // Copies the data from in to out. Returns false if there was an error. // If there was an error, check the individual streams' HadError/GetError methods. -bool Copy(OutputStream* out, InputStream* in); -bool Copy(OutputStream* out, android::StringPiece in); -bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in); +bool Copy(android::OutputStream* out, android::InputStream* in); +bool Copy(android::OutputStream* out, android::StringPiece in); +bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, android::InputStream* in); -class OutputStreamAdaptor : public io::OutputStream { +class OutputStreamAdaptor : public android::OutputStream { public: explicit OutputStreamAdaptor(::google::protobuf::io::ZeroCopyOutputStream* out) : out_(out) { } @@ -84,7 +85,7 @@ class OutputStreamAdaptor : public io::OutputStream { class ZeroCopyInputAdaptor : public ::google::protobuf::io::ZeroCopyInputStream { public: - explicit ZeroCopyInputAdaptor(io::InputStream* in) : in_(in) { + explicit ZeroCopyInputAdaptor(android::InputStream* in) : in_(in) { } bool Next(const void** data, int* size) override { @@ -119,12 +120,13 @@ class ZeroCopyInputAdaptor : public ::google::protobuf::io::ZeroCopyInputStream private: DISALLOW_COPY_AND_ASSIGN(ZeroCopyInputAdaptor); - io::InputStream* in_; + android::InputStream* in_; }; class ProtoInputStreamReader { public: - explicit ProtoInputStreamReader(io::InputStream* in) : in_(in) { } + explicit ProtoInputStreamReader(android::InputStream* in) : in_(in) { + } /** Deserializes a Message proto from the current position in the input stream.*/ template <typename T> bool ReadMessage(T *message) { @@ -135,7 +137,7 @@ class ProtoInputStreamReader { } private: - io::InputStream* in_; + android::InputStream* in_; }; } // namespace io diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp index cb5bbe96b8b7..e44d61e08899 100644 --- a/tools/aapt2/io/ZipArchive.cpp +++ b/tools/aapt2/io/ZipArchive.cpp @@ -63,7 +63,7 @@ std::unique_ptr<IData> ZipFile::OpenAsData() { } } -std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() { +std::unique_ptr<android::InputStream> ZipFile::OpenInputStream() { return OpenAsData(); } diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h index ac125d097983..a53c4a2e39f8 100644 --- a/tools/aapt2/io/ZipArchive.h +++ b/tools/aapt2/io/ZipArchive.h @@ -35,7 +35,7 @@ class ZipFile : public IFile { ZipFile(::ZipArchiveHandle handle, const ::ZipEntry& entry, const android::Source& source); std::unique_ptr<IData> OpenAsData() override; - std::unique_ptr<io::InputStream> OpenInputStream() override; + std::unique_ptr<android::InputStream> OpenInputStream() override; const android::Source& GetSource() const override; bool WasCompressed() override; bool GetModificationTime(struct tm* buf) const override; diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp index 98f3bd2018b0..db7aa35d5ad4 100644 --- a/tools/aapt2/java/ClassDefinition.cpp +++ b/tools/aapt2/java/ClassDefinition.cpp @@ -111,7 +111,7 @@ constexpr static const char* sWarningHeader = " */\n\n"; void ClassDefinition::WriteJavaFile(const ClassDefinition* def, StringPiece package, bool final, - bool strip_api_annotations, io::OutputStream* out) { + bool strip_api_annotations, android::OutputStream* out) { Printer printer(out); printer.Print(sWarningHeader).Print("package ").Print(package).Println(";"); printer.Println(); diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h index 63c99821a836..84e3f33db941 100644 --- a/tools/aapt2/java/ClassDefinition.h +++ b/tools/aapt2/java/ClassDefinition.h @@ -241,7 +241,7 @@ enum class ClassQualifier { kNone, kStatic }; class ClassDefinition : public ClassMember { public: static void WriteJavaFile(const ClassDefinition* def, android::StringPiece package, bool final, - bool strip_api_annotations, io::OutputStream* out); + bool strip_api_annotations, android::OutputStream* out); ClassDefinition(android::StringPiece name, ClassQualifier qualifier, bool createIfEmpty) : name_(name), qualifier_(qualifier), create_if_empty_(createIfEmpty) { diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp index 7665d0e8d9cb..58f656458177 100644 --- a/tools/aapt2/java/JavaClassGenerator.cpp +++ b/tools/aapt2/java/JavaClassGenerator.cpp @@ -37,8 +37,8 @@ #include "java/ClassDefinition.h" #include "process/SymbolTable.h" -using ::aapt::io::OutputStream; using ::aapt::text::Printer; +using ::android::OutputStream; using ::android::StringPiece; using ::android::base::StringPrintf; diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h index 234df04472ce..9909eeccb6ac 100644 --- a/tools/aapt2/java/JavaClassGenerator.h +++ b/tools/aapt2/java/JavaClassGenerator.h @@ -19,11 +19,10 @@ #include <string> -#include "androidfw/StringPiece.h" - #include "ResourceTable.h" #include "ResourceValues.h" -#include "io/Io.h" +#include "androidfw/Streams.h" +#include "androidfw/StringPiece.h" #include "process/IResourceTableConsumer.h" #include "process/SymbolTable.h" #include "text/Printer.h" @@ -70,12 +69,12 @@ class JavaClassGenerator { // All symbols technically belong to a single package, but linked libraries will // have their names mangled, denoting that they came from a different package. // We need to generate these symbols in a separate file. Returns true on success. - bool Generate(android::StringPiece package_name_to_generate, io::OutputStream* out, - io::OutputStream* out_r_txt = nullptr); + bool Generate(android::StringPiece package_name_to_generate, android::OutputStream* out, + android::OutputStream* out_r_txt = nullptr); bool Generate(android::StringPiece package_name_to_generate, - android::StringPiece output_package_name, io::OutputStream* out, - io::OutputStream* out_r_txt = nullptr); + android::StringPiece output_package_name, android::OutputStream* out, + android::OutputStream* out_r_txt = nullptr); const std::string& GetError() const; diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp index 80a46d553960..aef48fc102d7 100644 --- a/tools/aapt2/java/ProguardRules.cpp +++ b/tools/aapt2/java/ProguardRules.cpp @@ -29,8 +29,8 @@ #include "util/Util.h" #include "xml/XmlDom.h" -using ::aapt::io::OutputStream; using ::aapt::text::Printer; +using ::android::OutputStream; namespace aapt { namespace proguard { diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h index 267f7ede274a..876ef48042f5 100644 --- a/tools/aapt2/java/ProguardRules.h +++ b/tools/aapt2/java/ProguardRules.h @@ -26,8 +26,8 @@ #include "ResourceTable.h" #include "ValueVisitor.h" #include "androidfw/Source.h" +#include "androidfw/Streams.h" #include "androidfw/StringPiece.h" -#include "io/Io.h" #include "process/IResourceTableConsumer.h" #include "xml/XmlDom.h" @@ -69,7 +69,7 @@ class KeepSet { } private: - friend void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep, + friend void WriteKeepSet(const KeepSet& keep_set, android::OutputStream* out, bool minimal_keep, bool no_location_reference); friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, @@ -89,7 +89,7 @@ bool CollectProguardRules(IAaptContext* context, xml::XmlResource* res, KeepSet* bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set); -void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep, +void WriteKeepSet(const KeepSet& keep_set, android::OutputStream* out, bool minimal_keep, bool no_location_reference); bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set, diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h index e48668cf96a3..04379804d8ee 100644 --- a/tools/aapt2/test/Common.h +++ b/tools/aapt2/test/Common.h @@ -90,7 +90,7 @@ class TestFile : public io::IFile { return {}; } - std::unique_ptr<io::InputStream> OpenInputStream() override { + std::unique_ptr<android::InputStream> OpenInputStream() override { return OpenAsData(); } diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp index 428372f31d0d..b91abe572306 100644 --- a/tools/aapt2/test/Fixture.cpp +++ b/tools/aapt2/test/Fixture.cpp @@ -20,6 +20,7 @@ #include <android-base/file.h> #include <android-base/stringprintf.h> #include <android-base/utf8.h> +#include <androidfw/FileStream.h> #include <androidfw/StringPiece.h> #include <dirent.h> #include <gmock/gmock.h> @@ -28,7 +29,6 @@ #include "Diagnostics.h" #include "cmd/Compile.h" #include "cmd/Link.h" -#include "io/FileStream.h" #include "util/Files.h" using testing::Eq; diff --git a/tools/aapt2/text/Printer.cpp b/tools/aapt2/text/Printer.cpp index 8e491aca794d..c2fa8cccd536 100644 --- a/tools/aapt2/text/Printer.cpp +++ b/tools/aapt2/text/Printer.cpp @@ -20,7 +20,7 @@ #include "io/Util.h" -using ::aapt::io::OutputStream; +using ::android::OutputStream; using ::android::StringPiece; namespace aapt { diff --git a/tools/aapt2/text/Printer.h b/tools/aapt2/text/Printer.h index f7ad98bfd981..44f0fc546c7c 100644 --- a/tools/aapt2/text/Printer.h +++ b/tools/aapt2/text/Printer.h @@ -18,17 +18,16 @@ #define AAPT_TEXT_PRINTER_H #include "android-base/macros.h" +#include "androidfw/Streams.h" #include "androidfw/StringPiece.h" -#include "io/Io.h" - namespace aapt { namespace text { // An indenting Printer that helps write formatted text to the OutputStream. class Printer { public: - explicit Printer(::aapt::io::OutputStream* out) : out_(out) { + explicit Printer(android::OutputStream* out) : out_(out) { } Printer& Print(android::StringPiece str); @@ -41,7 +40,7 @@ class Printer { private: DISALLOW_COPY_AND_ASSIGN(Printer); - ::aapt::io::OutputStream* out_; + android::OutputStream* out_; int indent_level_ = 0; bool needs_indent_ = false; bool error_ = false; diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index 8dea8ea52f92..49807db26bb7 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -30,7 +30,7 @@ #include "XmlPullParser.h" #include "util/Util.h" -using ::aapt::io::InputStream; +using ::android::InputStream; using ::android::StringPiece; using ::android::StringPiece16; diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h index c253b0a1f4a9..9668b6a6e8ef 100644 --- a/tools/aapt2/xml/XmlDom.h +++ b/tools/aapt2/xml/XmlDom.h @@ -24,8 +24,8 @@ #include "Resource.h" #include "ResourceValues.h" #include "androidfw/IDiagnostics.h" +#include "androidfw/Streams.h" #include "androidfw/StringPiece.h" -#include "io/Io.h" #include "util/Util.h" #include "xml/XmlUtil.h" @@ -152,7 +152,7 @@ class XmlResource { }; // Inflates an XML DOM from an InputStream, logging errors to the logger. -std::unique_ptr<XmlResource> Inflate(io::InputStream* in, android::IDiagnostics* diag, +std::unique_ptr<XmlResource> Inflate(android::InputStream* in, android::IDiagnostics* diag, const android::Source& source); // Inflates an XML DOM from a binary ResXMLTree. diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp index d79446bfae6f..203832d2dbe8 100644 --- a/tools/aapt2/xml/XmlPullParser.cpp +++ b/tools/aapt2/xml/XmlPullParser.cpp @@ -21,7 +21,7 @@ #include "xml/XmlPullParser.h" #include "xml/XmlUtil.h" -using ::aapt::io::InputStream; +using ::android::InputStream; using ::android::StringPiece; namespace aapt { diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h index fe4cd018d808..655e6dc93e75 100644 --- a/tools/aapt2/xml/XmlPullParser.h +++ b/tools/aapt2/xml/XmlPullParser.h @@ -27,11 +27,10 @@ #include <string> #include <vector> +#include "Resource.h" #include "android-base/macros.h" +#include "androidfw/Streams.h" #include "androidfw/StringPiece.h" - -#include "Resource.h" -#include "io/Io.h" #include "process/IResourceTableConsumer.h" #include "xml/XmlUtil.h" @@ -66,7 +65,7 @@ class XmlPullParser : public IPackageDeclStack { static bool SkipCurrentElement(XmlPullParser* parser); static bool IsGoodEvent(Event event); - explicit XmlPullParser(io::InputStream* in); + explicit XmlPullParser(android::InputStream* in); ~XmlPullParser(); /** @@ -179,7 +178,7 @@ class XmlPullParser : public IPackageDeclStack { std::vector<Attribute> attributes; }; - io::InputStream* in_; + android::InputStream* in_; XML_Parser parser_; std::queue<EventData> event_queue_; std::string error_; diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING index 192b6f2b5e25..eca258c5a74d 100644 --- a/tools/hoststubgen/TEST_MAPPING +++ b/tools/hoststubgen/TEST_MAPPING @@ -1,11 +1,13 @@ { - "presubmit": [ - { "name": "tiny-framework-dump-test" }, - { "name": "hoststubgentest" }, - { "name": "hoststubgen-invoke-test" } - - // As a smoke test. - // TODO: Enable it once the infra knows how to run it. - // { "name": "CtsUtilTestCasesRavenwood" } - ] + "presubmit": [ + { "name": "tiny-framework-dump-test" }, + { "name": "hoststubgentest" }, + { "name": "hoststubgen-invoke-test" } + ], + "ravenwood-presubmit": [ + { + "name": "CtsUtilTestCasesRavenwood", + "host": true + } + ] } diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp index d415dc508587..0e2e158c327e 100644 --- a/tools/hoststubgen/hoststubgen/Android.bp +++ b/tools/hoststubgen/hoststubgen/Android.bp @@ -284,6 +284,7 @@ java_library_host { java_host_for_device { name: "hoststubgen-helper-libcore-runtime.ravenwood", + defaults: ["hoststubgen-for-prototype-only-java"], libs: [ "hoststubgen-helper-libcore-runtime", ], diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java index 22553451e128..3bcabcb01c5e 100644 --- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java +++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java @@ -15,9 +15,6 @@ */ package com.android.hoststubgen.nativesubstitution; -import android.os.IBinder; - -import java.io.FileDescriptor; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -143,12 +140,6 @@ public class Parcel_host { public static void nativeMarkSensitive(long nativePtr) { getInstance(nativePtr).mSensitive = true; } - public static void nativeMarkForBinder(long nativePtr, IBinder binder) { - throw new RuntimeException("Not implemented yet"); - } - public static boolean nativeIsForRpc(long nativePtr) { - throw new RuntimeException("Not implemented yet"); - } public static int nativeDataSize(long nativePtr) { return getInstance(nativePtr).mSize; } @@ -236,9 +227,6 @@ public class Parcel_host { public static int nativeWriteDouble(long nativePtr, double val) { return nativeWriteLong(nativePtr, Double.doubleToLongBits(val)); } - public static void nativeSignalExceptionForError(int error) { - throw new RuntimeException("Not implemented yet"); - } private static int align4(int val) { return ((val + 3) / 4) * 4; @@ -256,12 +244,6 @@ public class Parcel_host { // Just reuse String8 nativeWriteString8(nativePtr, val); } - public static void nativeWriteStrongBinder(long nativePtr, IBinder val) { - throw new RuntimeException("Not implemented yet"); - } - public static void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val) { - throw new RuntimeException("Not implemented yet"); - } public static byte[] nativeCreateByteArray(long nativePtr) { return nativeReadBlob(nativePtr); @@ -348,12 +330,6 @@ public class Parcel_host { public static String nativeReadString16(long nativePtr) { return nativeReadString8(nativePtr); } - public static IBinder nativeReadStrongBinder(long nativePtr) { - throw new RuntimeException("Not implemented yet"); - } - public static FileDescriptor nativeReadFileDescriptor(long nativePtr) { - throw new RuntimeException("Not implemented yet"); - } public static byte[] nativeMarshall(long nativePtr) { var p = getInstance(nativePtr); @@ -367,13 +343,6 @@ public class Parcel_host { p.mPos += length; p.updateSize(); } - public static int nativeCompareData(long thisNativePtr, long otherNativePtr) { - throw new RuntimeException("Not implemented yet"); - } - public static boolean nativeCompareDataInRange( - long ptrA, int offsetA, long ptrB, int offsetB, int length) { - throw new RuntimeException("Not implemented yet"); - } public static void nativeAppendFrom( long thisNativePtr, long otherNativePtr, int srcOffset, int length) { var dst = getInstance(thisNativePtr); @@ -397,28 +366,4 @@ public class Parcel_host { // Assume false for now, because we don't support writing FDs yet. return false; } - public static void nativeWriteInterfaceToken(long nativePtr, String interfaceName) { - throw new RuntimeException("Not implemented yet"); - } - public static void nativeEnforceInterface(long nativePtr, String interfaceName) { - throw new RuntimeException("Not implemented yet"); - } - - public static boolean nativeReplaceCallingWorkSourceUid( - long nativePtr, int workSourceUid) { - throw new RuntimeException("Not implemented yet"); - } - public static int nativeReadCallingWorkSourceUid(long nativePtr) { - throw new RuntimeException("Not implemented yet"); - } - - public static long nativeGetOpenAshmemSize(long nativePtr) { - throw new RuntimeException("Not implemented yet"); - } - public static long getGlobalAllocSize() { - throw new RuntimeException("Not implemented yet"); - } - public static long getGlobalAllocCount() { - throw new RuntimeException("Not implemented yet"); - } } diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenKeptInImpl.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenKeptInImpl.java new file mode 100644 index 000000000000..2cc500f527c0 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenKeptInImpl.java @@ -0,0 +1,35 @@ +/* + * 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.hoststubgen.hosthelper; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation injected to all classes/methods/fields that are kept in the "impl" jar. + */ +@Target({TYPE, METHOD, CONSTRUCTOR, FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface HostStubGenKeptInImpl { + String CLASS_INTERNAL_NAME = HostTestUtils.getInternalName(HostStubGenKeptInImpl.class); + String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";"; +} diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenKeptInStub.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenKeptInStub.java new file mode 100644 index 000000000000..12b9875fcf53 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenKeptInStub.java @@ -0,0 +1,38 @@ +/* + * 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.hoststubgen.hosthelper; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation injected to all classes/methods/fields that are kept in the "stub" jar. + * + * All items in the stub jar are automatically kept in the impl jar as well, so + * the items with this annotation will all have {@link HostStubGenKeptInImpl} too. + */ +@Target({TYPE, METHOD, CONSTRUCTOR, FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface HostStubGenKeptInStub { + String CLASS_INTERNAL_NAME = HostTestUtils.getInternalName(HostStubGenKeptInStub.class); + String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";"; +} diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsIgnore.java index 7ada961d710f..cb50404c96d9 100644 --- a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java +++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsIgnore.java @@ -15,18 +15,20 @@ */ package com.android.hoststubgen.hosthelper; -import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.METHOD; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotation added to all "stub" classes generated by HostStubGen. + * Annotation injected to all methods processed as "ignore". + * + * (This annotation is only added in the impl jar, but not the stub jar) */ -@Target({TYPE}) +@Target({METHOD}) @Retention(RetentionPolicy.RUNTIME) -public @interface HostStubGenProcessedKeepClass { - String CLASS_INTERNAL_NAME = HostTestUtils.getInternalName(HostStubGenProcessedKeepClass.class); +public @interface HostStubGenProcessedAsIgnore { + String CLASS_INTERNAL_NAME = HostTestUtils.getInternalName(HostStubGenProcessedAsIgnore.class); String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";"; } diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsSubstitute.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsSubstitute.java new file mode 100644 index 000000000000..cfa4896fdfa0 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsSubstitute.java @@ -0,0 +1,38 @@ +/* + * 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.hoststubgen.hosthelper; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation injected to all methods that are processed as "substitute". + * + * (This annotation is only added in the impl jar, but not the stub jar) + */ +@Target({TYPE, METHOD, CONSTRUCTOR, FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface HostStubGenProcessedAsSubstitute { + String CLASS_INTERNAL_NAME = HostTestUtils.getInternalName( + HostStubGenProcessedAsSubstitute.class); + String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";"; +} diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsThrow.java index e598da0a3cb9..0d2da114da97 100644 --- a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java +++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedAsThrow.java @@ -15,18 +15,20 @@ */ package com.android.hoststubgen.hosthelper; -import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.METHOD; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotation added to all "stub" classes generated by HostStubGen. + * Annotation injected to all methods that are processed as "throw". + * + * (This annotation is only added in the impl jar, but not the stub jar) */ -@Target({TYPE}) +@Target({METHOD}) @Retention(RetentionPolicy.RUNTIME) -public @interface HostStubGenProcessedStubClass { - String CLASS_INTERNAL_NAME = HostTestUtils.getInternalName(HostStubGenProcessedStubClass.class); +public @interface HostStubGenProcessedAsThrow { + String CLASS_INTERNAL_NAME = HostTestUtils.getInternalName(HostStubGenProcessedAsThrow.class); String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";"; } diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java index c770b9ccc800..7c6aa25bf5ea 100644 --- a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java +++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java @@ -23,8 +23,6 @@ import java.util.HashMap; import javax.annotation.concurrent.GuardedBy; -import org.junit.AssumptionViolatedException; - /** * Utilities used in the host side test environment. */ @@ -128,7 +126,7 @@ public class HostTestUtils { } } // All processed classes have this annotation. - var allowed = clazz.getAnnotation(HostStubGenProcessedKeepClass.class) != null; + var allowed = clazz.getAnnotation(HostStubGenKeptInImpl.class) != null; // Java classes should be able to access any methods. (via callbacks, etc.) if (!allowed) { diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt index 207ba52685f8..910bf59b3d8d 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt @@ -46,3 +46,7 @@ class UnknownApiException(message: String) : Exception(message), UserErrorExcept */ class InvalidAnnotationException(message: String) : Exception(message), UserErrorException +/** + * We use this for general "user" errors. + */ +class HostStubGenUserErrorException(message: String) : Exception(message), UserErrorException diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt index 4e0cd094da92..97e09b817ef6 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt @@ -128,7 +128,7 @@ class HostStubGen(val options: HostStubGenOptions) { } val end = System.currentTimeMillis() - log.v("Done reading class structure in %.1f second(s).", (end - start) / 1000.0) + log.i("Done reading class structure in %.1f second(s).", (end - start) / 1000.0) return allClasses } @@ -158,7 +158,7 @@ class HostStubGen(val options: HostStubGenOptions) { // This is used when a member (methods, fields, nested classes) don't get any polices // from upper filters. e.g. when a method has no annotations, then this filter will apply // the class-wide policy, if any. (if not, we'll fall back to the above filter.) - filter = ClassWidePolicyPropagatingFilter(filter) + filter = ClassWidePolicyPropagatingFilter(allClasses, filter) // Inject default hooks from options. filter = DefaultHookInjectingFilter( diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt index 9df04892ddbd..6b01d48b52b1 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt @@ -15,10 +15,10 @@ */ package com.android.hoststubgen -class HostStubGenErrors { - fun onErrorFound(message: String) { - // For now, we just throw as soon as any error is found, but eventually we should keep +open class HostStubGenErrors { + open fun onErrorFound(message: String) { + // TODO: For now, we just throw as soon as any error is found, but eventually we should keep // all errors and print them at the end. - throw RuntimeException(message) + throw HostStubGenUserErrorException(message) } }
\ No newline at end of file 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 d7aa0af13ce2..0579c2bb0525 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt @@ -17,6 +17,8 @@ package com.android.hoststubgen.asm import com.android.hoststubgen.ClassParseException import com.android.hoststubgen.HostStubGenInternalException +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.FieldVisitor import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes import org.objectweb.asm.Type @@ -108,7 +110,7 @@ fun isAnonymousInnerClass(cn: ClassNode): Boolean { * Otherwise, return null. */ fun getDirectOuterClassName(className: String): String? { - val pos = className.indexOf('$') + val pos = className.lastIndexOf('$') if (pos < 0) { return null } @@ -194,6 +196,29 @@ fun isVisibilityPrivateOrPackagePrivate(access: Int): Boolean { } } +enum class Visibility { + PRIVATE, + PACKAGE_PRIVATE, + PROTECTED, + PUBLIC; + + companion object { + fun fromAccess(access: Int): Visibility { + if ((access and Opcodes.ACC_PUBLIC) != 0) { + return PUBLIC + } + if ((access and Opcodes.ACC_PROTECTED) != 0) { + return PROTECTED + } + if ((access and Opcodes.ACC_PRIVATE) != 0) { + return PRIVATE + } + + return PACKAGE_PRIVATE + } + } +} + fun ClassNode.isEnum(): Boolean { return (this.access and Opcodes.ACC_ENUM) != 0 } @@ -210,6 +235,10 @@ fun MethodNode.isSynthetic(): Boolean { return (this.access and Opcodes.ACC_SYNTHETIC) != 0 } +fun MethodNode.isStatic(): Boolean { + return (this.access and Opcodes.ACC_STATIC) != 0 +} + fun FieldNode.isEnum(): Boolean { return (this.access and Opcodes.ACC_ENUM) != 0 } @@ -218,6 +247,19 @@ fun FieldNode.isSynthetic(): Boolean { return (this.access and Opcodes.ACC_SYNTHETIC) != 0 } +fun ClassNode.getVisibility(): Visibility { + return Visibility.fromAccess(this.access) +} + +fun MethodNode.getVisibility(): Visibility { + return Visibility.fromAccess(this.access) +} + +fun FieldNode.getVisibility(): Visibility { + return Visibility.fromAccess(this.access) +} + + /* Dump of the members of TinyFrameworkEnumSimple: @@ -283,3 +325,36 @@ fun isAutoGeneratedEnumMember(fn: FieldNode): Boolean { } return false } + +/** + * Class to help handle [ClassVisitor], [MethodVisitor] and [FieldVisitor] in a unified way. + */ +abstract class UnifiedVisitor { + abstract fun visitAnnotation(descriptor: String, visible: Boolean) + + companion object { + fun on(target: ClassVisitor): UnifiedVisitor { + return object : UnifiedVisitor() { + override fun visitAnnotation(descriptor: String, visible: Boolean) { + target.visitAnnotation(descriptor, visible) + } + } + } + + fun on(target: MethodVisitor): UnifiedVisitor { + return object : UnifiedVisitor() { + override fun visitAnnotation(descriptor: String, visible: Boolean) { + target.visitAnnotation(descriptor, visible) + } + } + } + + fun on(target: FieldVisitor): UnifiedVisitor { + return object : UnifiedVisitor() { + override fun visitAnnotation(descriptor: String, visible: Boolean) { + target.visitAnnotation(descriptor, visible) + } + } + } + } +} 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 6aac3d88b8b1..47790b10782a 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt @@ -15,6 +15,7 @@ */ package com.android.hoststubgen.filters +import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.getDirectOuterClassName /** @@ -22,22 +23,38 @@ import com.android.hoststubgen.asm.getDirectOuterClassName * (obtained from [outermostFilter]) to the fields and methods. */ class ClassWidePolicyPropagatingFilter( - fallback: OutputFilter, + private val classes: ClassNodes, + fallback: OutputFilter, ) : DelegatingFilter(fallback) { private fun getClassWidePolicy(className: String, resolve: Boolean): FilterPolicyWithReason? { 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) { - outermostFilter.getPolicyForClass(className).let { policy -> - if (policy.policy.isClassWidePolicy) { - val p = if (resolve) policy.policy.resolveClassWidePolicy() else policy.policy + // 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") + 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") + } } } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt index 96e4a3f9c726..21cfd4bcd0d8 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt @@ -18,14 +18,15 @@ package com.android.hoststubgen.visitors import com.android.hoststubgen.HostStubGenErrors import com.android.hoststubgen.LogLevel import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.UnifiedVisitor import com.android.hoststubgen.asm.getPackageNameFromClassName import com.android.hoststubgen.asm.resolveClassName import com.android.hoststubgen.asm.toJvmClassName import com.android.hoststubgen.filters.FilterPolicy import com.android.hoststubgen.filters.FilterPolicyWithReason import com.android.hoststubgen.filters.OutputFilter -import com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass -import com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass +import com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +import com.android.hoststubgen.hosthelper.HostStubGenKeptInStub import com.android.hoststubgen.log import org.objectweb.asm.ClassVisitor import org.objectweb.asm.FieldVisitor @@ -64,6 +65,18 @@ abstract class BaseAdapter ( */ protected abstract fun shouldEmit(policy: FilterPolicy): Boolean + /** + * Inject [HostStubGenKeptInStub] and [HostStubGenKeptInImpl] as needed to an item. + */ + protected fun injectInStubAndKeepAnnotations(policy: FilterPolicy, v: UnifiedVisitor) { + if (policy.needsInStub) { + v.visitAnnotation(HostStubGenKeptInStub.CLASS_DESCRIPTOR, true) + } + if (policy.needsInImpl) { + v.visitAnnotation(HostStubGenKeptInImpl.CLASS_DESCRIPTOR, true) + } + } + override fun visit( version: Int, access: Int, @@ -100,12 +113,7 @@ abstract class BaseAdapter ( nativeSubstitutionClass = fullClassName } // Inject annotations to generated classes. - if (classPolicy.policy.needsInStub) { - visitAnnotation(HostStubGenProcessedStubClass.CLASS_DESCRIPTOR, true) - } - if (classPolicy.policy.needsInImpl) { - visitAnnotation(HostStubGenProcessedKeepClass.CLASS_DESCRIPTOR, true) - } + injectInStubAndKeepAnnotations(classPolicy.policy, UnifiedVisitor.on(this)) } override fun visitEnd() { @@ -148,7 +156,11 @@ abstract class BaseAdapter ( } log.v("Emitting field: %s %s %s", name, descriptor, policy) - return super.visitField(access, name, descriptor, signature, value) + val ret = super.visitField(access, name, descriptor, signature, value) + + injectInStubAndKeepAnnotations(policy.policy, UnifiedVisitor.on(ret)) + + return ret } } @@ -166,7 +178,9 @@ abstract class BaseAdapter ( log.d("visitMethod: %s%s [%x] [%s] Policy: %s", name, descriptor, access, signature, p) log.withIndent { - // If it's a substitute-to method, then skip. + // If it's a substitute-from method, then skip (== remove). + // Instead of this method, we rename the substitute-to method with the original + // name, in the "Maybe rename the method" part below. val policy = filter.getPolicyForMethod(currentClassName, name, descriptor) if (policy.policy.isSubstitute) { log.d("Skipping %s%s %s", name, descriptor, policy) @@ -179,9 +193,19 @@ abstract class BaseAdapter ( // Maybe rename the method. val newName: String - val substituteTo = filter.getRenameTo(currentClassName, name, descriptor) - if (substituteTo != null) { - newName = substituteTo + val renameTo = filter.getRenameTo(currentClassName, name, descriptor) + if (renameTo != null) { + newName = renameTo + + // It's confusing, but here, `newName` is the original method name + // (the one with the @substitute/replace annotation). + // `name` is the name of the method we're currently visiting, so it's usually a + // "...$ravewnwood" name. + if (!checkSubstitutionMethodCompatibility( + classes, currentClassName, newName, name, descriptor, options.errors)) { + return null + } + log.v("Emitting %s.%s%s as %s %s", currentClassName, name, descriptor, newName, policy) } else { @@ -191,12 +215,19 @@ abstract class BaseAdapter ( // Let subclass update the flag. // But note, we only use it when calling the super's method, - // but not for visitMethodInner(), beucase when subclass wants to change access, + // but not for visitMethodInner(), because when subclass wants to change access, // it can do so inside visitMethodInner(). val newAccess = updateAccessFlags(access, name, descriptor) - return visitMethodInner(access, newName, descriptor, signature, exceptions, policy, - super.visitMethod(newAccess, newName, descriptor, signature, exceptions)) + val ret = visitMethodInner(access, newName, descriptor, signature, exceptions, policy, + renameTo != null, + super.visitMethod(newAccess, newName, descriptor, signature, exceptions)) + + ret?.let { + injectInStubAndKeepAnnotations(policy.policy, UnifiedVisitor.on(ret)) + } + + return ret } } @@ -215,6 +246,7 @@ abstract class BaseAdapter ( signature: String?, exceptions: Array<String>?, policy: FilterPolicyWithReason, + substituted: Boolean, superVisitor: MethodVisitor?, ): MethodVisitor? diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt new file mode 100644 index 000000000000..9d66c32e76ee --- /dev/null +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt @@ -0,0 +1,63 @@ +/* + * 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.hoststubgen.visitors + +import com.android.hoststubgen.HostStubGenErrors +import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.getVisibility +import com.android.hoststubgen.asm.isStatic + +/** + * Make sure substitution from and to methods have matching definition. + * (static-ness, visibility.) + */ +fun checkSubstitutionMethodCompatibility( + classes: ClassNodes, + className: String, + fromMethodName: String, // the one with the annotation + toMethodName: String, // the one with either a "_host" or "$ravenwood" prefix. (typically) + descriptor: String, + errors: HostStubGenErrors, +): Boolean { + val from = classes.findMethod(className, fromMethodName, descriptor) + if (from == null) { + errors.onErrorFound( + "Substitution-from method not found: $className.$fromMethodName$descriptor") + return false + } + val to = classes.findMethod(className, toMethodName, descriptor) + if (to == null) { + // This shouldn't happen, because the visitor visited this method... + errors.onErrorFound( + "Substitution-to method not found: $className.$toMethodName$descriptor") + return false + } + + if (from.isStatic() != to.isStatic()) { + errors.onErrorFound( + "Substitution method must have matching static-ness: " + + "$className.$fromMethodName$descriptor") + return false + } + if (from.getVisibility().ordinal > to.getVisibility().ordinal) { + errors.onErrorFound( + "Substitution method cannot have smaller visibility than original: " + + "$className.$fromMethodName$descriptor") + return false + } + + return true +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt index 88db15b86143..416b78242899 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt @@ -25,6 +25,9 @@ import com.android.hoststubgen.asm.writeByteCodeToReturn import com.android.hoststubgen.filters.FilterPolicy import com.android.hoststubgen.filters.FilterPolicyWithReason import com.android.hoststubgen.filters.OutputFilter +import com.android.hoststubgen.hosthelper.HostStubGenProcessedAsIgnore +import com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute +import com.android.hoststubgen.hosthelper.HostStubGenProcessedAsThrow import com.android.hoststubgen.hosthelper.HostTestUtils import com.android.hoststubgen.log import org.objectweb.asm.ClassVisitor @@ -135,6 +138,7 @@ class ImplGeneratingAdapter( signature: String?, exceptions: Array<String>?, policy: FilterPolicyWithReason, + substituted: Boolean, superVisitor: MethodVisitor?, ): MethodVisitor? { // Inject method log, if needed. @@ -182,23 +186,37 @@ class ImplGeneratingAdapter( ) } + fun MethodVisitor.withAnnotation(descriptor: String): MethodVisitor { + this.visitAnnotation(descriptor, true) + return this + } + log.withIndent { + var willThrow = false + if (policy.policy == FilterPolicy.Throw) { + log.v("Making method throw...") + willThrow = true + innerVisitor = ThrowingMethodAdapter( + access, name, descriptor, signature, exceptions, innerVisitor) + .withAnnotation(HostStubGenProcessedAsThrow.CLASS_DESCRIPTOR) + } if ((access and Opcodes.ACC_NATIVE) != 0 && nativeSubstitutionClass != null) { log.v("Rewriting native method...") return NativeSubstitutingMethodAdapter( access, name, descriptor, signature, exceptions, innerVisitor) + .withAnnotation(HostStubGenProcessedAsSubstitute.CLASS_DESCRIPTOR) } - if (policy.policy == FilterPolicy.Throw) { - log.v("Making method throw...") - return ThrowingMethodAdapter( - access, name, descriptor, signature, exceptions, innerVisitor) + if (willThrow) { + return innerVisitor } + if (policy.policy == FilterPolicy.Ignore) { when (Type.getReturnType(descriptor)) { Type.VOID_TYPE -> { log.v("Making method ignored...") return IgnoreMethodAdapter( access, name, descriptor, signature, exceptions, innerVisitor) + .withAnnotation(HostStubGenProcessedAsIgnore.CLASS_DESCRIPTOR) } else -> { throw RuntimeException("Ignored policy only allowed for void methods") @@ -206,6 +224,9 @@ class ImplGeneratingAdapter( } } } + if (substituted) { + innerVisitor?.withAnnotation(HostStubGenProcessedAsSubstitute.CLASS_DESCRIPTOR) + } return innerVisitor } @@ -294,13 +315,13 @@ class ImplGeneratingAdapter( next: MethodVisitor? ) : MethodVisitor(OPCODE_VERSION, next) { override fun visitCode() { - super.visitCode() - throw RuntimeException("NativeSubstitutingMethodVisitor should be called on " + " native method, where visitCode() shouldn't be called.") } override fun visitEnd() { + super.visitCode() + var targetDescriptor = descriptor var argOffset = 0 diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt index 37e2a888969d..fc20f2832d28 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt @@ -45,6 +45,7 @@ class StubGeneratingAdapter( signature: String?, exceptions: Array<String>?, policy: FilterPolicyWithReason, + substituted: Boolean, superVisitor: MethodVisitor?, ): MethodVisitor? { return StubMethodVisitor(access, name, descriptor, signature, exceptions, superVisitor) 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 3956893ee7ed..70f56ae37a97 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 @@ -1817,7 +1817,7 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 8, attributes: 2 + interfaces: 0, fields: 1, methods: 10, attributes: 2 int value; descriptor: I flags: (0x0000) @@ -1904,6 +1904,24 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative Start Length Slot Name Signature 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 0 6 1 arg I + + public static native void nativeStillNotSupported(); + descriptor: ()V + flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestThrow + + public static void nativeStillNotSupported_should_be_like_this(); + descriptor: ()V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V + x: athrow + LineNumberTable: } SourceFile: "TinyFrameworkNative.java" RuntimeInvisibleAnnotations: 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 9349355d4d02..b0db48347d46 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 @@ -17,6 +17,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro 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 addTwo(int); descriptor: (I)I @@ -28,6 +33,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro 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; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -35,9 +45,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class Compiled from "IPretendingAidl.java" @@ -58,6 +68,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub 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 addOne(int); descriptor: (I)I @@ -69,6 +84,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub 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; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -76,9 +96,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class Compiled from "IPretendingAidl.java" @@ -96,9 +116,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy @@ -121,6 +141,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl 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 getOneStub(); descriptor: ()I @@ -132,6 +157,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl 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 @@ -141,9 +171,9 @@ InnerClasses: SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class Compiled from "TinyFrameworkCallerCheck.java" @@ -164,6 +194,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck 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 getOne_withCheck(); descriptor: ()I @@ -175,6 +210,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck 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 getOne_noCheck(); descriptor: ()I @@ -186,15 +226,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck 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: private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -212,6 +257,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -226,6 +276,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -240,6 +295,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -254,6 +314,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -265,6 +330,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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; @@ -276,6 +346,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -283,9 +358,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota SourceFile: "TinyFrameworkClassAnnotations.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -305,14 +380,29 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -324,6 +414,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -335,6 +430,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -346,6 +446,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -357,6 +462,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -368,6 +478,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -379,6 +494,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -390,6 +510,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -401,13 +526,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -424,6 +554,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo descriptor: Ljava/util/Set; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook(); descriptor: ()V @@ -435,6 +570,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo 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 void onClassLoaded(java.lang.Class<?>); descriptor: (Ljava/lang/Class;)V @@ -447,6 +587,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // (Ljava/lang/Class<*>;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -458,13 +603,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo 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: "TinyFrameworkClassLoadHook.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -480,6 +630,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -487,6 +642,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -495,9 +655,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn SourceFile: "TinyFrameworkClassWithInitializerDefault.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -513,6 +673,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -520,6 +685,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -528,9 +698,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn SourceFile: "TinyFrameworkClassWithInitializerStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x(#x=s#x) android.hosttest.annotation.HostSideTestClassLoadHook( @@ -552,6 +722,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -559,6 +734,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -566,6 +746,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -573,6 +758,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -584,6 +774,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -595,6 +790,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String); descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V @@ -607,6 +807,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -621,6 +826,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 @@ -635,6 +845,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 @@ -649,6 +864,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 static {}; descriptor: ()V @@ -660,14 +880,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>; SourceFile: "TinyFrameworkEnumComplex.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -683,6 +908,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -690,6 +920,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -697,6 +932,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -708,6 +948,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -719,6 +964,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple(); descriptor: (Ljava/lang/String;I)V @@ -731,6 +981,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -742,6 +997,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 static {}; descriptor: ()V @@ -753,14 +1013,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>; SourceFile: "TinyFrameworkEnumSimple.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -783,6 +1048,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe 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 testException(); descriptor: ()I @@ -794,13 +1064,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe 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: "TinyFrameworkExceptionTester.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -816,6 +1091,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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.TinyFrameworkForTextPolicy(); descriptor: ()V @@ -827,6 +1107,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 @@ -838,6 +1123,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 @@ -849,6 +1139,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 @@ -860,6 +1155,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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; @@ -871,13 +1171,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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: "TinyFrameworkForTextPolicy.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class Compiled from "TinyFrameworkLambdas.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested @@ -891,6 +1196,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -899,6 +1209,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -913,6 +1228,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 @@ -928,6 +1248,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -943,6 +1268,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -957,6 +1287,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -968,6 +1303,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -979,6 +1319,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -990,6 +1335,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -997,9 +1347,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1019,6 +1369,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1027,6 +1382,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1041,6 +1401,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 @@ -1056,6 +1421,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1071,6 +1441,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1085,6 +1460,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -1096,6 +1476,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -1107,6 +1492,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -1118,6 +1508,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -1125,9 +1520,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1143,10 +1538,15 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 8, attributes: 3 + interfaces: 0, fields: 1, methods: 9, attributes: 3 int value; descriptor: I flags: (0x0000) + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative(); descriptor: ()V @@ -1158,10 +1558,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 native int nativeAddTwo(int); descriptor: (I)I flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeAddTwo_should_be_like_this(int); descriptor: (I)I @@ -1173,10 +1583,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 native long nativeLongPlus(long, long); descriptor: (JJ)J flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus_should_be_like_this(long, long); descriptor: (JJ)J @@ -1188,6 +1608,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 setValue(int); descriptor: (I)V @@ -1199,10 +1624,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 native int nativeNonStaticAddToValue(int); descriptor: (I)I flags: (0x0101) ACC_PUBLIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int nativeNonStaticAddToValue_should_be_like_this(int); descriptor: (I)I @@ -1214,13 +1649,34 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 void nativeStillNotSupported_should_be_like_this(); + descriptor: ()V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + 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: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1240,6 +1696,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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$BaseClass(int); descriptor: (I)V @@ -1251,15 +1712,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class Compiled from "TinyFrameworkNestedClasses.java" @@ -1273,10 +1739,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass public int value; descriptor: I flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V @@ -1288,15 +1764,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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 #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1313,6 +1794,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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(); descriptor: ()V @@ -1324,6 +1810,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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 java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -1336,6 +1827,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + 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 @@ -1343,9 +1839,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1369,6 +1865,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses @@ -1376,9 +1877,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class Compiled from "TinyFrameworkNestedClasses.java" @@ -1393,11 +1894,21 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static final java.util.function.Supplier<java.lang.Integer> sSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses(); descriptor: ()V @@ -1409,6 +1920,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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.util.function.Supplier<java.lang.Integer> getSupplier(); descriptor: ()Ljava/util/function/Supplier; @@ -1421,6 +1937,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -1433,6 +1954,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1444,6 +1970,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 @@ -1458,9 +1989,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1493,6 +2024,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi 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 foo(int); descriptor: (I)I @@ -1504,13 +2040,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi 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: "TinyFrameworkPackageRedirect.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1533,6 +2074,11 @@ public class com.unsupported.UnsupportedClass 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 getValue(); descriptor: ()I @@ -1544,13 +2090,18 @@ public class com.unsupported.UnsupportedClass 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: "UnsupportedClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub 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 4f8c408eb7d9..112f69e43c69 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 @@ -10,11 +10,14 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "HostSideTestClassLoadHook.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -36,7 +39,7 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang. SourceFile: "HostSideTestKeep.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -57,11 +60,14 @@ public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "HostSideTestNativeSubstitutionClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -83,7 +89,7 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan SourceFile: "HostSideTestRemove.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -105,7 +111,7 @@ public interface android.hosttest.annotation.HostSideTestStub extends java.lang. SourceFile: "HostSideTestStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -126,11 +132,14 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java public abstract java.lang.String suffix(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "HostSideTestSubstitute.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.METHOD] @@ -152,7 +161,7 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang SourceFile: "HostSideTestThrow.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -174,7 +183,7 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends SourceFile: "HostSideTestWholeClassKeep.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -196,7 +205,7 @@ public interface android.hosttest.annotation.HostSideTestWholeClassStub extends SourceFile: "HostSideTestWholeClassStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -226,6 +235,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int addTwo(int); descriptor: (I)I @@ -240,6 +254,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro LocalVariableTable: Start Length Slot Name Signature 0 4 0 a I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -247,9 +266,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class Compiled from "IPretendingAidl.java" @@ -272,6 +291,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int addOne(int); descriptor: (I)I @@ -286,6 +310,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub LocalVariableTable: Start Length Slot Name Signature 0 4 0 a I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -293,9 +322,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class Compiled from "IPretendingAidl.java" @@ -313,9 +342,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy @@ -340,6 +369,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int getOneKeep(); descriptor: ()I @@ -355,6 +389,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl x: iconst_1 x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -367,6 +404,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl x: iconst_1 x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -376,9 +418,9 @@ InnerClasses: SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class Compiled from "TinyFrameworkCallerCheck.java" @@ -401,6 +443,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int getOne_withCheck(); descriptor: ()I @@ -410,6 +457,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int getOne_noCheck(); descriptor: ()I @@ -419,15 +471,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -445,6 +502,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -452,6 +514,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -484,6 +549,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -502,6 +572,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -526,6 +601,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -544,6 +622,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -558,6 +643,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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; @@ -576,6 +668,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -592,6 +689,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -599,9 +701,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota SourceFile: "TinyFrameworkClassAnnotations.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -621,14 +723,29 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -648,6 +765,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -663,6 +785,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -678,6 +805,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -693,6 +825,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -708,6 +845,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -722,6 +866,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -734,6 +885,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -747,13 +903,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -770,6 +931,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo descriptor: Ljava/util/Set; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook(); descriptor: ()V @@ -783,6 +949,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static void onClassLoaded(java.lang.Class<?>); descriptor: (Ljava/lang/Class;)V @@ -802,6 +973,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo Start Length Slot Name Signature 0 11 0 clazz Ljava/lang/Class<*>; Signature: #x // (Ljava/lang/Class<*>;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -814,13 +990,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo x: putstatic #x // Field sLoadedClasses:Ljava/util/Set; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkClassLoadHook.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -836,6 +1017,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -843,6 +1029,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -851,9 +1042,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn SourceFile: "TinyFrameworkClassWithInitializerDefault.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -869,6 +1060,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -876,6 +1072,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -896,13 +1097,16 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn x: putstatic #x // Field sObject:Ljava/lang/Object; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkClassWithInitializerStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x(#x=s#x) android.hosttest.annotation.HostSideTestClassLoadHook( @@ -924,6 +1128,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -931,6 +1140,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -938,6 +1152,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -945,6 +1164,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private final java.lang.String mLongName; descriptor: Ljava/lang/String; flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -952,6 +1174,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private final java.lang.String mShortName; descriptor: Ljava/lang/String; flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -959,6 +1184,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -970,6 +1200,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;" x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -985,6 +1220,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC LocalVariableTable: Start Length Slot Name Signature 0 10 0 name Ljava/lang/String; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String); descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V @@ -1009,6 +1249,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 0 18 3 longName Ljava/lang/String; 0 18 4 shortName Ljava/lang/String; Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1025,6 +1270,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1041,6 +1291,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1066,6 +1321,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: aastore x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1100,14 +1360,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>; SourceFile: "TinyFrameworkEnumComplex.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1123,6 +1388,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1130,6 +1400,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1137,6 +1412,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -1148,6 +1428,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;" x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -1163,6 +1448,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS LocalVariableTable: Start Length Slot Name Signature 0 10 0 name Ljava/lang/String; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple(); descriptor: (Ljava/lang/String;I)V @@ -1179,6 +1469,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS Start Length Slot Name Signature 0 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; Signature: #x // ()V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -1197,6 +1492,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: aastore x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1219,14 +1519,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>; SourceFile: "TinyFrameworkEnumSimple.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1251,6 +1556,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int testException(); descriptor: ()I @@ -1279,13 +1589,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe LocalVariableTable: Start Length Slot Name Signature 11 11 0 e Ljava/lang/Exception; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkExceptionTester.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1301,10 +1616,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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.HostStubGenKeptInImpl private static {}; descriptor: ()V @@ -1334,6 +1657,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli LocalVariableTable: Start Length Slot Name Signature 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int addOne(int); descriptor: (I)I @@ -1349,6 +1677,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli Start Length Slot Name Signature 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; 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 @@ -1370,6 +1703,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli Start Length Slot Name Signature 15 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; 15 4 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int addTwo(int); descriptor: (I)I @@ -1385,6 +1721,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli Start Length Slot Name Signature 0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; 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 @@ -1399,6 +1742,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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; @@ -1417,6 +1767,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 public java.lang.String visibleButUsesUnsupportedMethod(); descriptor: ()Ljava/lang/String; @@ -1430,13 +1785,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkForTextPolicy.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class Compiled from "TinyFrameworkLambdas.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested @@ -1450,6 +1810,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1458,6 +1823,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1477,6 +1847,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1493,6 +1868,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes Start Length Slot Name Signature 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested; Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1506,6 +1886,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1519,6 +1904,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -1529,6 +1919,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -1539,6 +1934,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -1549,6 +1949,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1559,6 +1964,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -1566,9 +1974,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1609,6 +2017,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1617,6 +2030,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1636,6 +2054,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas LocalVariableTable: Start Length Slot Name Signature 0 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1652,6 +2075,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas Start Length Slot Name Signature 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas; Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1665,6 +2093,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1678,6 +2111,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -1688,6 +2126,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -1698,6 +2141,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -1708,6 +2156,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1718,6 +2171,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -1725,9 +2181,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1764,10 +2220,15 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 8, attributes: 3 + interfaces: 0, fields: 1, methods: 10, attributes: 3 int value; descriptor: I flags: (0x0000) + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative(); descriptor: ()V @@ -1781,6 +2242,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeAddTwo(int); descriptor: (I)I @@ -1790,6 +2256,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative x: iload_0 x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I x: ireturn + 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 nativeAddTwo_should_be_like_this(int); descriptor: (I)I @@ -1803,6 +2276,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative LocalVariableTable: Start Length Slot Name Signature 0 5 0 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus(long, long); descriptor: (JJ)J @@ -1813,6 +2291,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative x: lload_2 x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J x: lreturn + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus_should_be_like_this(long, long); descriptor: (JJ)J @@ -1828,6 +2313,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative Start Length Slot Name Signature 0 6 0 arg1 J 0 6 2 arg2 J + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public void setValue(int); descriptor: (I)V @@ -1843,6 +2333,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative Start Length Slot Name Signature 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 0 6 1 v I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int nativeNonStaticAddToValue(int); descriptor: (I)I @@ -1853,6 +2348,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative x: iload_1 x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I x: ireturn + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int nativeNonStaticAddToValue_should_be_like_this(int); descriptor: (I)I @@ -1868,13 +2370,62 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative Start Length Slot Name Signature 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 0 6 1 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static void nativeStillNotSupported(); + descriptor: ()V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeStillNotSupported + x: ldc #x // String ()V + 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.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestThrow + + public static void nativeStillNotSupported_should_be_like_this(); + descriptor: ()V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V + x: athrow + LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1909,6 +2460,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeAddTwo(int); descriptor: (I)I @@ -1929,6 +2483,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host LocalVariableTable: Start Length Slot Name Signature 15 4 0 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus(long, long); descriptor: (JJ)J @@ -1950,6 +2507,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host Start Length Slot Name Signature 15 4 0 arg1 J 15 4 2 arg2 J + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I @@ -1972,11 +2532,14 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host Start Length Slot Name Signature 15 7 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 15 7 1 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative_host.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassKeep @@ -1992,6 +2555,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V @@ -2009,6 +2575,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex Start Length Slot Name Signature 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; 0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2028,6 +2597,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2047,6 +2619,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 @@ -2055,7 +2630,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2078,6 +2653,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2097,6 +2675,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2116,6 +2697,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 @@ -2124,7 +2708,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2138,6 +2722,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V @@ -2155,6 +2742,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex Start Length Slot Name Signature 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; 0 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2174,6 +2764,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2193,6 +2786,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 @@ -2201,7 +2797,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2224,6 +2820,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2243,6 +2842,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2262,6 +2864,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 @@ -2270,7 +2875,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2284,6 +2889,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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$BaseClass(int); descriptor: (I)V @@ -2301,15 +2911,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass; 0 10 1 x I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2323,10 +2938,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass public int value; descriptor: I flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V @@ -2347,15 +2972,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass; 0 15 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -2381,6 +3011,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2400,6 +3033,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat LocalVariableTable: Start Length Slot Name Signature 15 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2419,6 +3055,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + RuntimeVisibleAnnotations: + 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 @@ -2428,7 +3067,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + 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" @@ -2442,6 +3081,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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(); descriptor: ()V @@ -2458,6 +3102,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass LocalVariableTable: Start Length Slot Name Signature 0 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -2470,6 +3119,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + 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 @@ -2477,9 +3131,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -2507,6 +3161,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass; 0 6 1 x I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses @@ -2514,9 +3173,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2531,11 +3190,21 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static final java.util.function.Supplier<java.lang.Integer> sSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses(); descriptor: ()V @@ -2555,6 +3224,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass LocalVariableTable: Start Length Slot Name Signature 0 17 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.util.function.Supplier<java.lang.Integer> getSupplier(); descriptor: ()Ljava/util/function/Supplier; @@ -2571,6 +3245,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 0 9 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -2583,6 +3262,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -2595,6 +3279,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 @@ -2609,9 +3298,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -2646,6 +3335,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int foo(int); descriptor: (I)I @@ -2662,13 +3356,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi LocalVariableTable: Start Length Slot Name Signature 0 12 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkPackageRedirect.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -2684,6 +3383,9 @@ public class com.supported.UnsupportedClass private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.supported.UnsupportedClass(int); descriptor: (I)V @@ -2707,6 +3409,9 @@ public class com.supported.UnsupportedClass Start Length Slot Name Signature 15 10 0 this Lcom/supported/UnsupportedClass; 15 10 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int getValue(); descriptor: ()I @@ -2726,11 +3431,14 @@ public class com.supported.UnsupportedClass LocalVariableTable: Start Length Slot Name Signature 15 5 0 this Lcom/supported/UnsupportedClass; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "UnsupportedClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassKeep @@ -2760,6 +3468,11 @@ public class com.unsupported.UnsupportedClass Start Length Slot Name Signature 0 14 0 this Lcom/unsupported/UnsupportedClass; 0 14 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int getValue(); descriptor: ()I @@ -2775,13 +3488,18 @@ public class com.unsupported.UnsupportedClass LocalVariableTable: Start Length Slot Name Signature 0 10 0 this Lcom/unsupported/UnsupportedClass; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "UnsupportedClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub 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 9349355d4d02..b0db48347d46 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 @@ -17,6 +17,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro 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 addTwo(int); descriptor: (I)I @@ -28,6 +33,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro 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; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -35,9 +45,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class Compiled from "IPretendingAidl.java" @@ -58,6 +68,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub 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 addOne(int); descriptor: (I)I @@ -69,6 +84,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub 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; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -76,9 +96,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class Compiled from "IPretendingAidl.java" @@ -96,9 +116,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy @@ -121,6 +141,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl 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 getOneStub(); descriptor: ()I @@ -132,6 +157,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl 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 @@ -141,9 +171,9 @@ InnerClasses: SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class Compiled from "TinyFrameworkCallerCheck.java" @@ -164,6 +194,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck 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 getOne_withCheck(); descriptor: ()I @@ -175,6 +210,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck 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 getOne_noCheck(); descriptor: ()I @@ -186,15 +226,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck 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: private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -212,6 +257,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -226,6 +276,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -240,6 +295,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -254,6 +314,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -265,6 +330,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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; @@ -276,6 +346,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -283,9 +358,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota SourceFile: "TinyFrameworkClassAnnotations.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -305,14 +380,29 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -324,6 +414,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -335,6 +430,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -346,6 +446,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -357,6 +462,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -368,6 +478,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -379,6 +494,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -390,6 +510,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -401,13 +526,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -424,6 +554,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo descriptor: Ljava/util/Set; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook(); descriptor: ()V @@ -435,6 +570,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo 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 void onClassLoaded(java.lang.Class<?>); descriptor: (Ljava/lang/Class;)V @@ -447,6 +587,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // (Ljava/lang/Class<*>;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -458,13 +603,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo 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: "TinyFrameworkClassLoadHook.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -480,6 +630,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -487,6 +642,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -495,9 +655,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn SourceFile: "TinyFrameworkClassWithInitializerDefault.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -513,6 +673,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -520,6 +685,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -528,9 +698,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn SourceFile: "TinyFrameworkClassWithInitializerStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x(#x=s#x) android.hosttest.annotation.HostSideTestClassLoadHook( @@ -552,6 +722,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -559,6 +734,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -566,6 +746,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -573,6 +758,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -584,6 +774,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -595,6 +790,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String); descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V @@ -607,6 +807,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -621,6 +826,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 @@ -635,6 +845,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 @@ -649,6 +864,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 static {}; descriptor: ()V @@ -660,14 +880,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 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 } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>; SourceFile: "TinyFrameworkEnumComplex.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -683,6 +908,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -690,6 +920,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -697,6 +932,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -708,6 +948,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -719,6 +964,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple(); descriptor: (Ljava/lang/String;I)V @@ -731,6 +981,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -742,6 +997,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 static {}; descriptor: ()V @@ -753,14 +1013,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS 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 } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>; SourceFile: "TinyFrameworkEnumSimple.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -783,6 +1048,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe 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 testException(); descriptor: ()I @@ -794,13 +1064,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe 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: "TinyFrameworkExceptionTester.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -816,6 +1091,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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.TinyFrameworkForTextPolicy(); descriptor: ()V @@ -827,6 +1107,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 @@ -838,6 +1123,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 @@ -849,6 +1139,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 @@ -860,6 +1155,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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; @@ -871,13 +1171,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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: "TinyFrameworkForTextPolicy.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class Compiled from "TinyFrameworkLambdas.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested @@ -891,6 +1196,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -899,6 +1209,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -913,6 +1228,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 @@ -928,6 +1248,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -943,6 +1268,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -957,6 +1287,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -968,6 +1303,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -979,6 +1319,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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 private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -990,6 +1335,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes 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; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -997,9 +1347,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1019,6 +1369,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1027,6 +1382,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1041,6 +1401,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 @@ -1056,6 +1421,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1071,6 +1441,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1085,6 +1460,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -1096,6 +1476,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -1107,6 +1492,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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 private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -1118,6 +1508,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas 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; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -1125,9 +1520,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1143,10 +1538,15 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 8, attributes: 3 + interfaces: 0, fields: 1, methods: 9, attributes: 3 int value; descriptor: I flags: (0x0000) + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative(); descriptor: ()V @@ -1158,10 +1558,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 native int nativeAddTwo(int); descriptor: (I)I flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeAddTwo_should_be_like_this(int); descriptor: (I)I @@ -1173,10 +1583,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 native long nativeLongPlus(long, long); descriptor: (JJ)J flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus_should_be_like_this(long, long); descriptor: (JJ)J @@ -1188,6 +1608,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 setValue(int); descriptor: (I)V @@ -1199,10 +1624,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 native int nativeNonStaticAddToValue(int); descriptor: (I)I flags: (0x0101) ACC_PUBLIC, ACC_NATIVE + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int nativeNonStaticAddToValue_should_be_like_this(int); descriptor: (I)I @@ -1214,13 +1649,34 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative 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 void nativeStillNotSupported_should_be_like_this(); + descriptor: ()V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + 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: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1240,6 +1696,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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$BaseClass(int); descriptor: (I)V @@ -1251,15 +1712,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class Compiled from "TinyFrameworkNestedClasses.java" @@ -1273,10 +1739,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass public int value; descriptor: I flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V @@ -1288,15 +1764,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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 #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1313,6 +1794,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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(); descriptor: ()V @@ -1324,6 +1810,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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 java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -1336,6 +1827,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + 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 @@ -1343,9 +1839,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1369,6 +1865,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses @@ -1376,9 +1877,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class Compiled from "TinyFrameworkNestedClasses.java" @@ -1393,11 +1894,21 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static final java.util.function.Supplier<java.lang.Integer> sSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses(); descriptor: ()V @@ -1409,6 +1920,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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.util.function.Supplier<java.lang.Integer> getSupplier(); descriptor: ()Ljava/util/function/Supplier; @@ -1421,6 +1937,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -1433,6 +1954,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V x: athrow Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1444,6 +1970,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 @@ -1458,9 +1989,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1493,6 +2024,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi 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 foo(int); descriptor: (I)I @@ -1504,13 +2040,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi 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: "TinyFrameworkPackageRedirect.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1533,6 +2074,11 @@ public class com.unsupported.UnsupportedClass 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 getValue(); descriptor: ()I @@ -1544,13 +2090,18 @@ public class com.unsupported.UnsupportedClass 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: "UnsupportedClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub 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 5ff3cded38b3..2357844c1e10 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 @@ -20,11 +20,14 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "HostSideTestClassLoadHook.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -55,7 +58,7 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang. SourceFile: "HostSideTestKeep.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -86,11 +89,14 @@ public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "HostSideTestNativeSubstitutionClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -121,7 +127,7 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan SourceFile: "HostSideTestRemove.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -152,7 +158,7 @@ public interface android.hosttest.annotation.HostSideTestStub extends java.lang. SourceFile: "HostSideTestStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -183,11 +189,14 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java public abstract java.lang.String suffix(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "HostSideTestSubstitute.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.METHOD] @@ -218,7 +227,7 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang SourceFile: "HostSideTestThrow.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x,e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR] @@ -249,7 +258,7 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends SourceFile: "HostSideTestWholeClassKeep.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -280,7 +289,7 @@ public interface android.hosttest.annotation.HostSideTestWholeClassStub extends SourceFile: "HostSideTestWholeClassStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl x: #x(#x=[e#x.#x]) java.lang.annotation.Target( value=[Ljava/lang/annotation/ElementType;.TYPE] @@ -325,6 +334,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int addTwo(int); descriptor: (I)I @@ -344,6 +358,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro LocalVariableTable: Start Length Slot Name Signature 11 4 0 a I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -351,9 +370,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class Compiled from "IPretendingAidl.java" @@ -391,6 +410,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int addOne(int); descriptor: (I)I @@ -410,6 +434,11 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub LocalVariableTable: Start Length Slot Name Signature 11 4 0 a I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl @@ -417,9 +446,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl ## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class Compiled from "IPretendingAidl.java" @@ -446,9 +475,9 @@ InnerClasses: SourceFile: "IPretendingAidl.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy @@ -488,6 +517,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int getOneKeep(); descriptor: ()I @@ -508,6 +542,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl x: iconst_1 x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -525,6 +562,11 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl x: iconst_1 x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -534,9 +576,9 @@ InnerClasses: SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class Compiled from "TinyFrameworkCallerCheck.java" @@ -574,6 +616,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int getOne_withCheck(); descriptor: ()I @@ -588,6 +635,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int getOne_noCheck(); descriptor: ()I @@ -602,15 +654,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I x: ireturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck SourceFile: "TinyFrameworkCallerCheck.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -628,6 +685,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -635,6 +697,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -675,6 +740,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -698,6 +768,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -727,6 +802,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -750,6 +828,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -769,6 +854,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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; @@ -792,6 +884,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -813,6 +910,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota 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 @@ -820,9 +922,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnota SourceFile: "TinyFrameworkClassAnnotations.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -842,14 +944,29 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -884,6 +1001,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -904,6 +1026,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -924,6 +1051,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -944,6 +1076,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -964,6 +1101,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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 @@ -983,6 +1127,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -1000,6 +1151,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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; @@ -1018,13 +1174,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassW 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.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1041,6 +1202,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo descriptor: Ljava/util/Set; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/Set<Ljava/lang/Class<*>;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook(); descriptor: ()V @@ -1059,6 +1225,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static void onClassLoaded(java.lang.Class<?>); descriptor: (Ljava/lang/Class;)V @@ -1083,6 +1254,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo Start Length Slot Name Signature 11 11 0 clazz Ljava/lang/Class<*>; Signature: #x // (Ljava/lang/Class<*>;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1103,13 +1279,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo x: putstatic #x // Field sLoadedClasses:Ljava/util/Set; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkClassLoadHook.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1125,6 +1306,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1132,6 +1318,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1140,9 +1331,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn SourceFile: "TinyFrameworkClassWithInitializerDefault.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1158,6 +1349,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1165,6 +1361,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn public static java.lang.Object sObject; descriptor: Ljava/lang/Object; flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1193,13 +1394,16 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn x: putstatic #x // Field sObject:Ljava/lang/Object; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkClassWithInitializerStub.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x(#x=s#x) android.hosttest.annotation.HostSideTestClassLoadHook( @@ -1221,6 +1425,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1228,6 +1437,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex GREEN; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1235,6 +1449,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex BLUE; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1242,6 +1461,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private final java.lang.String mLongName; descriptor: Ljava/lang/String; flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -1249,6 +1471,9 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private final java.lang.String mShortName; descriptor: Ljava/lang/String; flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestKeep @@ -1256,6 +1481,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -1272,6 +1502,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;" x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; @@ -1292,6 +1527,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC LocalVariableTable: Start Length Slot Name Signature 11 10 0 name Ljava/lang/String; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex(java.lang.String, java.lang.String); descriptor: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V @@ -1321,6 +1561,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC 11 18 3 longName Ljava/lang/String; 11 18 4 shortName Ljava/lang/String; Signature: #x // (Ljava/lang/String;Ljava/lang/String;)V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1342,6 +1587,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1363,6 +1613,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1393,6 +1648,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: aastore x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1435,14 +1695,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex;>; SourceFile: "TinyFrameworkEnumComplex.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1458,6 +1723,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1465,6 +1735,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple DOG; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1472,6 +1747,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS private static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $VALUES; descriptor: [Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x101a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -1488,6 +1768,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: checkcast #x // class "[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;" x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple valueOf(java.lang.String); descriptor: (Ljava/lang/String;)Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -1508,6 +1793,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS LocalVariableTable: Start Length Slot Name Signature 11 10 0 name Ljava/lang/String; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple(); descriptor: (Ljava/lang/String;I)V @@ -1529,6 +1819,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS Start Length Slot Name Signature 11 7 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; Signature: #x // ()V + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple[] $values(); descriptor: ()[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; @@ -1552,6 +1847,11 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: aastore x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -1582,14 +1882,19 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS x: putstatic #x // Field $VALUES:[Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } Signature: #x // Ljava/lang/Enum<Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple;>; SourceFile: "TinyFrameworkEnumSimple.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1629,6 +1934,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int testException(); descriptor: ()I @@ -1662,13 +1972,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe LocalVariableTable: Start Length Slot Name Signature 22 11 0 e Ljava/lang/Exception; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkExceptionTester.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -1684,10 +1999,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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.HostStubGenKeptInImpl private static {}; descriptor: ()V @@ -1725,6 +2048,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli LocalVariableTable: Start Length Slot Name Signature 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int addOne(int); descriptor: (I)I @@ -1745,6 +2073,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli Start Length Slot Name Signature 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; 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 @@ -1771,6 +2104,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli Start Length Slot Name Signature 26 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; 26 4 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int addTwo(int); descriptor: (I)I @@ -1791,6 +2127,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli Start Length Slot Name Signature 11 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; 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 @@ -1810,6 +2153,13 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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; @@ -1833,6 +2183,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli 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 public java.lang.String visibleButUsesUnsupportedMethod(); descriptor: ()Ljava/lang/String; @@ -1851,13 +2206,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkForTextPolicy.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested.class Compiled from "TinyFrameworkLambdas.java" public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nested @@ -1871,6 +2231,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1879,6 +2244,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1903,6 +2273,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes LocalVariableTable: Start Length Slot Name Signature 11 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1924,6 +2299,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes Start Length Slot Name Signature 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested; Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1942,6 +2322,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -1960,6 +2345,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -1975,6 +2365,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -1990,6 +2385,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -2005,6 +2405,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -2023,6 +2428,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -2030,9 +2438,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -2073,6 +2481,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -2081,6 +2494,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -2105,6 +2523,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas LocalVariableTable: Start Length Slot Name Signature 11 14 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -2126,6 +2549,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas Start Length Slot Name Signature 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas; Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -2144,6 +2572,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -2162,6 +2595,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$getSupplier$2(); descriptor: ()Ljava/lang/Integer; @@ -2177,6 +2615,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$static$1(); descriptor: ()Ljava/lang/Integer; @@ -2192,6 +2635,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static java.lang.Integer lambda$new$0(); descriptor: ()Ljava/lang/Integer; @@ -2207,6 +2655,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; x: areturn LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -2225,6 +2678,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested of class com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas @@ -2232,9 +2688,9 @@ InnerClasses: SourceFile: "TinyFrameworkLambdas.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestStub @@ -2271,10 +2727,15 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object - interfaces: 0, fields: 1, methods: 9, attributes: 3 + interfaces: 0, fields: 1, methods: 11, attributes: 3 int value; descriptor: I flags: (0x0000) + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static {}; descriptor: ()V @@ -2303,15 +2764,32 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeAddTwo(int); descriptor: (I)I flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: - stack=1, locals=1, args_size=1 - x: iload_0 - x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I - x: ireturn + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeAddTwo + 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: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I + x: ireturn + 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 nativeAddTwo_should_be_like_this(int); descriptor: (I)I @@ -2330,16 +2808,33 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative LocalVariableTable: Start Length Slot Name Signature 11 5 0 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus(long, long); descriptor: (JJ)J flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=4, args_size=2 - x: lload_0 - x: lload_2 - x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J - x: lreturn + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeLongPlus + x: ldc #x // String (JJ)J + 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: lload_0 + x: lload_2 + x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J + x: lreturn + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus_should_be_like_this(long, long); descriptor: (JJ)J @@ -2360,6 +2855,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative Start Length Slot Name Signature 11 6 0 arg1 J 11 6 2 arg2 J + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public void setValue(int); descriptor: (I)V @@ -2380,16 +2880,33 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative Start Length Slot Name Signature 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 11 6 1 v I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int nativeNonStaticAddToValue(int); descriptor: (I)I flags: (0x0001) ACC_PUBLIC Code: - stack=2, locals=2, args_size=2 - x: aload_0 - x: iload_1 - x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I - x: ireturn + stack=4, locals=2, args_size=2 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeNonStaticAddToValue + 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: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeNonStaticAddToValue:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I + x: ireturn + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int nativeNonStaticAddToValue_should_be_like_this(int); descriptor: (I)I @@ -2410,13 +2927,72 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative Start Length Slot Name Signature 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 11 6 1 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public static void nativeStillNotSupported(); + descriptor: ()V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeStillNotSupported + 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: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeStillNotSupported + x: ldc #x // String ()V + 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.HostStubGenProcessedAsSubstitute + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + RuntimeInvisibleAnnotations: + x: #x() + android.hosttest.annotation.HostSideTestThrow + + public static void nativeStillNotSupported_should_be_like_this(); + descriptor: ()V + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative + x: ldc #x // String nativeStillNotSupported_should_be_like_this + 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: new #x // class java/lang/RuntimeException + x: dup + x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V + x: athrow + LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -2466,6 +3042,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeAddTwo(int); descriptor: (I)I @@ -2491,6 +3070,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host LocalVariableTable: Start Length Slot Name Signature 26 4 0 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static long nativeLongPlus(long, long); descriptor: (JJ)J @@ -2517,6 +3099,9 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host Start Length Slot Name Signature 26 4 0 arg1 J 26 4 2 arg2 J + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int nativeNonStaticAddToValue(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative, int); descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;I)I @@ -2544,11 +3129,14 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host Start Length Slot Name Signature 26 7 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative; 26 7 1 arg I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkNative_host.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassKeep @@ -2564,6 +3152,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static {}; descriptor: ()V @@ -2596,6 +3187,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex Start Length Slot Name Signature 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; 11 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2620,6 +3214,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2644,6 +3241,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 @@ -2652,7 +3252,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2690,6 +3290,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2714,6 +3317,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2738,6 +3344,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 @@ -2746,7 +3355,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2760,6 +3369,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static {}; descriptor: ()V @@ -2792,6 +3404,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex Start Length Slot Name Signature 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; 11 10 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2816,6 +3431,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2840,6 +3458,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 @@ -2848,7 +3469,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2886,6 +3507,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -2910,6 +3534,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -2934,6 +3561,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 @@ -2942,7 +3572,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class Compiled from "TinyFrameworkNestedClasses.java" @@ -2956,6 +3586,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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 @@ -2988,15 +3623,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 11 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass; 11 10 1 x I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class Compiled from "TinyFrameworkNestedClasses.java" @@ -3010,10 +3650,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass public int value; descriptor: I flags: (0x0001) ACC_PUBLIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static {}; descriptor: ()V @@ -3049,15 +3699,20 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 11 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass; 11 15 1 this$0 Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -3098,6 +3753,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; @@ -3122,6 +3780,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat LocalVariableTable: Start Length Slot Name Signature 26 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.lang.Object get(); descriptor: ()Ljava/lang/Object; @@ -3146,6 +3807,9 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1; + RuntimeVisibleAnnotations: + 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 @@ -3155,7 +3819,7 @@ Signature: #x // Ljava/lang/Object;Ljava/util/function SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + 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" @@ -3169,6 +3833,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass 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 @@ -3200,6 +3869,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass LocalVariableTable: Start Length Slot Name Signature 11 11 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -3217,6 +3891,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + 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 @@ -3224,9 +3903,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -3269,6 +3948,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 11 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass; 11 6 1 x I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses @@ -3276,9 +3960,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class Compiled from "TinyFrameworkNestedClasses.java" @@ -3293,11 +3977,21 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static final java.util.function.Supplier<java.lang.Integer> sSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL Signature: #x // Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses(); descriptor: ()V @@ -3322,6 +4016,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass LocalVariableTable: Start Length Slot Name Signature 11 17 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public java.util.function.Supplier<java.lang.Integer> getSupplier(); descriptor: ()Ljava/util/function/Supplier; @@ -3343,6 +4042,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass Start Length Slot Name Signature 11 9 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static java.util.function.Supplier<java.lang.Integer> getSupplier_static(); descriptor: ()Ljava/util/function/Supplier; @@ -3360,6 +4064,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: areturn LineNumberTable: Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl static {}; descriptor: ()V @@ -3380,6 +4089,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier; x: return LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } InnerClasses: #x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 @@ -3394,9 +4108,9 @@ InnerClasses: SourceFile: "TinyFrameworkNestedClasses.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -3446,6 +4160,11 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi LocalVariableTable: Start Length Slot Name Signature 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public static int foo(int); descriptor: (I)I @@ -3467,13 +4186,18 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi LocalVariableTable: Start Length Slot Name Signature 11 12 0 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "TinyFrameworkPackageRedirect.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub @@ -3489,6 +4213,9 @@ public class com.supported.UnsupportedClass private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl private static {}; descriptor: ()V @@ -3527,6 +4254,9 @@ public class com.supported.UnsupportedClass Start Length Slot Name Signature 26 10 0 this Lcom/supported/UnsupportedClass; 26 10 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int getValue(); descriptor: ()I @@ -3551,11 +4281,14 @@ public class com.supported.UnsupportedClass LocalVariableTable: Start Length Slot Name Signature 26 5 0 this Lcom/supported/UnsupportedClass; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "UnsupportedClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassKeep @@ -3600,6 +4333,11 @@ public class com.unsupported.UnsupportedClass Start Length Slot Name Signature 11 14 0 this Lcom/unsupported/UnsupportedClass; 11 14 1 value I + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl public int getValue(); descriptor: ()I @@ -3620,13 +4358,18 @@ public class com.unsupported.UnsupportedClass LocalVariableTable: Start Length Slot Name Signature 11 10 0 this Lcom/unsupported/UnsupportedClass; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl } SourceFile: "UnsupportedClass.java" RuntimeVisibleAnnotations: x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() - com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java index e7b5d9fc2ece..5a5e22db59e5 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java @@ -16,6 +16,7 @@ package com.android.hoststubgen.test.tinyframework; import android.hosttest.annotation.HostSideTestNativeSubstitutionClass; +import android.hosttest.annotation.HostSideTestThrow; import android.hosttest.annotation.HostSideTestWholeClassStub; @HostSideTestWholeClassStub @@ -44,4 +45,11 @@ public class TinyFrameworkNative { public int nativeNonStaticAddToValue_should_be_like_this(int arg) { return TinyFrameworkNative_host.nativeNonStaticAddToValue(this, arg); } + + @HostSideTestThrow + public static native void nativeStillNotSupported(); + + public static void nativeStillNotSupported_should_be_like_this() { + throw new RuntimeException(); + } } 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 d3501057163d..fc6b862705f8 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 @@ -17,6 +17,8 @@ package com.android.hoststubgen.test.tinyframework; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass; import org.junit.Rule; @@ -158,6 +160,32 @@ public class TinyFrameworkClassTest { assertThat(instance.nativeNonStaticAddToValue(3)).isEqualTo(8); } + + @Test + public void testSubstituteNativeWithThrow() throws Exception { + // We can't use TinyFrameworkNative.nativeStillNotSupported() directly in this class, + // because @Throw implies @Keep (not @Stub), and we currently compile this test + // against the stub jar (so it won't contain @Throw methods). + // + // But the method exists at runtime, so we can use reflections to call it. + // + // In the real Ravenwood environment, we don't use HostStubGen's stub jar at all, + // so it's not a problem. + + final var clazz = TinyFrameworkNative.class; + final var method = clazz.getMethod("nativeStillNotSupported"); + + try { + method.invoke(null); + + fail("java.lang.reflect.InvocationTargetException expected"); + + } catch (java.lang.reflect.InvocationTargetException e) { + var inner = e.getCause(); + assertThat(inner.getMessage()).contains("not supported on the host side"); + } + } + @Test public void testExitLog() { thrown.expect(RuntimeException.class); diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt new file mode 100644 index 000000000000..6b46c84bd0bb --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/asm/AsmUtilsTest.kt @@ -0,0 +1,49 @@ +/* + * 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.hoststubgen.asm + +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.objectweb.asm.Opcodes.ACC_PRIVATE +import org.objectweb.asm.Opcodes.ACC_PROTECTED +import org.objectweb.asm.Opcodes.ACC_PUBLIC +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) { + assertThat(Visibility.fromAccess(access)).isEqualTo(expected) + } + + test(ACC_PUBLIC or ACC_STATIC, Visibility.PUBLIC) + test(ACC_PRIVATE or ACC_STATIC, Visibility.PRIVATE) + test(ACC_PROTECTED or ACC_STATIC, Visibility.PROTECTED) + test(ACC_STATIC, Visibility.PACKAGE_PRIVATE) + } +}
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt new file mode 100644 index 000000000000..0ea90ed2fbf0 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/visitors/HelperTest.kt @@ -0,0 +1,102 @@ +/* + * 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.hoststubgen.visitors + +import com.android.hoststubgen.HostStubGenErrors +import com.android.hoststubgen.asm.ClassNodes +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.objectweb.asm.Opcodes +import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.MethodNode + +class HelperTest { + @Test + fun testCheckSubstitutionMethodCompatibility() { + val errors = object : HostStubGenErrors() { + override fun onErrorFound(message: String) { + // Don't throw + } + } + + val cn = ClassNode().apply { + name = "ClassName" + methods = ArrayList() + } + + val descriptor = "()V" + + val staticPublic = MethodNode().apply { + name = "staticPublic" + access = Opcodes.ACC_STATIC or Opcodes.ACC_PUBLIC + desc = descriptor + cn.methods.add(this) + } + + val staticPrivate = MethodNode().apply { + name = "staticPrivate" + access = Opcodes.ACC_STATIC or Opcodes.ACC_PRIVATE + desc = descriptor + cn.methods.add(this) + } + + val nonStaticPublic = MethodNode().apply { + name = "nonStaticPublic" + access = Opcodes.ACC_PUBLIC + desc = descriptor + cn.methods.add(this) + } + + val nonStaticPProtected = MethodNode().apply { + name = "nonStaticPProtected" + access = 0 + desc = descriptor + cn.methods.add(this) + } + + val classes = ClassNodes().apply { + addClass(cn) + } + + fun check(from: MethodNode?, to: MethodNode?, expected: Boolean) { + assertThat(checkSubstitutionMethodCompatibility( + classes, + cn.name, + (from?.name ?: "**nonexistentmethodname**"), + (to?.name ?: "**nonexistentmethodname**"), + descriptor, + errors, + )).isEqualTo(expected) + } + + check(staticPublic, staticPublic, true) + check(staticPrivate, staticPrivate, true) + check(nonStaticPublic, nonStaticPublic, true) + check(nonStaticPProtected, nonStaticPProtected, true) + + check(staticPublic, null, false) + check(null, staticPublic, false) + + check(staticPublic, nonStaticPublic, false) + check(nonStaticPublic, staticPublic, false) + + check(staticPublic, staticPrivate, false) + check(staticPrivate, staticPublic, true) + + check(nonStaticPublic, nonStaticPProtected, false) + check(nonStaticPProtected, nonStaticPublic, true) + } +}
\ No newline at end of file diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh index 4ea501e27caa..222c874ac34b 100755 --- a/tools/hoststubgen/scripts/run-all-tests.sh +++ b/tools/hoststubgen/scripts/run-all-tests.sh @@ -18,11 +18,14 @@ source "${0%/*}"/../common.sh # Move to the top directory of hoststubgen cd .. +ATEST_ARGS="--host" + # These tests are known to pass. READY_TEST_MODULES=( HostStubGenTest-framework-all-test-host-test hoststubgen-test-tiny-test CtsUtilTestCasesRavenwood + CtsOsTestCasesRavenwood # This one uses native sustitution, so let's run it too. ) MUST_BUILD_MODULES=( @@ -34,7 +37,7 @@ MUST_BUILD_MODULES=( run m "${MUST_BUILD_MODULES[@]}" # Run the hoststubgen unittests / etc -run atest hoststubgentest hoststubgen-invoke-test +run atest $ATEST_ARGS hoststubgentest hoststubgen-invoke-test # Next, run the golden check. This should always pass too. # The following scripts _should_ pass too, but they depend on the internal paths to soong generated @@ -44,13 +47,13 @@ run ./hoststubgen/test-tiny-framework/diff-and-update-golden.sh run ./hoststubgen/test-framework/run-test-without-atest.sh run ./hoststubgen/test-tiny-framework/run-test-manually.sh -run atest tiny-framework-dump-test +run atest $ATEST_ARGS tiny-framework-dump-test run ./scripts/build-framework-hostside-jars-and-extract.sh # This script is already broken on goog/master # run ./scripts/build-framework-hostside-jars-without-genrules.sh # These tests should all pass. -run atest ${READY_TEST_MODULES[*]} +run atest $ATEST_ARGS ${READY_TEST_MODULES[*]} -echo ""${0##*/}" finished, with no failures. Ready to submit!"
\ No newline at end of file +echo ""${0##*/}" finished, with no failures. Ready to submit!" |