diff options
218 files changed, 4429 insertions, 1566 deletions
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp index 9366ff2d81a9..e1b3241e051e 100644 --- a/apct-tests/perftests/core/Android.bp +++ b/apct-tests/perftests/core/Android.bp @@ -66,6 +66,7 @@ android_test { errorprone: { javacflags: [ "-Xep:ReturnValueIgnored:WARN", + "-Xep:UnnecessaryStringBuilder:OFF", ], }, } diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java index c42c7ca25133..2ace6028456e 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java @@ -128,6 +128,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration(); final InsetsState mOutInsetsState = new InsetsState(); final InsetsSourceControl.Array mOutControls = new InsetsSourceControl.Array(); + final Bundle mOutBundle = new Bundle(); final IWindow mWindow; final View mView; final WindowManager.LayoutParams mParams; @@ -136,7 +137,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase final SurfaceControl mOutSurfaceControl; final IntSupplier mViewVisibility; - + int mRelayoutSeq; int mFlags; RelayoutRunner(Activity activity, IWindow window, IntSupplier visibilitySupplier) { @@ -152,10 +153,11 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase void runBenchmark(BenchmarkState state) throws RemoteException { final IWindowSession session = WindowManagerGlobal.getWindowSession(); while (state.keepRunning()) { + mRelayoutSeq++; session.relayout(mWindow, mParams, mWidth, mHeight, - mViewVisibility.getAsInt(), mFlags, 0 /* seq */, 0 /* lastSyncSeqId */, + mViewVisibility.getAsInt(), mFlags, mRelayoutSeq, 0 /* lastSyncSeqId */, mOutFrames, mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, - mOutControls, new Bundle()); + mOutControls, mOutBundle); } } } 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 b828f39a120c..13bea6bd1dd1 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 @@ -598,7 +598,6 @@ public final class JobStatus { long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs, int internalFlags, int dynamicConstraints) { - this.job = job; this.callingUid = callingUid; this.standbyBucket = standbyBucket; mNamespace = namespace; @@ -626,6 +625,22 @@ public final class JobStatus { this.sourceTag = tag; } + // This needs to be done before setting the field variable. + if (job.getRequiredNetwork() != null) { + // Later, when we check if a given network satisfies the required + // network, we need to know the UID that is requesting it, so push + // the source UID into place. + final JobInfo.Builder builder = new JobInfo.Builder(job); + builder.setRequiredNetwork(new NetworkRequest.Builder(job.getRequiredNetwork()) + .setUids(Collections.singleton(new Range<>(this.sourceUid, this.sourceUid))) + .build()); + // Don't perform validation checks at this point since we've already passed the + // initial validation check. + job = builder.build(false, false); + } + + this.job = job; + final String bnNamespace = namespace == null ? "" : "@" + namespace + "@"; this.batteryName = this.sourceTag != null ? bnNamespace + this.sourceTag + ":" + job.getService().getPackageName() @@ -708,21 +723,6 @@ public final class JobStatus { updateNetworkBytesLocked(); - if (job.getRequiredNetwork() != null) { - // Later, when we check if a given network satisfies the required - // network, we need to know the UID that is requesting it, so push - // our source UID into place. - final JobInfo.Builder builder = new JobInfo.Builder(job); - final NetworkRequest.Builder requestBuilder = - new NetworkRequest.Builder(job.getRequiredNetwork()); - requestBuilder.setUids( - Collections.singleton(new Range<Integer>(this.sourceUid, this.sourceUid))); - builder.setRequiredNetwork(requestBuilder.build()); - // Don't perform validation checks at this point since we've already passed the - // initial validation check. - job = builder.build(false, false); - } - updateMediaBackupExemptionStatus(); } diff --git a/api/Android.bp b/api/Android.bp index d6c14fbdfae3..2b1cfcb82d04 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -404,3 +404,49 @@ build = [ "ApiDocs.bp", "StubLibraries.bp", ] + +genrule_defaults { + name: "flag-api-mapping-generation-defaults", + cmd: "$(location extract-flagged-apis) $(in) $(out)", + tools: ["extract-flagged-apis"], +} + +genrule { + name: "flag-api-mapping-PublicApi", + defaults: ["flag-api-mapping-generation-defaults"], + srcs: [":frameworks-base-api-current.txt"], + out: ["flag_api_map.textproto"], + dist: { + targets: ["droid"], + }, +} + +genrule { + name: "flag-api-mapping-SystemApi", + defaults: ["flag-api-mapping-generation-defaults"], + srcs: [":frameworks-base-api-system-current.txt"], + out: ["system_flag_api_map.textproto"], + dist: { + targets: ["droid"], + }, +} + +genrule { + name: "flag-api-mapping-ModuleLibApi", + defaults: ["flag-api-mapping-generation-defaults"], + srcs: [":frameworks-base-api-module-lib-current.txt"], + out: ["module_lib_flag_api_map.textproto"], + dist: { + targets: ["droid"], + }, +} + +genrule { + name: "flag-api-mapping-SystemServerApi", + defaults: ["flag-api-mapping-generation-defaults"], + srcs: [":frameworks-base-api-system-server-current.txt"], + out: ["system_server_flag_api_map.textproto"], + dist: { + targets: ["droid"], + }, +} diff --git a/core/api/current.txt b/core/api/current.txt index 207abb216c37..be76c8ac6ac2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12781,6 +12781,7 @@ package android.content.pm { method public boolean isPackageSuspended(); method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String); method public abstract boolean isSafeMode(); + method @FlaggedApi("android.content.pm.get_package_info") @WorkerThread public <T> T parseAndroidManifest(@NonNull String, @NonNull java.util.function.Function<android.content.res.XmlResourceParser,T>) throws java.io.IOException; method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryActivityProperty(@NonNull String); method @NonNull public java.util.List<android.content.pm.PackageManager.Property> queryApplicationProperty(@NonNull String); method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(@NonNull android.content.Intent, int); @@ -45159,6 +45160,7 @@ package android.telephony { method public void addOnSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid); method public boolean canManageSubscription(android.telephony.SubscriptionInfo); + method @FlaggedApi("com.android.internal.telephony.flags.work_profile_api_split") @NonNull public android.telephony.SubscriptionManager createForAllUserProfiles(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>); method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context); method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 02eaf0b3bbd3..8af12161cc08 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -232,6 +232,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; import com.android.org.conscrypt.TrustedCertificateStore; import com.android.server.am.MemInfoDumpProto; +import com.android.window.flags.Flags; import dalvik.annotation.optimization.NeverCompile; import dalvik.system.AppSpecializationHooks; @@ -3713,7 +3714,13 @@ public final class ActivityThread extends ClientTransactionHandler final ArrayList<ResultInfo> list = new ArrayList<>(); list.add(new ResultInfo(id, requestCode, resultCode, data)); final ClientTransaction clientTransaction = ClientTransaction.obtain(mAppThread); - clientTransaction.addCallback(ActivityResultItem.obtain(activityToken, list)); + final ActivityResultItem activityResultItem = ActivityResultItem.obtain( + activityToken, list); + if (Flags.bundleClientTransactionFlag()) { + clientTransaction.addTransactionItem(activityResultItem); + } else { + clientTransaction.addCallback(activityResultItem); + } try { mAppThread.scheduleTransaction(clientTransaction); } catch (RemoteException e) { @@ -4492,16 +4499,26 @@ public final class ActivityThread extends ClientTransactionHandler private void schedulePauseWithUserLeavingHint(ActivityClientRecord r) { final ClientTransaction transaction = ClientTransaction.obtain(mAppThread); - transaction.setLifecycleStateRequest(PauseActivityItem.obtain(r.token, + final PauseActivityItem pauseActivityItem = PauseActivityItem.obtain(r.token, r.activity.isFinishing(), /* userLeaving */ true, r.activity.mConfigChangeFlags, - /* dontReport */ false, /* autoEnteringPip */ false)); + /* dontReport */ false, /* autoEnteringPip */ false); + if (Flags.bundleClientTransactionFlag()) { + transaction.addTransactionItem(pauseActivityItem); + } else { + transaction.setLifecycleStateRequest(pauseActivityItem); + } executeTransaction(transaction); } private void scheduleResume(ActivityClientRecord r) { final ClientTransaction transaction = ClientTransaction.obtain(mAppThread); - transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(r.token, - /* isForward */ false, /* shouldSendCompatFakeFocus */ false)); + final ResumeActivityItem resumeActivityItem = ResumeActivityItem.obtain(r.token, + /* isForward */ false, /* shouldSendCompatFakeFocus */ false); + if (Flags.bundleClientTransactionFlag()) { + transaction.addTransactionItem(resumeActivityItem); + } else { + transaction.setLifecycleStateRequest(resumeActivityItem); + } executeTransaction(transaction); } @@ -6092,8 +6109,13 @@ public final class ActivityThread extends ClientTransactionHandler TransactionExecutorHelper.getLifecycleRequestForCurrentState(r); // Schedule the transaction. final ClientTransaction transaction = ClientTransaction.obtain(mAppThread); - transaction.addCallback(activityRelaunchItem); - transaction.setLifecycleStateRequest(lifecycleRequest); + if (Flags.bundleClientTransactionFlag()) { + transaction.addTransactionItem(activityRelaunchItem); + transaction.addTransactionItem(lifecycleRequest); + } else { + transaction.addCallback(activityRelaunchItem); + transaction.setLifecycleStateRequest(lifecycleRequest); + } executeTransaction(transaction); } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index ca6d8df1df12..a4c3bb824502 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -80,6 +80,8 @@ import android.content.pm.SuspendDialogInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; +import android.content.pm.parsing.ApkLiteParseUtils; +import android.content.res.ApkAssets; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -144,6 +146,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; +import java.util.function.Function; /** @hide */ public class ApplicationPackageManager extends PackageManager { @@ -4024,4 +4027,34 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowFromSystemServer(); } } + + @Override + public <T> T parseAndroidManifest(@NonNull String apkFilePath, + @NonNull Function<XmlResourceParser, T> parserFunction) throws IOException { + Objects.requireNonNull(apkFilePath, "apkFilePath cannot be null"); + Objects.requireNonNull(parserFunction, "parserFunction cannot be null"); + try (XmlResourceParser xmlResourceParser = getAndroidManifestParser(apkFilePath)) { + return parserFunction.apply(xmlResourceParser); + } catch (IOException e) { + Log.w(TAG, "Failed to get the android manifest parser", e); + throw e; + } + } + + private static XmlResourceParser getAndroidManifestParser(@NonNull String apkFilePath) + throws IOException { + ApkAssets apkAssets = null; + try { + apkAssets = ApkAssets.loadFromPath(apkFilePath); + return apkAssets.openXml(ApkLiteParseUtils.ANDROID_MANIFEST_FILENAME); + } finally { + if (apkAssets != null) { + try { + apkAssets.close(); + } catch (Throwable ignored) { + Log.w(TAG, "Failed to close apkAssets", ignored); + } + } + } + } } diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java index 7c34cdefe95f..5e5526802fe9 100644 --- a/core/java/android/app/servertransaction/ClientTransaction.java +++ b/core/java/android/app/servertransaction/ClientTransaction.java @@ -75,7 +75,6 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem { /** * Adds a message to the end of the sequence of transaction items. * @param item A single message that can contain a client activity/window request/callback. - * TODO(b/260873529): replace both {@link #addCallback} and {@link #setLifecycleStateRequest}. */ public void addTransactionItem(@NonNull ClientTransactionItem item) { if (mTransactionItems == null) { diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java index dfbccb41d045..475c6fb9a48a 100644 --- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -235,7 +235,9 @@ public class TransactionExecutorHelper { * Configuration - ActivityResult - Configuration - ActivityResult * index 1 will be returned, because ActivityResult request on position 1 will be the last * request that moves activity to the RESUMED state where it will eventually end. + * @deprecated to be removed with {@link TransactionExecutor#executeCallbacks}. */ + @Deprecated static int lastCallbackRequestingState(@NonNull ClientTransaction transaction) { final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); if (callbacks == null || callbacks.isEmpty() diff --git a/core/java/android/app/usage/ParcelableUsageEventList.java b/core/java/android/app/usage/ParcelableUsageEventList.java index 016d97f60e26..aa3239237478 100644 --- a/core/java/android/app/usage/ParcelableUsageEventList.java +++ b/core/java/android/app/usage/ParcelableUsageEventList.java @@ -48,13 +48,16 @@ public final class ParcelableUsageEventList implements Parcelable { private List<Event> mList; - public ParcelableUsageEventList(List<Event> list) { + public ParcelableUsageEventList(@NonNull List<Event> list) { + if (list == null) { + throw new IllegalArgumentException("Empty list"); + } mList = list; } private ParcelableUsageEventList(Parcel in) { final int N = in.readInt(); - mList = new ArrayList<>(); + mList = new ArrayList<>(N); if (DEBUG) Log.d(TAG, "Retrieving " + N + " items"); if (N <= 0) { return; diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 1eb452cfd085..6c7eba06dea7 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -24,9 +24,11 @@ import android.content.res.Configuration; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -35,6 +37,7 @@ import java.util.List; * from which to read {@link android.app.usage.UsageEvents.Event} objects. */ public final class UsageEvents implements Parcelable { + private static final String TAG = "UsageEvents"; /** @hide */ public static final String INSTANT_APP_PACKAGE_NAME = "android.instant_app"; @@ -786,10 +789,20 @@ public final class UsageEvents implements Parcelable { } private void readUsageEventsFromParcelWithParceledList(Parcel in) { + mEventCount = in.readInt(); mIndex = in.readInt(); - mEventsToWrite = in.readParcelable(UsageEvents.class.getClassLoader(), - ParcelableUsageEventList.class).getList(); - mEventCount = mEventsToWrite.size(); + ParcelableUsageEventList slice = in.readParcelable(getClass().getClassLoader(), + ParcelableUsageEventList.class); + if (slice != null) { + mEventsToWrite = slice.getList(); + } else { + mEventsToWrite = new ArrayList<>(); + } + + if (mEventCount != mEventsToWrite.size()) { + Log.w(TAG, "Partial usage event list received: " + mEventCount + " != " + + mEventsToWrite.size()); + } } private void readUsageEventsFromParcelWithBlob(Parcel in) { @@ -1065,6 +1078,7 @@ public final class UsageEvents implements Parcelable { } private void writeUsageEventsToParcelWithParceledList(Parcel dest, int flags) { + dest.writeInt(mEventCount); dest.writeInt(mIndex); dest.writeParcelable(new ParcelableUsageEventList(mEventsToWrite), flags); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index c3b3423c1a57..fe31c9dbf27d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -34,6 +34,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UserIdInt; +import android.annotation.WorkerThread; import android.annotation.XmlRes; import android.app.ActivityManager; import android.app.ActivityThread; @@ -96,6 +97,7 @@ import com.android.internal.util.DataClass; import dalvik.system.VMRuntime; import java.io.File; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.security.cert.Certificate; @@ -108,6 +110,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; import java.util.function.Consumer; +import java.util.function.Function; /** * Class for retrieving various kinds of information related to the application @@ -11426,4 +11429,60 @@ public abstract class PackageManager { throw new UnsupportedOperationException( "unregisterPackageMonitorCallback not implemented in subclass"); } + + /** + * Retrieve AndroidManifest.xml information for the given application apk path. + * + * <p>Example: + * + * <pre><code> + * Bundle result; + * try { + * result = getContext().getPackageManager().parseAndroidManifest(apkFilePath, + * xmlResourceParser -> { + * Bundle bundle = new Bundle(); + * // Search the start tag + * int type; + * while ((type = xmlResourceParser.next()) != XmlPullParser.START_TAG + * && type != XmlPullParser.END_DOCUMENT) { + * } + * if (type != XmlPullParser.START_TAG) { + * return bundle; + * } + * + * // Start to read the tags and attributes from the xmlResourceParser + * if (!xmlResourceParser.getName().equals("manifest")) { + * return bundle; + * } + * String packageName = xmlResourceParser.getAttributeValue(null, "package"); + * bundle.putString("package", packageName); + * + * // Continue to read the tags and attributes from the xmlResourceParser + * + * return bundle; + * }); + * } catch (IOException e) { + * } + * </code></pre> + * + * Note: When the parserFunction is invoked, the client can read the AndroidManifest.xml + * information by the XmlResourceParser object. After leaving the parserFunction, the + * XmlResourceParser object will be closed. + * + * @param apkFilePath The path of an application apk file. + * @param parserFunction The parserFunction will be invoked with the XmlResourceParser object + * after getting the AndroidManifest.xml of an application package. + * + * @return Returns the result of the {@link Function#apply(Object)}. + * + * @throws IOException if the AndroidManifest.xml of an application package cannot be + * read or accessed. + */ + @FlaggedApi(android.content.pm.Flags.FLAG_GET_PACKAGE_INFO) + @WorkerThread + public <T> T parseAndroidManifest(@NonNull String apkFilePath, + @NonNull Function<XmlResourceParser, T> parserFunction) throws IOException { + throw new UnsupportedOperationException( + "parseAndroidManifest not implemented in subclass"); + } } diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java index 7756b9ca7e5a..c3791888b44f 100644 --- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java +++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java @@ -22,9 +22,11 @@ import android.annotation.RequiresPermission; import android.content.Context; import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.Trace; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; @@ -45,6 +47,8 @@ import java.util.concurrent.Executor; @VisibleForTesting(visibility = Visibility.PACKAGE) public final class DeviceStateManagerGlobal { private static DeviceStateManagerGlobal sInstance; + private static final String TAG = "DeviceStateManagerGlobal"; + private static final boolean DEBUG = Build.IS_DEBUGGABLE; /** * Returns an instance of {@link DeviceStateManagerGlobal}. May return {@code null} if a @@ -400,11 +404,29 @@ public final class DeviceStateManagerGlobal { } void notifyBaseStateChanged(int newBaseState) { - mExecutor.execute(() -> mDeviceStateCallback.onBaseStateChanged(newBaseState)); + execute("notifyBaseStateChanged", + () -> mDeviceStateCallback.onBaseStateChanged(newBaseState)); } void notifyStateChanged(int newDeviceState) { - mExecutor.execute(() -> mDeviceStateCallback.onStateChanged(newDeviceState)); + execute("notifyStateChanged", + () -> mDeviceStateCallback.onStateChanged(newDeviceState)); + } + + private void execute(String traceName, Runnable r) { + mExecutor.execute(() -> { + if (DEBUG) { + Trace.beginSection( + mDeviceStateCallback.getClass().getSimpleName() + "#" + traceName); + } + try { + r.run(); + } finally { + if (DEBUG) { + Trace.endSection(); + } + } + }); } } diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 4791a8341912..f71e853a1170 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -721,8 +721,19 @@ public abstract class DisplayManagerInternal { public interface DisplayOffloadSession { /** Provide the display state to use in place of state DOZE. */ void setDozeStateOverride(int displayState); - /** Returns the associated DisplayOffloader. */ - DisplayOffloader getDisplayOffloader(); + + /** Whether the session is active. */ + boolean isActive(); + + /** + * Update the brightness from the offload chip. + * @param brightness The brightness value between {@link PowerManager.BRIGHTNESS_MIN} and + * {@link PowerManager.BRIGHTNESS_MAX}, or + * {@link PowerManager.BRIGHTNESS_INVALID_FLOAT} which removes + * the brightness from offload. Other values will be ignored. + */ + void updateBrightness(float brightness); + /** Returns whether displayoffload supports the given display state. */ static boolean isSupportedOffloadState(int displayState) { return Display.isSuspendedState(displayState); diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index f817fb8dcaed..1100731702a2 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -82,8 +82,8 @@ public final class BinderProxy implements IBinder { private static final int MAIN_INDEX_SIZE = 1 << LOG_MAIN_INDEX_SIZE; private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1; /** - * Debuggable builds will throw an BinderProxyMapSizeException if the number of - * map entries exceeds: + * We will throw a BinderProxyMapSizeException if the number of map entries + * exceeds: */ private static final int CRASH_AT_SIZE = 25_000; diff --git a/core/java/android/util/DataUnit.java b/core/java/android/util/DataUnit.java index cc33af32ba93..10905e1b1908 100644 --- a/core/java/android/util/DataUnit.java +++ b/core/java/android/util/DataUnit.java @@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public enum DataUnit { KILOBYTES { @Override public long toBytes(long v) { return v * 1_000; } }, MEGABYTES { @Override public long toBytes(long v) { return v * 1_000_000; } }, diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java index 4654dbfa9531..d2c5975ea356 100644 --- a/core/java/android/util/EventLog.java +++ b/core/java/android/util/EventLog.java @@ -48,6 +48,9 @@ import java.util.regex.Pattern; * They carry a payload of one or more int, long, or String values. The * event-log-tags file defines the payload contents for each type code. */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass +@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass( + "com.android.hoststubgen.nativesubstitution.EventLog_host") public class EventLog { /** @hide */ public EventLog() {} @@ -416,6 +419,7 @@ public class EventLog { /** * Read TAGS_FILE, populating sTagCodes and sTagNames, if not already done. */ + @android.ravenwood.annotation.RavenwoodReplace private static synchronized void readTagsFile() { if (sTagCodes != null && sTagNames != null) return; @@ -441,8 +445,7 @@ public class EventLog { try { int num = Integer.parseInt(m.group(1)); String name = m.group(2); - sTagCodes.put(name, num); - sTagNames.put(num, name); + registerTagLocked(num, name); } catch (NumberFormatException e) { Log.wtf(TAG, "Error in " + TAGS_FILE + ": " + line, e); } @@ -454,4 +457,20 @@ public class EventLog { try { if (reader != null) reader.close(); } catch (IOException e) {} } } + + private static void registerTagLocked(int num, String name) { + sTagCodes.put(name, num); + sTagNames.put(num, name); + } + + private static synchronized void readTagsFile$ravenwood() { + // TODO: restore parsing logic once we carry into runtime + sTagCodes = new HashMap<String, Integer>(); + sTagNames = new HashMap<Integer, String>(); + + // Hard-code a few common tags + registerTagLocked(524288, "sysui_action"); + registerTagLocked(524290, "sysui_count"); + registerTagLocked(524291, "sysui_histogram"); + } } diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java index c04a71c4d31b..413ae1f5cbcf 100644 --- a/core/java/android/util/IntArray.java +++ b/core/java/android/util/IntArray.java @@ -26,6 +26,7 @@ import java.util.Arrays; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class IntArray implements Cloneable { private static final int MIN_CAPACITY_INCREMENT = 12; diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java index 3101c0da6986..4c7ef08ddfcb 100644 --- a/core/java/android/util/LongArray.java +++ b/core/java/android/util/LongArray.java @@ -30,6 +30,7 @@ import java.util.Arrays; * * @hide */ +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class LongArray implements Cloneable { private static final int MIN_CAPACITY_INCREMENT = 12; diff --git a/core/java/android/util/Slog.java b/core/java/android/util/Slog.java index 3aeeccaba250..c0ceb9ea8204 100644 --- a/core/java/android/util/Slog.java +++ b/core/java/android/util/Slog.java @@ -31,6 +31,7 @@ import android.os.Build; * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public final class Slog { private Slog() { @@ -216,6 +217,7 @@ public final class Slog { * @see Log#wtf(String, String) */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @android.ravenwood.annotation.RavenwoodThrow public static int wtf(@Nullable String tag, @NonNull String msg) { return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, false, true); } @@ -223,6 +225,7 @@ public final class Slog { /** * Similar to {@link #wtf(String, String)}, but does not output anything to the log. */ + @android.ravenwood.annotation.RavenwoodThrow public static void wtfQuiet(@Nullable String tag, @NonNull String msg) { Log.wtfQuiet(Log.LOG_ID_SYSTEM, tag, msg, true); } @@ -241,6 +244,7 @@ public final class Slog { * @see Log#wtfStack(String, String) */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + @android.ravenwood.annotation.RavenwoodThrow public static int wtfStack(@Nullable String tag, @NonNull String msg) { return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, null, true, true); } @@ -259,6 +263,7 @@ public final class Slog { * * @see Log#wtf(String, Throwable) */ + @android.ravenwood.annotation.RavenwoodThrow public static int wtf(@Nullable String tag, @Nullable Throwable tr) { return Log.wtf(Log.LOG_ID_SYSTEM, tag, tr.getMessage(), tr, false, true); } @@ -279,6 +284,7 @@ public final class Slog { * @see Log#wtf(String, String, Throwable) */ @UnsupportedAppUsage + @android.ravenwood.annotation.RavenwoodThrow public static int wtf(@Nullable String tag, @NonNull String msg, @Nullable Throwable tr) { return Log.wtf(Log.LOG_ID_SYSTEM, tag, msg, tr, false, true); } diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index d06b0ce1a2d8..bff8db13ad14 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -41,6 +41,8 @@ import java.util.List; /** * A class containing utility methods related to time zones. */ +@android.ravenwood.annotation.RavenwoodKeepPartialClass +@android.ravenwood.annotation.RavenwoodKeepStaticInitializer public class TimeUtils { /** @hide */ public TimeUtils() {} /** {@hide} */ @@ -180,6 +182,7 @@ public class TimeUtils { private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10]; private static char[] sTmpFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10]; + @android.ravenwood.annotation.RavenwoodKeep static private int accumField(int amt, int suffix, boolean always, int zeropad) { if (amt > 999) { int num = 0; @@ -202,6 +205,7 @@ public class TimeUtils { return 0; } + @android.ravenwood.annotation.RavenwoodKeep static private int printFieldLocked(char[] formatStr, int amt, char suffix, int pos, boolean always, int zeropad) { if (always || amt > 0) { @@ -242,6 +246,7 @@ public class TimeUtils { return pos; } + @android.ravenwood.annotation.RavenwoodKeep private static int formatDurationLocked(long duration, int fieldLen) { if (sFormatStr.length < fieldLen) { sFormatStr = new char[fieldLen]; @@ -314,6 +319,7 @@ public class TimeUtils { } /** @hide Just for debugging; not internationalized. */ + @android.ravenwood.annotation.RavenwoodKeep public static void formatDuration(long duration, StringBuilder builder) { synchronized (sFormatSync) { int len = formatDurationLocked(duration, 0); @@ -322,6 +328,7 @@ public class TimeUtils { } /** @hide Just for debugging; not internationalized. */ + @android.ravenwood.annotation.RavenwoodKeep public static void formatDuration(long duration, StringBuilder builder, int fieldLen) { synchronized (sFormatSync) { int len = formatDurationLocked(duration, fieldLen); @@ -331,6 +338,7 @@ public class TimeUtils { /** @hide Just for debugging; not internationalized. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + @android.ravenwood.annotation.RavenwoodKeep public static void formatDuration(long duration, PrintWriter pw, int fieldLen) { synchronized (sFormatSync) { int len = formatDurationLocked(duration, fieldLen); @@ -340,6 +348,7 @@ public class TimeUtils { /** @hide Just for debugging; not internationalized. */ @TestApi + @android.ravenwood.annotation.RavenwoodKeep public static String formatDuration(long duration) { synchronized (sFormatSync) { int len = formatDurationLocked(duration, 0); @@ -349,11 +358,13 @@ public class TimeUtils { /** @hide Just for debugging; not internationalized. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + @android.ravenwood.annotation.RavenwoodKeep public static void formatDuration(long duration, PrintWriter pw) { formatDuration(duration, pw, 0); } /** @hide Just for debugging; not internationalized. */ + @android.ravenwood.annotation.RavenwoodKeep public static void formatDuration(long time, long now, StringBuilder sb) { if (time == 0) { sb.append("--"); @@ -363,6 +374,7 @@ public class TimeUtils { } /** @hide Just for debugging; not internationalized. */ + @android.ravenwood.annotation.RavenwoodKeep public static void formatDuration(long time, long now, PrintWriter pw) { if (time == 0) { pw.print("--"); @@ -372,16 +384,19 @@ public class TimeUtils { } /** @hide Just for debugging; not internationalized. */ + @android.ravenwood.annotation.RavenwoodKeep public static String formatUptime(long time) { return formatTime(time, SystemClock.uptimeMillis()); } /** @hide Just for debugging; not internationalized. */ + @android.ravenwood.annotation.RavenwoodKeep public static String formatRealtime(long time) { return formatTime(time, SystemClock.elapsedRealtime()); } /** @hide Just for debugging; not internationalized. */ + @android.ravenwood.annotation.RavenwoodKeep public static String formatTime(long time, long referenceTime) { long diff = time - referenceTime; if (diff > 0) { @@ -402,6 +417,7 @@ public class TimeUtils { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @android.ravenwood.annotation.RavenwoodKeep public static String logTimeOfDay(long millis) { Calendar c = Calendar.getInstance(); if (millis >= 0) { @@ -413,6 +429,7 @@ public class TimeUtils { } /** {@hide} */ + @android.ravenwood.annotation.RavenwoodKeep public static String formatForLogging(long millis) { if (millis <= 0) { return "unknown"; @@ -426,6 +443,7 @@ public class TimeUtils { * * @hide */ + @android.ravenwood.annotation.RavenwoodKeep public static void dumpTime(PrintWriter pw, long time) { pw.print(sDumpDateFormat.format(new Date(time))); } @@ -457,6 +475,7 @@ public class TimeUtils { * * @hide */ + @android.ravenwood.annotation.RavenwoodKeep public static void dumpTimeWithDelta(PrintWriter pw, long time, long now) { pw.print(sDumpDateFormat.format(new Date(time))); if (time == now) { diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig index 42a1f1e58967..11bd22f7d6ff 100644 --- a/core/java/android/window/flags/window_surfaces.aconfig +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -37,5 +37,6 @@ flag { namespace: "window_surfaces" name: "remove_capture_display" description: "Remove uses of ScreenCapture#captureDisplay" + is_fixed_read_only: true bug: "293445881" }
\ No newline at end of file diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index b600b22751ff..933cc49f8602 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -9,6 +9,16 @@ flag { bug: "260873529" } +# Using a fixed read only flag because there are ClientTransaction scheduling before +# WindowManagerService creation. +flag { + namespace: "windowing_sdk" + name: "bundle_client_transaction_flag" + description: "To bundle multiple ClientTransactionItems into one ClientTransaction" + bug: "260873529" + is_fixed_read_only: true +} + flag { namespace: "windowing_sdk" name: "activity_embedding_overlay_presentation_flag" diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java index df6c1538fc6d..e3bb1fe8b736 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java @@ -66,10 +66,6 @@ public class SystemUiSystemPropertiesFlags { public static final Flag SHOW_STICKY_HUN_FOR_DENIED_FSI = releasedFlag("persist.sysui.notification.show_sticky_hun_for_denied_fsi"); - /** Gating the redaction of OTP notifications on the lockscreen */ - public static final Flag OTP_REDACTION = - devFlag("persist.sysui.notification.otp_redaction"); - /** Gating the logging of DND state change events. */ public static final Flag LOG_DND_STATE_EVENTS = releasedFlag("persist.sysui.notification.log_dnd_state_events"); diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 5c1d91ff540e..5b68e8ed1ad8 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -184,11 +184,11 @@ status_t NativeInputEventReceiver::reportTimeline(int32_t inputEventId, nsecs_t void NativeInputEventReceiver::setFdEvents(int events) { if (mFdEvents != events) { mFdEvents = events; - int fd = mInputConsumer.getChannel()->getFd(); + auto&& fd = mInputConsumer.getChannel()->getFd(); if (events) { - mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr); + mMessageQueue->getLooper()->addFd(fd.get(), 0, events, this, nullptr); } else { - mMessageQueue->getLooper()->removeFd(fd); + mMessageQueue->getLooper()->removeFd(fd.get()); } } } diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 833952def02b..6bdf8214a1bf 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -102,8 +102,8 @@ NativeInputEventSender::~NativeInputEventSender() { } status_t NativeInputEventSender::initialize() { - int receiveFd = mInputPublisher.getChannel()->getFd(); - mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL); + auto&& receiveFd = mInputPublisher.getChannel()->getFd(); + mMessageQueue->getLooper()->addFd(receiveFd.get(), 0, ALOOPER_EVENT_INPUT, this, NULL); return OK; } @@ -112,7 +112,7 @@ void NativeInputEventSender::dispose() { LOG(DEBUG) << "channel '" << getInputChannelName() << "' ~ Disposing input event sender."; } - mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel()->getFd()); + mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel()->getFd().get()); } status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* event) { diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 68bad45b6e00..6cd6eb4b8df9 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5465,6 +5465,7 @@ <item>1,1,1.0,.15,15</item> <item>0,0,0.7,0,1</item> <item>0,0,0.83333,0,1</item> + <item>0,0,1.1667,0,1</item> </string-array> <!-- The integer index of the selected option in config_udfps_touch_detection_options --> diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 4b02257978d2..2327b20bada6 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -42,6 +42,7 @@ import android.app.IApplicationThread; import android.app.PictureInPictureParams; import android.app.ResourcesManager; import android.app.servertransaction.ActivityConfigurationChangeItem; +import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityRelaunchItem; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.ClientTransactionItem; @@ -73,6 +74,7 @@ import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; import com.android.internal.content.ReferrerIntent; +import com.android.window.flags.Flags; import org.junit.After; import org.junit.Before; @@ -227,7 +229,8 @@ public class ActivityThreadTest { try { // Send process level config change. ClientTransaction transaction = newTransaction(activityThread); - transaction.addCallback(ConfigurationChangeItem.obtain(newConfig, DEVICE_ID_INVALID)); + addClientTransactionItem(transaction, ConfigurationChangeItem.obtain( + newConfig, DEVICE_ID_INVALID)); appThread.scheduleTransaction(transaction); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); @@ -243,7 +246,7 @@ public class ActivityThreadTest { newConfig.seq++; newConfig.smallestScreenWidthDp++; transaction = newTransaction(activityThread); - transaction.addCallback(ActivityConfigurationChangeItem.obtain( + addClientTransactionItem(transaction, ActivityConfigurationChangeItem.obtain( activity.getActivityToken(), newConfig)); appThread.scheduleTransaction(transaction); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); @@ -444,16 +447,16 @@ public class ActivityThreadTest { activity.mTestLatch = new CountDownLatch(1); ClientTransaction transaction = newTransaction(activityThread); - transaction.addCallback(ConfigurationChangeItem.obtain( + addClientTransactionItem(transaction, ConfigurationChangeItem.obtain( processConfigLandscape, DEVICE_ID_INVALID)); appThread.scheduleTransaction(transaction); transaction = newTransaction(activityThread); - transaction.addCallback(ActivityConfigurationChangeItem.obtain( + addClientTransactionItem(transaction, ActivityConfigurationChangeItem.obtain( activity.getActivityToken(), activityConfigLandscape)); - transaction.addCallback(ConfigurationChangeItem.obtain( + addClientTransactionItem(transaction, ConfigurationChangeItem.obtain( processConfigPortrait, DEVICE_ID_INVALID)); - transaction.addCallback(ActivityConfigurationChangeItem.obtain( + addClientTransactionItem(transaction, ActivityConfigurationChangeItem.obtain( activity.getActivityToken(), activityConfigPortrait)); appThread.scheduleTransaction(transaction); @@ -840,8 +843,8 @@ public class ActivityThreadTest { false /* shouldSendCompatFakeFocus*/); final ClientTransaction transaction = newTransaction(activity); - transaction.addCallback(callbackItem); - transaction.setLifecycleStateRequest(resumeStateRequest); + addClientTransactionItem(transaction, callbackItem); + addClientTransactionItem(transaction, resumeStateRequest); return transaction; } @@ -853,7 +856,7 @@ public class ActivityThreadTest { false /* shouldSendCompatFakeFocus */); final ClientTransaction transaction = newTransaction(activity); - transaction.setLifecycleStateRequest(resumeStateRequest); + addClientTransactionItem(transaction, resumeStateRequest); return transaction; } @@ -864,7 +867,7 @@ public class ActivityThreadTest { activity.getActivityToken(), 0 /* configChanges */); final ClientTransaction transaction = newTransaction(activity); - transaction.setLifecycleStateRequest(stopStateRequest); + addClientTransactionItem(transaction, stopStateRequest); return transaction; } @@ -876,7 +879,7 @@ public class ActivityThreadTest { activity.getActivityToken(), config); final ClientTransaction transaction = newTransaction(activity); - transaction.addCallback(item); + addClientTransactionItem(transaction, item); return transaction; } @@ -888,7 +891,7 @@ public class ActivityThreadTest { resume); final ClientTransaction transaction = newTransaction(activity); - transaction.addCallback(item); + addClientTransactionItem(transaction, item); return transaction; } @@ -903,6 +906,17 @@ public class ActivityThreadTest { return ClientTransaction.obtain(activityThread.getApplicationThread()); } + private static void addClientTransactionItem(@NonNull ClientTransaction transaction, + @NonNull ClientTransactionItem item) { + if (Flags.bundleClientTransactionFlag()) { + transaction.addTransactionItem(item); + } else if (item.isActivityLifecycleItem()) { + transaction.setLifecycleStateRequest((ActivityLifecycleItem) item); + } else { + transaction.addCallback(item); + } + } + // Test activity public static class TestActivity extends Activity { static final String PIP_REQUESTED_OVERRIDE_ENTER = "pip_requested_override_enter"; diff --git a/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java b/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java index 2ec58d43477d..5a202c5e8834 100644 --- a/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java +++ b/core/tests/coretests/src/android/app/usage/ParcelableUsageEventListTest.java @@ -20,6 +20,7 @@ import static android.view.Surface.ROTATION_90; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -43,11 +44,29 @@ import java.util.Random; @LargeTest public class ParcelableUsageEventListTest { private static final int SMALL_TEST_EVENT_COUNT = 100; - private static final int LARGE_TEST_EVENT_COUNT = 10000; + private static final int LARGE_TEST_EVENT_COUNT = 30000; private Random mRandom = new Random(); @Test + public void testNullList() throws Exception { + Parcel parcel = Parcel.obtain(); + try { + parcel.writeParcelable(new ParcelableUsageEventList(null), 0); + fail("Expected IllegalArgumentException with null list."); + } catch (IllegalArgumentException expected) { + // Expected. + } finally { + parcel.recycle(); + } + } + + @Test + public void testEmptyList() throws Exception { + testParcelableUsageEventList(0); + } + + @Test public void testSmallList() throws Exception { testParcelableUsageEventList(SMALL_TEST_EVENT_COUNT); } @@ -58,15 +77,15 @@ public class ParcelableUsageEventListTest { } private void testParcelableUsageEventList(int eventCount) throws Exception { - List<Event> smallList = new ArrayList<>(); + List<Event> eventList = new ArrayList<>(); for (int i = 0; i < eventCount; i++) { - smallList.add(generateUsageEvent()); + eventList.add(generateUsageEvent()); } ParcelableUsageEventList slice; Parcel parcel = Parcel.obtain(); try { - parcel.writeParcelable(new ParcelableUsageEventList(smallList), 0); + parcel.writeParcelable(new ParcelableUsageEventList(eventList), 0); parcel.setDataPosition(0); slice = parcel.readParcelable(getClass().getClassLoader(), ParcelableUsageEventList.class); @@ -79,7 +98,7 @@ public class ParcelableUsageEventListTest { assertEquals(eventCount, slice.getList().size()); for (int i = 0; i < eventCount; i++) { - compareUsageEvent(smallList.get(i), slice.getList().get(i)); + compareUsageEvent(eventList.get(i), slice.getList().get(i)); } } diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp index 580e73c331a1..06340a222ac6 100644 --- a/core/tests/utiltests/Android.bp +++ b/core/tests/utiltests/Android.bp @@ -35,6 +35,7 @@ android_test { "androidx.test.ext.junit", "truth", "servicestests-utils", + "ravenwood-junit", ], libs: [ @@ -50,3 +51,22 @@ android_test { test_suites: ["device-tests"], } + +android_ravenwood_test { + name: "FrameworksUtilTestsRavenwood", + static_libs: [ + "androidx.annotation_annotation", + "androidx.test.rules", + ], + srcs: [ + "src/android/util/DataUnitTest.java", + "src/android/util/EventLogTest.java", + "src/android/util/IndentingPrintWriterTest.java", + "src/android/util/IntArrayTest.java", + "src/android/util/LocalLogTest.java", + "src/android/util/LongArrayTest.java", + "src/android/util/SlogTest.java", + "src/android/util/TimeUtilsTest.java", + ], + auto_gen_config: true, +} diff --git a/core/tests/coretests/src/android/util/DataUnitTest.java b/core/tests/utiltests/src/android/util/DataUnitTest.java index 034cbddc0144..af9ebc833d4b 100644 --- a/core/tests/coretests/src/android/util/DataUnitTest.java +++ b/core/tests/utiltests/src/android/util/DataUnitTest.java @@ -16,12 +16,18 @@ package android.util; +import static org.junit.Assert.assertEquals; + import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; @SmallTest -public class DataUnitTest extends TestCase { +@RunWith(AndroidJUnit4.class) +public class DataUnitTest { + @Test public void testSi() throws Exception { assertEquals(12_000L, DataUnit.KILOBYTES.toBytes(12)); assertEquals(12_000_000L, DataUnit.MEGABYTES.toBytes(12)); @@ -29,6 +35,7 @@ public class DataUnitTest extends TestCase { assertEquals(12_000_000_000_000L, DataUnit.TERABYTES.toBytes(12)); } + @Test public void testIec() throws Exception { assertEquals(12_288L, DataUnit.KIBIBYTES.toBytes(12)); assertEquals(12_582_912L, DataUnit.MEBIBYTES.toBytes(12)); diff --git a/core/tests/coretests/src/android/util/EventLogTest.java b/core/tests/utiltests/src/android/util/EventLogTest.java index 94e72c4a8d52..0ebf2c163d19 100644 --- a/core/tests/coretests/src/android/util/EventLogTest.java +++ b/core/tests/utiltests/src/android/util/EventLogTest.java @@ -16,23 +16,42 @@ package android.util; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.ravenwood.RavenwoodRule; import android.util.EventLog.Event; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import junit.framework.AssertionFailedError; +import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.List; /** Unit tests for {@link android.util.EventLog} */ +@SmallTest +@RunWith(AndroidJUnit4.class) public class EventLogTest { + @Rule public final RavenwoodRule mRavenwood = new RavenwoodRule(); + + @Test + public void testSimple() throws Throwable { + EventLog.writeEvent(42, 42); + EventLog.writeEvent(42, 42L); + EventLog.writeEvent(42, 42f); + EventLog.writeEvent(42, "forty-two"); + EventLog.writeEvent(42, 42, "forty-two", null, 42); + } @Test + @IgnoreUnderRavenwood(reason = "Reading not yet supported") public void testWithNewData() throws Throwable { Event event = createEvent(() -> { EventLog.writeEvent(314, 123); diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/utiltests/src/android/util/LocalLogTest.java index d4861cd391a8..5025a3d0980c 100644 --- a/core/tests/coretests/src/android/util/LocalLogTest.java +++ b/core/tests/utiltests/src/android/util/LocalLogTest.java @@ -16,9 +16,13 @@ package android.util; +import static org.junit.Assert.assertTrue; + import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; -import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; import java.io.PrintWriter; import java.io.StringWriter; @@ -27,13 +31,16 @@ import java.util.Collections; import java.util.List; @LargeTest -public class LocalLogTest extends TestCase { +@RunWith(AndroidJUnit4.class) +public class LocalLogTest { + @Test public void testA_localTimestamps() { boolean localTimestamps = true; doTestA(localTimestamps); } + @Test public void testA_nonLocalTimestamps() { boolean localTimestamps = false; doTestA(localTimestamps); @@ -49,6 +56,7 @@ public class LocalLogTest extends TestCase { testcase(new LocalLog(10, localTimestamps), lines, want); } + @Test public void testB() { String[] lines = { "foo", @@ -59,6 +67,7 @@ public class LocalLogTest extends TestCase { testcase(new LocalLog(0), lines, want); } + @Test public void testC() { String[] lines = { "dropped", diff --git a/core/tests/utiltests/src/android/util/SlogTest.java b/core/tests/utiltests/src/android/util/SlogTest.java new file mode 100644 index 000000000000..6f761e348dbe --- /dev/null +++ b/core/tests/utiltests/src/android/util/SlogTest.java @@ -0,0 +1,47 @@ +/* + * 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.util; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SlogTest { + private static final String TAG = "tag"; + private static final String MSG = "msg"; + private static final Throwable THROWABLE = new Throwable(); + + @Test + public void testSimple() { + Slog.v(TAG, MSG); + Slog.d(TAG, MSG); + Slog.i(TAG, MSG); + Slog.w(TAG, MSG); + Slog.e(TAG, MSG); + } + + @Test + public void testThrowable() { + Slog.v(TAG, MSG, THROWABLE); + Slog.d(TAG, MSG, THROWABLE); + Slog.i(TAG, MSG, THROWABLE); + Slog.w(TAG, MSG, THROWABLE); + Slog.e(TAG, MSG, THROWABLE); + } +} diff --git a/core/tests/utiltests/src/android/util/TimeUtilsTest.java b/core/tests/utiltests/src/android/util/TimeUtilsTest.java new file mode 100644 index 000000000000..e8246c83e086 --- /dev/null +++ b/core/tests/utiltests/src/android/util/TimeUtilsTest.java @@ -0,0 +1,117 @@ +/* + * 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.util; + +import static org.junit.Assert.assertEquals; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.function.Consumer; + +@RunWith(AndroidJUnit4.class) +public class TimeUtilsTest { + public static final long SECOND_IN_MILLIS = 1000; + public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60; + public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60; + public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24; + public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7; + + @Test + public void testFormatTime() { + assertEquals("1672556400000 (now)", + TimeUtils.formatTime(1672556400000L, 1672556400000L)); + assertEquals("1672556400000 (in 10 ms)", + TimeUtils.formatTime(1672556400000L, 1672556400000L - 10)); + assertEquals("1672556400000 (10 ms ago)", + TimeUtils.formatTime(1672556400000L, 1672556400000L + 10)); + + // Uses formatter above, so we just care that it doesn't crash + TimeUtils.formatRealtime(1672556400000L); + TimeUtils.formatUptime(1672556400000L); + } + + @Test + public void testFormatDuration_Zero() { + assertEquals("0", TimeUtils.formatDuration(0)); + } + + @Test + public void testFormatDuration_Negative() { + assertEquals("-10ms", TimeUtils.formatDuration(-10)); + } + + @Test + public void testFormatDuration() { + long accum = 900; + assertEquals("+900ms", TimeUtils.formatDuration(accum)); + + accum += 59 * SECOND_IN_MILLIS; + assertEquals("+59s900ms", TimeUtils.formatDuration(accum)); + + accum += 59 * MINUTE_IN_MILLIS; + assertEquals("+59m59s900ms", TimeUtils.formatDuration(accum)); + + accum += 23 * HOUR_IN_MILLIS; + assertEquals("+23h59m59s900ms", TimeUtils.formatDuration(accum)); + + accum += 6 * DAY_IN_MILLIS; + assertEquals("+6d23h59m59s900ms", TimeUtils.formatDuration(accum)); + } + + @Test + public void testDumpTime() { + assertEquals("2023-01-01 00:00:00.000", runWithPrintWriter((pw) -> { + TimeUtils.dumpTime(pw, 1672556400000L); + })); + assertEquals("2023-01-01 00:00:00.000 (now)", runWithPrintWriter((pw) -> { + TimeUtils.dumpTimeWithDelta(pw, 1672556400000L, 1672556400000L); + })); + assertEquals("2023-01-01 00:00:00.000 (-10ms)", runWithPrintWriter((pw) -> { + TimeUtils.dumpTimeWithDelta(pw, 1672556400000L, 1672556400000L + 10); + })); + } + + @Test + public void testFormatForLogging() { + assertEquals("unknown", TimeUtils.formatForLogging(0)); + assertEquals("unknown", TimeUtils.formatForLogging(-1)); + assertEquals("unknown", TimeUtils.formatForLogging(Long.MIN_VALUE)); + assertEquals("2023-01-01 00:00:00", TimeUtils.formatForLogging(1672556400000L)); + } + + @Test + public void testLogTimeOfDay() { + assertEquals("01-01 00:00:00.000", TimeUtils.logTimeOfDay(1672556400000L)); + } + + public static String runWithPrintWriter(Consumer<PrintWriter> consumer) { + final StringWriter sw = new StringWriter(); + consumer.accept(new PrintWriter(sw)); + return sw.toString(); + } + + public static String runWithStringBuilder(Consumer<StringBuilder> consumer) { + final StringBuilder sb = new StringBuilder(); + consumer.accept(sb); + return sb.toString(); + } +} diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java index 07f1d4a09006..8dc9579e6b52 100644 --- a/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java +++ b/errorprone/java/com/google/errorprone/bugpatterns/android/HideInCommentsChecker.java @@ -63,7 +63,7 @@ public class HideInCommentsChecker extends BugChecker implements @Override public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) { - final Map<Integer, Tree> javadocableTrees = findJavadocableTrees(tree); + final Map<Integer, Tree> javadocableTrees = findJavadocableTrees(tree, state); final String sourceCode = state.getSourceCode().toString(); for (ErrorProneToken token : ErrorProneTokens.getTokens(sourceCode, state.context)) { for (Tokens.Comment comment : token.comments()) { @@ -112,9 +112,9 @@ public class HideInCommentsChecker extends BugChecker implements } - private Map<Integer, Tree> findJavadocableTrees(CompilationUnitTree tree) { + private Map<Integer, Tree> findJavadocableTrees(CompilationUnitTree tree, VisitorState state) { Map<Integer, Tree> javadoccableTrees = new HashMap<>(); - new SuppressibleTreePathScanner<Void, Void>() { + new SuppressibleTreePathScanner<Void, Void>(state) { @Override public Void visitClass(ClassTree classTree, Void unused) { javadoccableTrees.put(getStartPosition(classTree), classTree); diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index c366ccd235db..4d2d960822d1 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -42,3 +42,11 @@ flag { description: "Enables PiP UI state callback on entering" bug: "303718131" } + +flag { + name: "enable_pip2_implementation" + namespace: "multitasking" + description: "Enables the new implementation of PiP (PiP2)" + bug: "290220798" + is_fixed_read_only: true +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt index 108aa8275009..1e30d8feb132 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt @@ -21,13 +21,13 @@ import android.app.WindowConfiguration import android.content.ComponentName import android.content.Context import android.os.RemoteException -import android.os.SystemProperties import android.util.DisplayMetrics import android.util.Log import android.util.Pair import android.util.TypedValue import android.window.TaskSnapshot import com.android.internal.protolog.common.ProtoLog +import com.android.wm.shell.Flags import com.android.wm.shell.protolog.ShellProtoLogGroup import kotlin.math.abs @@ -37,7 +37,6 @@ object PipUtils { // Minimum difference between two floats (e.g. aspect ratios) to consider them not equal. private const val EPSILON = 1e-7 - private const val ENABLE_PIP2_IMPLEMENTATION = "persist.wm.debug.enable_pip2_implementation" /** * @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack. @@ -138,5 +137,5 @@ object PipUtils { @JvmStatic val isPip2ExperimentEnabled: Boolean - get() = SystemProperties.getBoolean(ENABLE_PIP2_IMPLEMENTATION, false) + get() = Flags.enablePip2Implementation() }
\ No newline at end of file diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index d78038ecee61..9ab9ba8bbfed 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -224,6 +224,11 @@ android_library { extra_check_modules: ["SystemUILintChecker"], warning_checks: ["MissingApacheLicenseDetector"], }, + errorprone: { + javacflags: [ + "-Xep:InvalidPatternSyntax:WARN", + ], + }, } filegroup { @@ -548,6 +553,11 @@ android_library { test: true, extra_check_modules: ["SystemUILintChecker"], }, + errorprone: { + javacflags: [ + "-Xep:InvalidPatternSyntax:WARN", + ], + }, } android_app { @@ -589,6 +599,12 @@ android_app { }, plugins: ["dagger2-compiler"], + + errorprone: { + javacflags: [ + "-Xep:InvalidPatternSyntax:WARN", + ], + }, } android_robolectric_test { diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 68d4b6319b2f..a745ab5cbdd9 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -140,4 +140,11 @@ flag { namespace: "systemui" description: "Move LightRevealScrim to recommended architecture" bug: "281655028" -}
\ No newline at end of file +} + +flag { + name: "media_in_scene_container" + namespace: "systemui" + description: "Enable media in the scene container framework" + bug: "296122467" +} diff --git a/packages/SystemUI/communal/layout/Android.bp b/packages/SystemUI/communal/layout/Android.bp deleted file mode 100644 index 88dad6623d03..000000000000 --- a/packages/SystemUI/communal/layout/Android.bp +++ /dev/null @@ -1,35 +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 { - default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], -} - -android_library { - name: "CommunalLayoutLib", - srcs: [ - "src/**/*.kt", - ], - static_libs: [ - "androidx.arch.core_core-runtime", - "androidx.compose.animation_animation-graphics", - "androidx.compose.runtime_runtime", - "androidx.compose.material3_material3", - "jsr330", - "kotlinx-coroutines-android", - "kotlinx-coroutines-core", - ], - manifest: "AndroidManifest.xml", - kotlincflags: ["-Xjvm-default=all"], -} diff --git a/packages/SystemUI/communal/layout/AndroidManifest.xml b/packages/SystemUI/communal/layout/AndroidManifest.xml deleted file mode 100644 index 141be0762ae9..000000000000 --- a/packages/SystemUI/communal/layout/AndroidManifest.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- 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. ---> - -<manifest package="com.android.systemui.communal.layout" /> diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt deleted file mode 100644 index 91fe33cd2f4b..000000000000 --- a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/CommunalLayoutEngine.kt +++ /dev/null @@ -1,69 +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.communal.layout - -import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard - -/** Computes the arrangement of cards. */ -class CommunalLayoutEngine { - companion object { - /** - * Determines the size that each card should be rendered in, and distributes the cards into - * columns. - * - * Returns a nested list where the outer list contains columns, and the inner list contains - * cards in each column. - * - * Currently treats the first supported size as the size to be rendered in, ignoring other - * supported sizes. - * - * Cards are ordered by priority, from highest to lowest. - */ - fun distributeCardsIntoColumns( - cards: List<CommunalGridLayoutCard>, - ): List<List<CommunalGridLayoutCardInfo>> { - val result = ArrayList<ArrayList<CommunalGridLayoutCardInfo>>() - - var capacityOfLastColumn = 0 - val sorted = cards.sortedByDescending { it.priority } - for (card in sorted) { - val cardSize = card.supportedSizes.first() - if (capacityOfLastColumn >= cardSize.value) { - // Card fits in last column - capacityOfLastColumn -= cardSize.value - } else { - // Create a new column - result.add(arrayListOf()) - capacityOfLastColumn = CommunalGridLayoutCard.Size.FULL.value - cardSize.value - } - - result.last().add(CommunalGridLayoutCardInfo(card, cardSize)) - } - - return result - } - } - - /** - * A data class that wraps around a [CommunalGridLayoutCard] and also contains the size that the - * card should be rendered in. - */ - data class CommunalGridLayoutCardInfo( - val card: CommunalGridLayoutCard, - val size: CommunalGridLayoutCard.Size, - ) -} diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt deleted file mode 100644 index 33024f764710..000000000000 --- a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/CommunalGridLayout.kt +++ /dev/null @@ -1,72 +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.communal.layout.ui.compose - -import android.util.SizeF -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.android.systemui.communal.layout.CommunalLayoutEngine -import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard -import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutConfig - -/** - * An arrangement of cards with a horizontal scroll, where each card is displayed in the right size - * and follows a specific order based on its priority, ensuring a seamless layout without any gaps. - */ -@Composable -fun CommunalGridLayout( - modifier: Modifier, - layoutConfig: CommunalGridLayoutConfig, - communalCards: List<CommunalGridLayoutCard>, -) { - val columns = CommunalLayoutEngine.distributeCardsIntoColumns(communalCards) - LazyRow( - modifier = modifier.height(layoutConfig.gridHeight), - horizontalArrangement = Arrangement.spacedBy(layoutConfig.gridGutter), - ) { - for (column in columns) { - item { - Column( - modifier = Modifier.width(layoutConfig.cardWidth), - verticalArrangement = Arrangement.spacedBy(layoutConfig.gridGutter), - ) { - for (cardInfo in column) { - Row( - modifier = Modifier.height(layoutConfig.cardHeight(cardInfo.size)), - ) { - cardInfo.card.Content( - modifier = Modifier.fillMaxSize(), - size = - SizeF( - layoutConfig.cardWidth.value, - layoutConfig.cardHeight(cardInfo.size).value, - ), - ) - } - } - } - } - } - } -} diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt deleted file mode 100644 index 4b2a156c1dbd..000000000000 --- a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutCard.kt +++ /dev/null @@ -1,68 +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.communal.layout.ui.compose.config - -import android.util.SizeF -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier - -/** A card that hosts content to be rendered in the communal grid layout. */ -abstract class CommunalGridLayoutCard { - /** - * Content to be hosted by the card. - * - * To host non-Compose views, see - * https://developer.android.com/jetpack/compose/migrate/interoperability-apis/views-in-compose. - * - * @param size The size given to the card. Content of the card should fill all this space, given - * that margins and paddings have been taken care of by the layout. - */ - @Composable abstract fun Content(modifier: Modifier, size: SizeF) - - /** - * Sizes supported by the card. - * - * If multiple sizes are available, they should be ranked in order of preference, from most to - * least preferred. - */ - abstract val supportedSizes: List<Size> - - /** - * Priority of the content hosted by the card. - * - * The value of priority is relative to other cards. Cards with a higher priority are generally - * ordered first. - */ - open val priority: Int = 0 - - /** - * Size of the card. - * - * @param value A numeric value that represents the size. Must be less than or equal to - * [Size.FULL]. - */ - enum class Size(val value: Int) { - /** The card takes up full height of the grid layout. */ - FULL(value = 6), - - /** The card takes up half of the vertical space of the grid layout. */ - HALF(value = 3), - - /** The card takes up a third of the vertical space of the grid layout. */ - THIRD(value = 2), - } -} diff --git a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt b/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt deleted file mode 100644 index 143df838169b..000000000000 --- a/packages/SystemUI/communal/layout/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfig.kt +++ /dev/null @@ -1,82 +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.communal.layout.ui.compose.config - -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.times - -/** - * Configurations of the communal grid layout. - * - * The communal grid layout follows Material Design's responsive layout grid (see - * https://m2.material.io/design/layout/responsive-layout-grid.html), in which the layout is divided - * up by columns and gutters, and each card occupies one or multiple columns. - */ -data class CommunalGridLayoutConfig( - /** - * Size in dp of each grid column. - * - * Every card occupies one or more grid columns, which means that the width of each card is - * influenced by the size of the grid columns. - */ - val gridColumnSize: Dp, - - /** - * Size in dp of each grid gutter. - * - * A gutter is the space between columns that helps separate content. This is, therefore, also - * the size of the gaps between cards, both horizontally and vertically. - */ - val gridGutter: Dp, - - /** - * Height in dp of the grid layout. - * - * Cards with a full size take up the entire height of the grid layout. - */ - val gridHeight: Dp, - - /** - * Number of grid columns that each card occupies. - * - * It's important to note that all the cards take up the same number of grid columns, or in - * simpler terms, they all have the same width. - */ - val gridColumnsPerCard: Int, -) { - /** - * Width in dp of each card. - * - * It's important to note that all the cards take up the same number of grid columns, or in - * simpler terms, they all have the same width. - */ - val cardWidth = gridColumnSize * gridColumnsPerCard + gridGutter * (gridColumnsPerCard - 1) - - /** Returns the height of a card in dp, based on its size. */ - fun cardHeight(cardSize: CommunalGridLayoutCard.Size): Dp { - return when (cardSize) { - CommunalGridLayoutCard.Size.FULL -> cardHeightBy(denominator = 1) - CommunalGridLayoutCard.Size.HALF -> cardHeightBy(denominator = 2) - CommunalGridLayoutCard.Size.THIRD -> cardHeightBy(denominator = 3) - } - } - - /** Returns the height of a card in dp when the layout is evenly divided by [denominator]. */ - private fun cardHeightBy(denominator: Int): Dp { - return (gridHeight - (denominator - 1) * gridGutter) / denominator - } -} diff --git a/packages/SystemUI/communal/layout/tests/Android.bp b/packages/SystemUI/communal/layout/tests/Android.bp deleted file mode 100644 index 9a05504cad8b..000000000000 --- a/packages/SystemUI/communal/layout/tests/Android.bp +++ /dev/null @@ -1,47 +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 { - default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], -} - -android_test { - name: "CommunalLayoutLibTests", - srcs: [ - "**/*.kt", - ], - static_libs: [ - "CommunalLayoutLib", - "androidx.test.runner", - "androidx.test.rules", - "androidx.test.ext.junit", - "frameworks-base-testutils", - "junit", - "kotlinx_coroutines_test", - "mockito-target-extended-minus-junit4", - "platform-test-annotations", - "testables", - "truth", - ], - libs: [ - "android.test.mock", - "android.test.base", - "android.test.runner", - ], - jni_libs: [ - "libdexmakerjvmtiagent", - "libstaticjvmtiagent", - ], - manifest: "AndroidManifest.xml", -} diff --git a/packages/SystemUI/communal/layout/tests/AndroidManifest.xml b/packages/SystemUI/communal/layout/tests/AndroidManifest.xml deleted file mode 100644 index b19007c1ff1b..000000000000 --- a/packages/SystemUI/communal/layout/tests/AndroidManifest.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest - xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.systemui.communal.layout.tests"> - - <application android:debuggable="true" android:largeHeap="true"> - <uses-library android:name="android.test.mock" /> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation android:name="android.testing.TestableInstrumentation" - android:targetPackage="com.android.systemui.communal.layout.tests" - android:label="Tests for CommunalLayoutLib"> - </instrumentation> - -</manifest> diff --git a/packages/SystemUI/communal/layout/tests/AndroidTest.xml b/packages/SystemUI/communal/layout/tests/AndroidTest.xml deleted file mode 100644 index 1352b238f6fe..000000000000 --- a/packages/SystemUI/communal/layout/tests/AndroidTest.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<configuration description="Runs tests for CommunalLayoutLib"> - - <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> - <option name="cleanup-apks" value="true" /> - <option name="install-arg" value="-t" /> - <option name="test-file-name" value="CommunalLayoutLibTests.apk" /> - </target_preparer> - - <option name="test-suite-tag" value="apct" /> - <option name="test-suite-tag" value="framework-base-presubmit" /> - <option name="test-tag" value="CommunalLayoutLibTests" /> - - <test class="com.android.tradefed.testtype.AndroidJUnitTest" > - <option name="package" value="com.android.systemui.communal.layout.tests" /> - <option name="runner" value="android.testing.TestableInstrumentation" /> - <option name="hidden-api-checks" value="false"/> - </test> - -</configuration> diff --git a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt deleted file mode 100644 index 50b7c5f02068..000000000000 --- a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/CommunalLayoutEngineTest.kt +++ /dev/null @@ -1,145 +0,0 @@ -package com.android.systemui.communal.layout - -import android.util.SizeF -import androidx.compose.material3.Card -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.systemui.communal.layout.ui.compose.config.CommunalGridLayoutCard -import com.google.common.truth.Truth.assertThat -import org.junit.Test -import org.junit.runner.RunWith - -@SmallTest -@RunWith(AndroidJUnit4::class) -class CommunalLayoutEngineTest { - @Test - fun distribution_fullLayout() { - val cards = - listOf( - generateCard(CommunalGridLayoutCard.Size.FULL), - generateCard(CommunalGridLayoutCard.Size.HALF), - generateCard(CommunalGridLayoutCard.Size.HALF), - generateCard(CommunalGridLayoutCard.Size.THIRD), - generateCard(CommunalGridLayoutCard.Size.THIRD), - generateCard(CommunalGridLayoutCard.Size.THIRD), - ) - val expected = - listOf( - listOf( - CommunalGridLayoutCard.Size.FULL, - ), - listOf( - CommunalGridLayoutCard.Size.HALF, - CommunalGridLayoutCard.Size.HALF, - ), - listOf( - CommunalGridLayoutCard.Size.THIRD, - CommunalGridLayoutCard.Size.THIRD, - CommunalGridLayoutCard.Size.THIRD, - ), - ) - - assertDistributionBySize(cards, expected) - } - - @Test - fun distribution_layoutWithGaps() { - val cards = - listOf( - generateCard(CommunalGridLayoutCard.Size.HALF), - generateCard(CommunalGridLayoutCard.Size.THIRD), - generateCard(CommunalGridLayoutCard.Size.HALF), - generateCard(CommunalGridLayoutCard.Size.FULL), - generateCard(CommunalGridLayoutCard.Size.THIRD), - ) - val expected = - listOf( - listOf( - CommunalGridLayoutCard.Size.HALF, - CommunalGridLayoutCard.Size.THIRD, - ), - listOf( - CommunalGridLayoutCard.Size.HALF, - ), - listOf( - CommunalGridLayoutCard.Size.FULL, - ), - listOf( - CommunalGridLayoutCard.Size.THIRD, - ), - ) - - assertDistributionBySize(cards, expected) - } - - @Test - fun distribution_sortByPriority() { - val cards = - listOf( - generateCard(priority = 2), - generateCard(priority = 7), - generateCard(priority = 10), - generateCard(priority = 1), - generateCard(priority = 5), - ) - val expected = - listOf( - listOf(10, 7), - listOf(5, 2), - listOf(1), - ) - - assertDistributionByPriority(cards, expected) - } - - private fun assertDistributionBySize( - cards: List<CommunalGridLayoutCard>, - expected: List<List<CommunalGridLayoutCard.Size>>, - ) { - val result = CommunalLayoutEngine.distributeCardsIntoColumns(cards) - - for (c in expected.indices) { - for (r in expected[c].indices) { - assertThat(result[c][r].size).isEqualTo(expected[c][r]) - } - } - } - - private fun assertDistributionByPriority( - cards: List<CommunalGridLayoutCard>, - expected: List<List<Int>>, - ) { - val result = CommunalLayoutEngine.distributeCardsIntoColumns(cards) - - for (c in expected.indices) { - for (r in expected[c].indices) { - assertThat(result[c][r].card.priority).isEqualTo(expected[c][r]) - } - } - } - - private fun generateCard(size: CommunalGridLayoutCard.Size): CommunalGridLayoutCard { - return object : CommunalGridLayoutCard() { - override val supportedSizes = listOf(size) - - @Composable - override fun Content(modifier: Modifier, size: SizeF) { - Card(modifier = modifier, content = {}) - } - } - } - - private fun generateCard(priority: Int): CommunalGridLayoutCard { - return object : CommunalGridLayoutCard() { - override val supportedSizes = listOf(Size.HALF) - override val priority = priority - - @Composable - override fun Content(modifier: Modifier, size: SizeF) { - Card(modifier = modifier, content = {}) - } - } - } -} diff --git a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt b/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt deleted file mode 100644 index 946eeecbec5d..000000000000 --- a/packages/SystemUI/communal/layout/tests/src/com/android/systemui/communal/layout/ui/compose/config/CommunalGridLayoutConfigTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.android.systemui.communal.layout.ui.compose.config - -import androidx.compose.ui.unit.dp -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.google.common.truth.Truth -import org.junit.Test -import org.junit.runner.RunWith - -@SmallTest -@RunWith(AndroidJUnit4::class) -class CommunalGridLayoutConfigTest { - @Test - fun cardWidth() { - Truth.assertThat( - CommunalGridLayoutConfig( - gridColumnSize = 5.dp, - gridGutter = 3.dp, - gridHeight = 17.dp, - gridColumnsPerCard = 1, - ) - .cardWidth - ) - .isEqualTo(5.dp) - - Truth.assertThat( - CommunalGridLayoutConfig( - gridColumnSize = 5.dp, - gridGutter = 3.dp, - gridHeight = 17.dp, - gridColumnsPerCard = 2, - ) - .cardWidth - ) - .isEqualTo(13.dp) - - Truth.assertThat( - CommunalGridLayoutConfig( - gridColumnSize = 5.dp, - gridGutter = 3.dp, - gridHeight = 17.dp, - gridColumnsPerCard = 3, - ) - .cardWidth - ) - .isEqualTo(21.dp) - } - - @Test - fun cardHeight() { - val config = - CommunalGridLayoutConfig( - gridColumnSize = 5.dp, - gridGutter = 2.dp, - gridHeight = 10.dp, - gridColumnsPerCard = 3, - ) - - Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.FULL)).isEqualTo(10.dp) - Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.HALF)).isEqualTo(4.dp) - Truth.assertThat(config.cardHeight(CommunalGridLayoutCard.Size.THIRD)).isEqualTo(2.dp) - } -} diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp index 16c24375d14f..796abf4b52d6 100644 --- a/packages/SystemUI/compose/features/Android.bp +++ b/packages/SystemUI/compose/features/Android.bp @@ -31,7 +31,6 @@ android_library { ], static_libs: [ - "CommunalLayoutLib", "SystemUI-core", "PlatformComposeCore", "PlatformComposeSceneTransitionLayout", 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 ce84c19a53ee..2c4dc806f468 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 @@ -65,10 +65,13 @@ fun CommunalContainer( viewModel.currentScene .transform<CommunalSceneKey, SceneKey> { value -> value.toTransitionSceneKey() } .collectAsState(TransitionSceneKey.Blank) + // 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) // Failsafe to hide the whole SceneTransitionLayout in case of bugginess. var showSceneTransitionLayout by remember { mutableStateOf(true) } - if (!showSceneTransitionLayout) { + if (!showSceneTransitionLayout || !isKeyguardShowing) { return } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt index 28a4801d582a..765468372604 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt @@ -25,9 +25,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect @@ -36,7 +33,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -76,9 +72,6 @@ fun SceneScope.QuickSettings( .element(QuickSettings.Elements.Content) .fillMaxWidth() .defaultMinSize(minHeight = 300.dp) - .clip(RoundedCornerShape(32.dp)) - .background(MaterialTheme.colorScheme.primary) - .padding(1.dp), ) { QuickSettingsContent(qsSceneAdapter = qsSceneAdapter, state) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 9dd7bfaf3549..871d9f9b7627 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -23,7 +23,7 @@ import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.clickable +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -51,6 +52,7 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.ui.composable.ComposableScene import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.ExpandedShadeHeader +import com.android.systemui.shade.ui.composable.Shade import com.android.systemui.shade.ui.composable.ShadeHeader import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager @@ -104,53 +106,59 @@ private fun SceneScope.QuickSettingsScene( ) { // TODO(b/280887232): implement the real UI. Box(modifier = modifier.fillMaxSize()) { - val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState() - val collapsedHeaderHeight = - with(LocalDensity.current) { ShadeHeader.Dimensions.CollapsedHeight.roundToPx() } - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = - Modifier.fillMaxSize() - .clickable(onClick = { viewModel.onContentClicked() }) - .padding(start = 16.dp, end = 16.dp, bottom = 48.dp) - ) { - when (LocalWindowSizeClass.current.widthSizeClass) { - WindowWidthSizeClass.Compact -> - AnimatedVisibility( - visible = !isCustomizing, - enter = - expandVertically( - animationSpec = tween(1000), - initialHeight = { collapsedHeaderHeight }, - ) + fadeIn(tween(1000)), - exit = - shrinkVertically( - animationSpec = tween(1000), - targetHeight = { collapsedHeaderHeight }, - shrinkTowards = Alignment.Top, - ) + fadeOut(tween(1000)), - ) { - ExpandedShadeHeader( + Box(modifier = Modifier.fillMaxSize()) { + val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState() + val collapsedHeaderHeight = + with(LocalDensity.current) { ShadeHeader.Dimensions.CollapsedHeight.roundToPx() } + Spacer( + modifier = + Modifier.element(Shade.Elements.ScrimBackground) + .fillMaxSize() + .background(MaterialTheme.colorScheme.scrim, shape = Shade.Shapes.Scrim) + ) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = + Modifier.fillMaxSize().padding(start = 16.dp, end = 16.dp, bottom = 48.dp) + ) { + when (LocalWindowSizeClass.current.widthSizeClass) { + WindowWidthSizeClass.Compact -> + AnimatedVisibility( + visible = !isCustomizing, + enter = + expandVertically( + animationSpec = tween(1000), + initialHeight = { collapsedHeaderHeight }, + ) + fadeIn(tween(1000)), + exit = + shrinkVertically( + animationSpec = tween(1000), + targetHeight = { collapsedHeaderHeight }, + shrinkTowards = Alignment.Top, + ) + fadeOut(tween(1000)), + ) { + ExpandedShadeHeader( + viewModel = viewModel.shadeHeaderViewModel, + createTintedIconManager = createTintedIconManager, + createBatteryMeterViewController = createBatteryMeterViewController, + statusBarIconController = statusBarIconController, + ) + } + else -> + CollapsedShadeHeader( viewModel = viewModel.shadeHeaderViewModel, createTintedIconManager = createTintedIconManager, createBatteryMeterViewController = createBatteryMeterViewController, statusBarIconController = statusBarIconController, ) - } - else -> - CollapsedShadeHeader( - viewModel = viewModel.shadeHeaderViewModel, - createTintedIconManager = createTintedIconManager, - createBatteryMeterViewController = createBatteryMeterViewController, - statusBarIconController = statusBarIconController, - ) + } + Spacer(modifier = Modifier.height(16.dp)) + QuickSettings( + modifier = Modifier.fillMaxHeight(), + viewModel.qsSceneAdapter, + QSSceneAdapter.State.QS + ) } - Spacer(modifier = Modifier.height(16.dp)) - QuickSettings( - modifier = Modifier.fillMaxHeight(), - viewModel.qsSceneAdapter, - QSSceneAdapter.State.QS - ) } HeadsUpNotificationSpace( viewModel = viewModel.notifications, diff --git a/packages/SystemUI/res/layout/udfps_touch_overlay.xml b/packages/SystemUI/res/layout/udfps_touch_overlay.xml new file mode 100644 index 000000000000..ea92776aba2d --- /dev/null +++ b/packages/SystemUI/res/layout/udfps_touch_overlay.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/udfps_touch_overlay" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@string/accessibility_fingerprint_label"> +</com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 1fa55f5d839b..54cb501db002 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -384,6 +384,11 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } } + @Nullable + View getAodNotifIconContainer() { + return mAodIconContainer; + } + @Override protected void onViewDetached() { mClockRegistry.unregisterClockChangeListener(mClockChangedListener); @@ -639,6 +644,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } } else { mNotificationIconAreaController.setupAodIcons(nic); + mAodIconContainer = nic; } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 87d937bc45fb..4fbf077a8852 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -84,6 +84,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV Dumpable { private static final boolean DEBUG = KeyguardConstants.DEBUG; @VisibleForTesting static final String TAG = "KeyguardStatusViewController"; + private static final long STATUS_AREA_HEIGHT_ANIMATION_MILLIS = 133; /** * Duration to use for the animator when the keyguard status view alignment changes, and a @@ -104,6 +105,10 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV private final KeyguardInteractor mKeyguardInteractor; private final PowerInteractor mPowerInteractor; private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; + private final DozeParameters mDozeParameters; + + private View mStatusArea = null; + private ValueAnimator mStatusAreaHeightAnimator = null; private Boolean mSplitShadeEnabled = false; private Boolean mStatusViewCentered = true; @@ -123,6 +128,46 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } }; + private final View.OnLayoutChangeListener mStatusAreaLayoutChangeListener = + new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, + int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom + ) { + if (!mDozeParameters.getAlwaysOn()) { + return; + } + + int oldHeight = oldBottom - oldTop; + int diff = v.getHeight() - oldHeight; + if (diff == 0) { + return; + } + + int startValue = -1 * diff; + long duration = STATUS_AREA_HEIGHT_ANIMATION_MILLIS; + if (mStatusAreaHeightAnimator != null + && mStatusAreaHeightAnimator.isRunning()) { + duration += mStatusAreaHeightAnimator.getDuration() + - mStatusAreaHeightAnimator.getCurrentPlayTime(); + startValue += (int) mStatusAreaHeightAnimator.getAnimatedValue(); + mStatusAreaHeightAnimator.cancel(); + mStatusAreaHeightAnimator = null; + } + + mStatusAreaHeightAnimator = ValueAnimator.ofInt(startValue, 0); + mStatusAreaHeightAnimator.setDuration(duration); + final View nic = mKeyguardClockSwitchController.getAodNotifIconContainer(); + if (nic != null) { + mStatusAreaHeightAnimator.addUpdateListener(anim -> { + nic.setTranslationY((int) anim.getAnimatedValue()); + }); + } + mStatusAreaHeightAnimator.start(); + } + }; + @Inject public KeyguardStatusViewController( KeyguardStatusView keyguardStatusView, @@ -144,6 +189,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV mKeyguardClockSwitchController = keyguardClockSwitchController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mConfigurationController = configurationController; + mDozeParameters = dozeParameters; mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController, dozeParameters, screenOffAnimationController, /* animateYPos= */ true, logger.getBuffer()); @@ -218,12 +264,15 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV @Override protected void onViewAttached() { + mStatusArea = mView.findViewById(R.id.keyguard_status_area); + mStatusArea.addOnLayoutChangeListener(mStatusAreaLayoutChangeListener); mKeyguardUpdateMonitor.registerCallback(mInfoCallback); mConfigurationController.addCallback(mConfigurationListener); } @Override protected void onViewDetached() { + mStatusArea.removeOnLayoutChangeListener(mStatusAreaLayoutChangeListener); mKeyguardUpdateMonitor.removeCallback(mInfoCallback); mConfigurationController.removeCallback(mConfigurationListener); } @@ -293,9 +342,15 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV /** * Get the height of the keyguard status view without the notification icon area, as that's * only visible on AOD. + * + * We internally animate height changes to the status area to prevent discontinuities in the + * doze animation introduced by the height suddenly changing due to smartpace. */ public int getLockscreenHeight() { - return mView.getHeight() - mKeyguardClockSwitchController.getNotificationIconAreaHeight(); + int heightAnimValue = mStatusAreaHeightAnimator == null ? 0 : + (int) mStatusAreaHeightAnimator.getAnimatedValue(); + return mView.getHeight() + heightAnimValue + - mKeyguardClockSwitchController.getNotificationIconAreaHeight(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 57e252dd9929..8fe42b536b1e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -100,7 +100,6 @@ import javax.inject.Inject; import javax.inject.Provider; import kotlin.Unit; - import kotlinx.coroutines.CoroutineScope; /** @@ -1099,6 +1098,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, // TODO(b/141025588): Create separate methods for handling hard and soft errors. final boolean isSoftError = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT + || error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL || isCameraPrivacyEnabled); if (mCurrentDialog != null) { if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index b064391f74b5..e15538b88d8c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -52,6 +52,7 @@ import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.MotionEvent; +import android.view.View; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; @@ -78,9 +79,9 @@ 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.Main; +import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor; import com.android.systemui.doze.DozeReceiver; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; @@ -150,7 +151,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor; @NonNull private final Provider<UdfpsKeyguardViewModels> mUdfpsKeyguardViewModels; @NonNull private final VibratorHelper mVibrator; - @NonNull private final FeatureFlags mFeatureFlags; @NonNull private final FalsingManager mFalsingManager; @NonNull private final PowerManager mPowerManager; @NonNull private final AccessibilityManager mAccessibilityManager; @@ -281,7 +281,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { fromUdfpsView ), mActivityLaunchAnimator, - mFeatureFlags, mPrimaryBouncerInteractor, mAlternateBouncerInteractor, mUdfpsKeyguardAccessibilityDelegate, @@ -318,10 +317,8 @@ public class UdfpsController implements DozeReceiver, Dumpable { return; } mAcquiredReceived = true; - final UdfpsView view = mOverlay.getOverlayView(); - if (view != null && isOptical()) { - unconfigureDisplay(view); - } + final View view = mOverlay.getTouchOverlay(); + unconfigureDisplay(view); tryAodSendFingerUp(); }); } @@ -339,7 +336,9 @@ public class UdfpsController implements DozeReceiver, Dumpable { if (mOverlay == null || mOverlay.isHiding()) { return; } - mOverlay.getOverlayView().setDebugMessage(message); + if (!DeviceEntryUdfpsRefactor.isEnabled()) { + ((UdfpsView) mOverlay.getTouchOverlay()).setDebugMessage(message); + } }); } @@ -506,6 +505,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f && !mAlternateBouncerInteractor.isVisibleState()) || mPrimaryBouncerInteractor.isInTransit()) { + Log.w(TAG, "ignoring touch due to qsDragProcess or primaryBouncerInteractor"); return false; } if (event.getAction() == MotionEvent.ACTION_DOWN @@ -563,7 +563,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { } mAttemptedToDismissKeyguard = false; onFingerUp(requestId, - mOverlay.getOverlayView(), + mOverlay.getTouchOverlay(), data.getPointerId(), data.getX(), data.getY(), @@ -597,7 +597,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { if (shouldPilfer && !mPointerPilfered && getBiometricSessionType() != SESSION_BIOMETRIC_PROMPT) { mInputManager.pilferPointers( - mOverlay.getOverlayView().getViewRootImpl().getInputToken()); + mOverlay.getTouchOverlay().getViewRootImpl().getInputToken()); mPointerPilfered = true; } @@ -605,9 +605,15 @@ public class UdfpsController implements DozeReceiver, Dumpable { } private boolean shouldTryToDismissKeyguard() { - return mOverlay != null - && mOverlay.getAnimationViewController() - instanceof UdfpsKeyguardViewControllerAdapter + boolean onKeyguard = false; + if (DeviceEntryUdfpsRefactor.isEnabled()) { + onKeyguard = mKeyguardStateController.isShowing(); + } else { + onKeyguard = mOverlay != null + && mOverlay.getAnimationViewController() + instanceof UdfpsKeyguardViewControllerAdapter; + } + return onKeyguard && mKeyguardStateController.canDismissLockScreen() && !mAttemptedToDismissKeyguard; } @@ -623,7 +629,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, @NonNull DumpManager dumpManager, @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, - @NonNull FeatureFlags featureFlags, @NonNull FalsingManager falsingManager, @NonNull PowerManager powerManager, @NonNull AccessibilityManager accessibilityManager, @@ -670,7 +675,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { mDumpManager = dumpManager; mDialogManager = dialogManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mFeatureFlags = featureFlags; mFalsingManager = falsingManager; mPowerManager = powerManager; mAccessibilityManager = accessibilityManager; @@ -737,9 +741,9 @@ public class UdfpsController implements DozeReceiver, Dumpable { @VisibleForTesting public void playStartHaptic() { if (mAccessibilityManager.isTouchExplorationEnabled()) { - if (mOverlay != null && mOverlay.getOverlayView() != null) { + if (mOverlay != null && mOverlay.getTouchOverlay() != null) { mVibrator.performHapticFeedback( - mOverlay.getOverlayView(), + mOverlay.getTouchOverlay(), HapticFeedbackConstants.CONTEXT_CLICK ); } else { @@ -751,10 +755,11 @@ public class UdfpsController implements DozeReceiver, Dumpable { @Override public void dozeTimeTick() { - if (mOverlay != null) { - final UdfpsView view = mOverlay.getOverlayView(); + if (mOverlay != null && mOverlay.getTouchOverlay() instanceof UdfpsView) { + DeviceEntryUdfpsRefactor.assertInLegacyMode(); + final View view = mOverlay.getTouchOverlay(); if (view != null) { - view.dozeTimeTick(); + ((UdfpsView) view).dozeTimeTick(); } } } @@ -797,7 +802,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { if (mOverlay != null) { // Reset the controller back to its starting state. - final UdfpsView oldView = mOverlay.getOverlayView(); + final View oldView = mOverlay.getTouchOverlay(); if (oldView != null) { onFingerUp(mOverlay.getRequestId(), oldView); } @@ -813,9 +818,21 @@ public class UdfpsController implements DozeReceiver, Dumpable { } - private void unconfigureDisplay(@NonNull UdfpsView view) { - if (view.isDisplayConfigured()) { - view.unconfigureDisplay(); + private void unconfigureDisplay(View view) { + if (!isOptical()) { + return; + } + if (DeviceEntryUdfpsRefactor.isEnabled()) { + if (mUdfpsDisplayMode != null) { + mUdfpsDisplayMode.disable(null); // beverlt + } + } else { + if (view != null) { + UdfpsView udfpsView = (UdfpsView) view; + if (udfpsView.isDisplayConfigured()) { + udfpsView.unconfigureDisplay(); + } + } } } @@ -837,10 +854,10 @@ public class UdfpsController implements DozeReceiver, Dumpable { } mKeyguardViewManager.showPrimaryBouncer(true); - // play the same haptic as the LockIconViewController longpress - if (mOverlay != null && mOverlay.getOverlayView() != null) { + // play the same haptic as the DeviceEntryIcon longpress + if (mOverlay != null && mOverlay.getTouchOverlay() != null) { mVibrator.performHapticFeedback( - mOverlay.getOverlayView(), + mOverlay.getTouchOverlay(), UdfpsController.LONG_PRESS ); } else { @@ -909,8 +926,8 @@ public class UdfpsController implements DozeReceiver, Dumpable { return; } cancelAodSendFingerUpAction(); - if (mOverlay != null && mOverlay.getOverlayView() != null) { - onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView()); + if (mOverlay != null && mOverlay.getTouchOverlay() != null) { + onFingerUp(mOverlay.getRequestId(), mOverlay.getTouchOverlay()); } } @@ -1004,12 +1021,17 @@ public class UdfpsController implements DozeReceiver, Dumpable { mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, pointerId, x, y, minor, major, orientation, time, gestureStart, isAod); Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0); - final UdfpsView view = mOverlay.getOverlayView(); + + final View view = mOverlay.getTouchOverlay(); if (view != null && isOptical()) { if (mIgnoreRefreshRate) { dispatchOnUiReady(requestId); } else { - view.configureDisplay(() -> dispatchOnUiReady(requestId)); + if (DeviceEntryUdfpsRefactor.isEnabled()) { + mUdfpsDisplayMode.enable(() -> dispatchOnUiReady(requestId)); + } else { + ((UdfpsView) view).configureDisplay(() -> dispatchOnUiReady(requestId)); + } } } @@ -1018,7 +1040,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { } } - private void onFingerUp(long requestId, @NonNull UdfpsView view) { + private void onFingerUp(long requestId, @NonNull View view) { onFingerUp( requestId, view, @@ -1035,7 +1057,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { private void onFingerUp( long requestId, - @NonNull UdfpsView view, + View view, int pointerId, float x, float y, @@ -1056,9 +1078,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { } } mOnFingerDown = false; - if (isOptical()) { - unconfigureDisplay(view); - } + unconfigureDisplay(view); cancelAodSendFingerUpAction(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index a5bd89a15e5a..2d54f7ac8e7d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -46,11 +46,11 @@ import androidx.annotation.VisibleForTesting import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams +import com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor import com.android.systemui.dump.DumpManager -import com.android.systemui.flags.FeatureFlags import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -96,7 +96,6 @@ class UdfpsControllerOverlay @JvmOverloads constructor( private val controllerCallback: IUdfpsOverlayControllerCallback, private val onTouch: (View, MotionEvent, Boolean) -> Boolean, private val activityLaunchAnimator: ActivityLaunchAnimator, - private val featureFlags: FeatureFlags, private val primaryBouncerInteractor: PrimaryBouncerInteractor, private val alternateBouncerInteractor: AlternateBouncerInteractor, private val isDebuggable: Boolean = Build.IS_DEBUGGABLE, @@ -104,9 +103,22 @@ class UdfpsControllerOverlay @JvmOverloads constructor( private val transitionInteractor: KeyguardTransitionInteractor, private val selectedUserInteractor: SelectedUserInteractor, ) { - /** The view, when [isShowing], or null. */ - var overlayView: UdfpsView? = null + private var overlayViewLegacy: UdfpsView? = null private set + private var overlayTouchView: UdfpsTouchOverlay? = null + + /** + * Get the current UDFPS overlay touch view which is a different View depending on whether + * the DeviceEntryUdfpsRefactor flag is enabled or not. + * @return The view, when [isShowing], else null + */ + fun getTouchOverlay(): View? { + return if (DeviceEntryUdfpsRefactor.isEnabled) { + overlayTouchView + } else { + overlayViewLegacy + } + } private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams() private var sensorBounds: Rect = Rect() @@ -132,15 +144,15 @@ class UdfpsControllerOverlay @JvmOverloads constructor( /** If the overlay is currently showing. */ val isShowing: Boolean - get() = overlayView != null + get() = getTouchOverlay() != null /** Opposite of [isShowing]. */ val isHiding: Boolean - get() = overlayView == null + get() = getTouchOverlay() == null /** The animation controller if the overlay [isShowing]. */ val animationViewController: UdfpsAnimationViewController<*>? - get() = overlayView?.animationViewController + get() = overlayViewLegacy?.animationViewController private var touchExplorationEnabled = false @@ -158,28 +170,48 @@ class UdfpsControllerOverlay @JvmOverloads constructor( /** Show the overlay or return false and do nothing if it is already showing. */ @SuppressLint("ClickableViewAccessibility") fun show(controller: UdfpsController, params: UdfpsOverlayParams): Boolean { - if (overlayView == null) { + if (getTouchOverlay() == null) { overlayParams = params sensorBounds = Rect(params.sensorBounds) try { - overlayView = (inflater.inflate( - R.layout.udfps_view, null, false - ) as UdfpsView).apply { - overlayParams = params - setUdfpsDisplayModeProvider(udfpsDisplayModeProvider) - val animation = inflateUdfpsAnimation(this, controller) - if (animation != null) { - animation.init() - animationViewController = animation - } - // This view overlaps the sensor area - // prevent it from being selectable during a11y - if (requestReason.isImportantForAccessibility()) { - importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO + if (DeviceEntryUdfpsRefactor.isEnabled) { + overlayTouchView = (inflater.inflate( + R.layout.udfps_touch_overlay, null, false + ) as UdfpsTouchOverlay).apply { + // This view overlaps the sensor area + // prevent it from being selectable during a11y + if (requestReason.isImportantForAccessibility()) { + importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO + } + windowManager.addView(this, coreLayoutParams.updateDimensions(null)) } + // TODO (b/305234447): Bind view model to UdfpsTouchOverlay here to control + // the visibility (sometimes, even if UDFPS is running, the UDFPS UI can be + // obscured and we don't want to accept touches. ie: for enrollment don't accept + // touches when the shade is expanded and for keyguard: don't accept touches + // depending on the keyguard & shade state + } else { + overlayViewLegacy = (inflater.inflate( + R.layout.udfps_view, null, false + ) as UdfpsView).apply { + overlayParams = params + setUdfpsDisplayModeProvider(udfpsDisplayModeProvider) + val animation = inflateUdfpsAnimation(this, controller) + if (animation != null) { + animation.init() + animationViewController = animation + } + // This view overlaps the sensor area + // prevent it from being selectable during a11y + if (requestReason.isImportantForAccessibility()) { + importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO + } - windowManager.addView(this, coreLayoutParams.updateDimensions(animation)) - sensorRect = sensorBounds + windowManager.addView(this, coreLayoutParams.updateDimensions(animation)) + sensorRect = sensorBounds + } + } + getTouchOverlay()?.apply { touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled overlayTouchListener = TouchExplorationStateChangeListener { if (accessibilityManager.isTouchExplorationEnabled) { @@ -193,7 +225,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor( } } accessibilityManager.addTouchExplorationStateChangeListener( - overlayTouchListener!! + overlayTouchListener!! ) overlayTouchListener?.onTouchExplorationStateChanged(true) } @@ -211,6 +243,8 @@ class UdfpsControllerOverlay @JvmOverloads constructor( view: UdfpsView, controller: UdfpsController ): UdfpsAnimationViewController<*>? { + DeviceEntryUdfpsRefactor.assertInLegacyMode() + val isEnrollment = when (requestReason) { REASON_ENROLL_FIND_SENSOR, REASON_ENROLL_ENROLLING -> true else -> false @@ -237,39 +271,27 @@ class UdfpsControllerOverlay @JvmOverloads constructor( ) } REASON_AUTH_KEYGUARD -> { - if (DeviceEntryUdfpsRefactor.isEnabled) { - // note: empty controller, currently shows no visual affordance - // instead SysUI will show the fingerprint icon in its DeviceEntryIconView - UdfpsBpViewController( - view.addUdfpsView(R.layout.udfps_bp_view), - statusBarStateController, - primaryBouncerInteractor, - dialogManager, - dumpManager - ) - } else { - UdfpsKeyguardViewControllerLegacy( - view.addUdfpsView(R.layout.udfps_keyguard_view_legacy) { - updateSensorLocation(sensorBounds) - }, - statusBarStateController, - statusBarKeyguardViewManager, - keyguardUpdateMonitor, - dumpManager, - transitionController, - configurationController, - keyguardStateController, - unlockedScreenOffAnimationController, - dialogManager, - controller, - activityLaunchAnimator, - primaryBouncerInteractor, - alternateBouncerInteractor, - udfpsKeyguardAccessibilityDelegate, - selectedUserInteractor, - transitionInteractor, - ) - } + UdfpsKeyguardViewControllerLegacy( + view.addUdfpsView(R.layout.udfps_keyguard_view_legacy) { + updateSensorLocation(sensorBounds) + }, + statusBarStateController, + statusBarKeyguardViewManager, + keyguardUpdateMonitor, + dumpManager, + transitionController, + configurationController, + keyguardStateController, + unlockedScreenOffAnimationController, + dialogManager, + controller, + activityLaunchAnimator, + primaryBouncerInteractor, + alternateBouncerInteractor, + udfpsKeyguardAccessibilityDelegate, + selectedUserInteractor, + transitionInteractor, + ) } REASON_AUTH_BP -> { // note: empty controller, currently shows no visual affordance @@ -302,19 +324,26 @@ class UdfpsControllerOverlay @JvmOverloads constructor( fun hide(): Boolean { val wasShowing = isShowing - overlayView?.apply { + overlayViewLegacy?.apply { if (isDisplayConfigured) { unconfigureDisplay() } + animationViewController = null + } + if (DeviceEntryUdfpsRefactor.isEnabled) { + udfpsDisplayModeProvider.disable(null) + } + getTouchOverlay()?.apply { windowManager.removeView(this) setOnTouchListener(null) setOnHoverListener(null) - animationViewController = null overlayTouchListener?.let { accessibilityManager.removeTouchExplorationStateChangeListener(it) } } - overlayView = null + + overlayViewLegacy = null + overlayTouchView = null overlayTouchListener = null return wasShowing @@ -392,7 +421,14 @@ class UdfpsControllerOverlay @JvmOverloads constructor( } private fun shouldRotate(animation: UdfpsAnimationViewController<*>?): Boolean { - if (animation !is UdfpsKeyguardViewControllerAdapter) { + val keyguardNotShowing = + if (DeviceEntryUdfpsRefactor.isEnabled) { + !keyguardStateController.isShowing + } else { + animation !is UdfpsKeyguardViewControllerAdapter + } + + if (keyguardNotShowing) { // always rotate view if we're not on the keyguard return true } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt new file mode 100644 index 000000000000..2484c339a1d4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt @@ -0,0 +1,26 @@ +/* + * 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.view + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout + +/** + * A translucent (not visible to the user) view that receives touches to send to FingerprintManager + * for fingerprint authentication. + */ +class UdfpsTouchOverlay(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index fd7f641c2e61..e630fd4e3c54 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -27,6 +27,7 @@ import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.communal.widgets.EditWidgetsActivityStarter import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.smartspace.data.repository.SmartspaceRepository import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -46,6 +47,7 @@ constructor( private val widgetRepository: CommunalWidgetRepository, mediaRepository: CommunalMediaRepository, smartspaceRepository: SmartspaceRepository, + keyguardInteractor: KeyguardInteractor, private val appWidgetHost: AppWidgetHost, private val editWidgetsActivityStarter: EditWidgetsActivityStarter ) { @@ -67,6 +69,8 @@ constructor( val isCommunalShowing: Flow<Boolean> = communalRepository.desiredScene.map { it == CommunalSceneKey.Communal } + val isKeyguardVisible: Flow<Boolean> = keyguardInteractor.isKeyguardVisible + /** Callback received whenever the [SceneTransitionLayout] finishes a scene transition. */ fun onSceneChanged(newScene: CommunalSceneKey) { communalRepository.setDesiredScene(newScene) 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 b4ab5fbfcc1a..4d8e893cb747 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 @@ -28,6 +28,8 @@ abstract class BaseCommunalViewModel( private val communalInteractor: CommunalInteractor, val mediaHost: MediaHost, ) { + val isKeyguardVisible: Flow<Boolean> = communalInteractor.isKeyguardVisible + val currentScene: StateFlow<CommunalSceneKey> = communalInteractor.desiredScene fun onSceneChanged(scene: CommunalSceneKey) { 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 eaf2d5741e23..11bde6bd7af0 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 @@ -39,7 +39,6 @@ constructor( tutorialInteractor: CommunalTutorialInteractor, @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, ) : BaseCommunalViewModel(communalInteractor, mediaHost) { - @OptIn(ExperimentalCoroutinesApi::class) override val communalContent: Flow<List<CommunalContentModel>> = tutorialInteractor.isTutorialAvailable.flatMapLatest { isTutorialMode -> diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 7d541070f146..98fda3eb01c5 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -464,12 +464,6 @@ object Flags { val WALLPAPER_MULTI_CROP = sysPropBooleanFlag("persist.wm.debug.wallpaper_multi_crop", default = false) - // TODO(b/290220798): Tracking Bug - @Keep - @JvmField - val ENABLE_PIP2_IMPLEMENTATION = - sysPropBooleanFlag("persist.wm.debug.enable_pip2_implementation", default = false) - // 1200 - predictive back @Keep @JvmField diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt index f2db088ced83..44232ffb3ad7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt @@ -19,12 +19,18 @@ package com.android.systemui.media.controls.util import android.app.StatusBarManager import android.os.UserHandle import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags +import com.android.systemui.scene.shared.flag.SceneContainerFlags import javax.inject.Inject @SysUISingleton -class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) { +class MediaFlags +@Inject +constructor( + private val featureFlags: FeatureFlagsClassic, + private val sceneContainerFlags: SceneContainerFlags +) { /** * Check whether media control actions should be based on PlaybackState instead of notification */ @@ -48,4 +54,8 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) { /** Check whether we allow remote media to generate resume controls */ fun isRemoteResumeAllowed() = featureFlags.isEnabled(Flags.MEDIA_REMOTE_RESUME) + + /** Check whether to use flexiglass layout */ + fun isFlexiglassEnabled() = + sceneContainerFlags.isEnabled() && MediaInSceneContainerFlag.isEnabled } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaInSceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaInSceneContainerFlag.kt new file mode 100644 index 000000000000..898298c58b32 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaInSceneContainerFlag.kt @@ -0,0 +1,48 @@ +/* + * 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.media.controls.util + +import com.android.systemui.Flags +import com.android.systemui.flags.RefactorFlagUtils + +/** Helper for reading or using the media_in_scene_container flag state. */ +@Suppress("NOTHING_TO_INLINE") +object MediaInSceneContainerFlag { + /** The aconfig flag name */ + const val FLAG_NAME = Flags.FLAG_MEDIA_IN_SCENE_CONTAINER + + /** Is the flag enabled? */ + @JvmStatic + inline val isEnabled + get() = Flags.mediaInSceneContainer() + + /** + * Called to ensure code is only run when the flag is enabled. This protects users from the + * unintended behaviors caused by accidentally running new logic, while also crashing on an eng + * build to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun isUnexpectedlyInLegacyMode() = + RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception if + * the flag is enabled to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt index 346d5c30a63e..e5e1e8445e94 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt @@ -17,7 +17,6 @@ package com.android.systemui.qs.ui.viewmodel import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.SceneKey @@ -33,14 +32,10 @@ import kotlinx.coroutines.flow.map class QuickSettingsSceneViewModel @Inject constructor( - private val deviceEntryInteractor: DeviceEntryInteractor, val shadeHeaderViewModel: ShadeHeaderViewModel, val qsSceneAdapter: QSSceneAdapter, val notifications: NotificationsPlaceholderViewModel, ) { - /** Notifies that some content in quick settings was clicked. */ - fun onContentClicked() = deviceEntryInteractor.attemptDeviceEntry() - val destinationScenes = qsSceneAdapter.isCustomizing.map { customizing -> if (customizing) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 11c65e542bcd..6cb079a22e7d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -2221,8 +2221,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mMenuRow != null) { mMenuRow.resetMenu(); } - mTranslateAnim = null; } + mTranslateAnim = null; } }); mTranslateAnim = translateAnim; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 283a5930f930..61a79b716b0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -3751,6 +3751,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } protected boolean isInsideQsHeader(MotionEvent ev) { + if (mQsHeader == null) { + Log.wtf(TAG, "qsHeader is null while NSSL is handling a touch"); + return false; + } + mQsHeader.getBoundsOnScreen(mQsHeaderBound); /** * One-handed mode defines a feature FEATURE_ONE_HANDED of DisplayArea {@link DisplayArea} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java index 146715d26b7d..13fb42ce8c3e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java @@ -35,6 +35,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.power.data.repository.FakePowerRepository; import com.android.systemui.power.domain.interactor.PowerInteractorFactory; +import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; @@ -70,6 +71,7 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { @Mock protected KeyguardClockSwitch mKeyguardClockSwitch; @Mock protected FrameLayout mMediaHostContainer; + @Mock protected KeyguardStatusAreaView mKeyguardStatusAreaView; @Before public void setup() { @@ -109,6 +111,8 @@ public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase { when(mKeyguardStatusView.getViewTreeObserver()).thenReturn(mViewTreeObserver); when(mKeyguardClockSwitchController.getView()).thenReturn(mKeyguardClockSwitch); when(mKeyguardTransitionInteractor.getGoneToAodTransition()).thenReturn(emptyFlow()); + when(mKeyguardStatusView.findViewById(R.id.keyguard_status_area)) + .thenReturn(mKeyguardStatusAreaView); } protected void givenViewAttached() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java index 948942fbce3a..9c3288b9f93d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java @@ -16,6 +16,8 @@ package com.android.keyguard; +import static junit.framework.Assert.assertEquals; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; @@ -27,6 +29,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.animation.AnimatorTestRule; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -40,6 +43,7 @@ import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -51,6 +55,9 @@ import java.lang.reflect.Field; @RunWith(AndroidTestingRunner.class) public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControllerBaseTest { + @Rule + public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(); + @Test public void dozeTimeTick_updatesSlice() { mController.dozeTimeTick(); @@ -230,4 +237,34 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll throw new RuntimeException(e); } } + + @Test + public void statusAreaHeightChange_animatesHeightOutputChange() { + // Init & Capture Layout Listener + mController.onInit(); + mController.onViewAttached(); + + when(mDozeParameters.getAlwaysOn()).thenReturn(true); + ArgumentCaptor<View.OnLayoutChangeListener> captor = + ArgumentCaptor.forClass(View.OnLayoutChangeListener.class); + verify(mKeyguardStatusAreaView).addOnLayoutChangeListener(captor.capture()); + View.OnLayoutChangeListener listener = captor.getValue(); + + // Setup and validate initial height + when(mKeyguardStatusView.getHeight()).thenReturn(200); + when(mKeyguardClockSwitchController.getNotificationIconAreaHeight()).thenReturn(10); + assertEquals(190, mController.getLockscreenHeight()); + + // Trigger Change and validate value unchanged immediately + when(mKeyguardStatusAreaView.getHeight()).thenReturn(100); + when(mKeyguardStatusView.getHeight()).thenReturn(300); // Include child height + listener.onLayoutChange(mKeyguardStatusAreaView, + /* new layout */ 100, 300, 200, 400, + /* old layout */ 100, 300, 200, 300); + assertEquals(190, mController.getLockscreenHeight()); + + // Complete animation, validate height increased + mAnimatorTestRule.advanceTimeBy(200); + assertEquals(290, mController.getLockscreenHeight()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt index 2b51ac5e3187..a7e7dd074a33 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.animation import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.core.animation.doOnEnd -import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.util.doOnEnd @@ -31,7 +30,6 @@ import org.junit.runner.RunWith @RunWith(AndroidTestingRunner::class) @SmallTest @RunWithLooper -@FlakyTest(bugId = 302149604) class AnimatorTestRuleOrderTest : SysuiTestCase() { @get:Rule val animatorTestRule = AnimatorTestRule() diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 11c5d3bb27b3..602f3dc29491 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -475,6 +475,22 @@ public class AuthControllerTest extends SysuiTestCase { } @Test + public void testOnAuthenticationFailedInvoked_whenBiometricReEnrollRequired() { + showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); + final int modality = BiometricAuthenticator.TYPE_FACE; + mAuthController.onBiometricError(modality, + BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL, + 0 /* vendorCode */); + + verify(mDialog1).onAuthenticationFailed(mModalityCaptor.capture(), + mMessageCaptor.capture()); + + assertThat(mModalityCaptor.getValue()).isEqualTo(modality); + assertThat(mMessageCaptor.getValue()).isEqualTo(mContext.getString( + R.string.face_recalibrate_notification_content)); + } + + @Test public void testOnAuthenticationFailedInvoked_coex_whenFaceAuthRejected_withPaused() { testOnAuthenticationFailedInvoked_coex_whenFaceAuthRejected( BiometricConstants.BIOMETRIC_PAUSED_REJECTED); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index 5f0d4d428322..f5b6f14a627c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -36,13 +36,13 @@ import android.view.accessibility.AccessibilityManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams 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.flags.FeatureFlags import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R @@ -107,7 +107,6 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Mock private lateinit var udfpsView: UdfpsView @Mock private lateinit var mUdfpsKeyguardViewLegacy: UdfpsKeyguardViewLegacy @Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator - @Mock private lateinit var featureFlags: FeatureFlags @Mock private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor @@ -123,47 +122,52 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Before fun setup() { whenever(inflater.inflate(R.layout.udfps_view, null, false)) - .thenReturn(udfpsView) + .thenReturn(udfpsView) whenever(inflater.inflate(R.layout.udfps_bp_view, null)) - .thenReturn(mock(UdfpsBpView::class.java)) + .thenReturn(mock(UdfpsBpView::class.java)) whenever(inflater.inflate(R.layout.udfps_keyguard_view_legacy, null)) - .thenReturn(mUdfpsKeyguardViewLegacy) + .thenReturn(mUdfpsKeyguardViewLegacy) whenever(inflater.inflate(R.layout.udfps_fpm_empty_view, null)) - .thenReturn(mock(UdfpsFpmEmptyView::class.java)) + .thenReturn(mock(UdfpsFpmEmptyView::class.java)) } private fun withReason( - @ShowReason reason: Int, - isDebuggable: Boolean = false, - block: () -> Unit + @ShowReason reason: Int, + isDebuggable: Boolean = false, + enableDeviceEntryUdfpsRefactor: Boolean = false, + block: () -> Unit, ) { + if (enableDeviceEntryUdfpsRefactor) { + mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + } else { + mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + } controllerOverlay = UdfpsControllerOverlay( - context, - inflater, - windowManager, - accessibilityManager, - statusBarStateController, - statusBarKeyguardViewManager, - keyguardUpdateMonitor, - dialogManager, - dumpManager, - transitionController, - configurationController, - keyguardStateController, - unlockedScreenOffAnimationController, - udfpsDisplayMode, - REQUEST_ID, - reason, - controllerCallback, - onTouch, - activityLaunchAnimator, - featureFlags, - primaryBouncerInteractor, - alternateBouncerInteractor, - isDebuggable, - udfpsKeyguardAccessibilityDelegate, - keyguardTransitionInteractor, - mSelectedUserInteractor, + context, + inflater, + windowManager, + accessibilityManager, + statusBarStateController, + statusBarKeyguardViewManager, + keyguardUpdateMonitor, + dialogManager, + dumpManager, + transitionController, + configurationController, + keyguardStateController, + unlockedScreenOffAnimationController, + udfpsDisplayMode, + REQUEST_ID, + reason, + controllerCallback, + onTouch, + activityLaunchAnimator, + primaryBouncerInteractor, + alternateBouncerInteractor, + isDebuggable, + udfpsKeyguardAccessibilityDelegate, + keyguardTransitionInteractor, + mSelectedUserInteractor, ) block() } @@ -185,12 +189,12 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { val sensorBounds = Rect(0, 0, SENSOR_WIDTH, SENSOR_HEIGHT) val overlayBounds = Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT) overlayParams = UdfpsOverlayParams( - sensorBounds, - overlayBounds, - DISPLAY_WIDTH, - DISPLAY_HEIGHT, - scaleFactor = 1f, - rotation + sensorBounds, + overlayBounds, + DISPLAY_WIDTH, + DISPLAY_HEIGHT, + scaleFactor = 1f, + rotation ) block() } @@ -200,8 +204,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { withReason(REASON_AUTH_BP) { controllerOverlay.show(udfpsController, overlayParams) verify(windowManager).addView( - eq(controllerOverlay.overlayView), - layoutParamsCaptor.capture() + eq(controllerOverlay.getTouchOverlay()), + layoutParamsCaptor.capture() ) // ROTATION_0 is the native orientation. Sensor should stay in the top left corner. @@ -218,8 +222,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { withReason(REASON_AUTH_BP) { controllerOverlay.show(udfpsController, overlayParams) verify(windowManager).addView( - eq(controllerOverlay.overlayView), - layoutParamsCaptor.capture() + eq(controllerOverlay.getTouchOverlay()), + layoutParamsCaptor.capture() ) // ROTATION_180 is not supported. Sensor should stay in the top left corner. @@ -236,8 +240,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { withReason(REASON_AUTH_BP) { controllerOverlay.show(udfpsController, overlayParams) verify(windowManager).addView( - eq(controllerOverlay.overlayView), - layoutParamsCaptor.capture() + eq(controllerOverlay.getTouchOverlay()), + layoutParamsCaptor.capture() ) // Sensor should be in the bottom left corner in ROTATION_90. @@ -254,8 +258,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { withReason(REASON_AUTH_BP) { controllerOverlay.show(udfpsController, overlayParams) verify(windowManager).addView( - eq(controllerOverlay.overlayView), - layoutParamsCaptor.capture() + eq(controllerOverlay.getTouchOverlay()), + layoutParamsCaptor.capture() ) // Sensor should be in the top right corner in ROTATION_270. @@ -270,7 +274,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { private fun showUdfpsOverlay() { val didShow = controllerOverlay.show(udfpsController, overlayParams) - verify(windowManager).addView(eq(controllerOverlay.overlayView), any()) + verify(windowManager).addView(eq(controllerOverlay.getTouchOverlay()), any()) verify(udfpsView).setUdfpsDisplayModeProvider(eq(udfpsDisplayMode)) verify(udfpsView).animationViewController = any() verify(udfpsView).addView(any()) @@ -278,7 +282,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { assertThat(didShow).isTrue() assertThat(controllerOverlay.isShowing).isTrue() assertThat(controllerOverlay.isHiding).isFalse() - assertThat(controllerOverlay.overlayView).isNotNull() + assertThat(controllerOverlay.getTouchOverlay()).isNotNull() } @Test @@ -295,14 +299,14 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { private fun hideUdfpsOverlay() { val didShow = controllerOverlay.show(udfpsController, overlayParams) - val view = controllerOverlay.overlayView + val view = controllerOverlay.getTouchOverlay() val didHide = controllerOverlay.hide() verify(windowManager).removeView(eq(view)) assertThat(didShow).isTrue() assertThat(didHide).isTrue() - assertThat(controllerOverlay.overlayView).isNull() + assertThat(controllerOverlay.getTouchOverlay()).isNull() assertThat(controllerOverlay.animationViewController).isNull() assertThat(controllerOverlay.isShowing).isFalse() assertThat(controllerOverlay.isHiding).isTrue() @@ -348,8 +352,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { controllerOverlay.show(udfpsController, overlayParams) verify(windowManager).addView( - eq(controllerOverlay.overlayView), - layoutParamsCaptor.capture() + eq(controllerOverlay.getTouchOverlay()), + layoutParamsCaptor.capture() ) // Layout params should use sensor bounds diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index c8c400de5740..e2cab29c473c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -73,6 +73,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.InstanceIdSequence; import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; @@ -286,6 +287,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // Create a fake background executor. mBiometricExecutor = new FakeExecutor(new FakeSystemClock()); + mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR); initUdfpsController(mOpticalProps); } @@ -304,7 +306,6 @@ public class UdfpsControllerTest extends SysuiTestCase { mStatusBarKeyguardViewManager, mDumpManager, mKeyguardUpdateMonitor, - mFeatureFlags, mFalsingManager, mPowerManager, mAccessibilityManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt index 5c325ae67369..42e27ba12f42 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt @@ -19,7 +19,6 @@ package com.android.systemui.qs.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags @@ -39,14 +38,11 @@ import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsPro import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi -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 QuickSettingsSceneViewModelTest : SysuiTestCase() { @@ -90,15 +86,8 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { broadcastDispatcher = fakeBroadcastDispatcher, ) - val authenticationInteractor = utils.authenticationInteractor() - underTest = QuickSettingsSceneViewModel( - deviceEntryInteractor = - utils.deviceEntryInteractor( - authenticationInteractor = authenticationInteractor, - sceneInteractor = sceneInteractor, - ), shadeHeaderViewModel = shadeHeaderViewModel, qsSceneAdapter = qsFlexiglassAdapter, notifications = utils.notificationsPlaceholderViewModel(), @@ -106,32 +95,6 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { } @Test - fun onContentClicked_deviceUnlocked_switchesToGone() = - testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.desiredScene) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) - utils.deviceEntryRepository.setUnlocked(true) - runCurrent() - - underTest.onContentClicked() - - assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone)) - } - - @Test - fun onContentClicked_deviceLockedSecurely_switchesToBouncer() = - testScope.runTest { - val currentScene by collectLastValue(sceneInteractor.desiredScene) - utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) - utils.deviceEntryRepository.setUnlocked(false) - runCurrent() - - underTest.onContentClicked() - - assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer)) - } - - @Test fun destinationsNotCustomizing() = testScope.runTest { val destinations by collectLastValue(underTest.destinationScenes) diff --git a/packages/SystemUI/tests/utils/src/android/app/ActivityManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/app/ActivityManagerKosmos.kt new file mode 100644 index 000000000000..f9c920a89e16 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/android/app/ActivityManagerKosmos.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 android.app + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +val Kosmos.activityManager by Kosmos.Fixture { mock<ActivityManager>() } diff --git a/packages/SystemUI/tests/utils/src/android/app/admin/DevicePolicyManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/app/admin/DevicePolicyManagerKosmos.kt new file mode 100644 index 000000000000..b284ac0ec7e9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/android/app/admin/DevicePolicyManagerKosmos.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 android.app.admin + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +val Kosmos.devicePolicyManager by Kosmos.Fixture { mock<DevicePolicyManager>() } diff --git a/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt b/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt new file mode 100644 index 000000000000..f96c5080bb95 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.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 android.content + +import com.android.systemui.SysuiTestableContext +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testCase + +val Kosmos.testableContext: SysuiTestableContext by Kosmos.Fixture { testCase.context } +var Kosmos.applicationContext: Context by Kosmos.Fixture { testableContext } diff --git a/packages/SystemUI/tests/utils/src/android/content/res/ResourcesKosmos.kt b/packages/SystemUI/tests/utils/src/android/content/res/ResourcesKosmos.kt new file mode 100644 index 000000000000..56867640d03d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/android/content/res/ResourcesKosmos.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 android.content.res + +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos + +var Kosmos.mainResources: Resources by Kosmos.Fixture { applicationContext.resources } diff --git a/packages/SystemUI/tests/utils/src/android/os/UserManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/os/UserManagerKosmos.kt new file mode 100644 index 000000000000..c936b914f44e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/android/os/UserManagerKosmos.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 android.os + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.userManager by Kosmos.Fixture { mock<UserManager>() } diff --git a/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt new file mode 100644 index 000000000000..34c0a7915523 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.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 android.view + +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos + +val Kosmos.layoutInflater: LayoutInflater by + Kosmos.Fixture { LayoutInflater.from(applicationContext) } diff --git a/packages/SystemUI/tests/utils/src/com/android/internal/logging/UiEventLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/internal/logging/UiEventLoggerKosmos.kt new file mode 100644 index 000000000000..9059da2259b1 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/internal/logging/UiEventLoggerKosmos.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.internal.logging + +import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.systemui.kosmos.Kosmos + +var Kosmos.uiEventLogger: UiEventLogger by Kosmos.Fixture { uiEventLoggerFake } +val Kosmos.uiEventLoggerFake by Kosmos.Fixture { UiEventLoggerFake() } diff --git a/packages/SystemUI/tests/utils/src/com/android/keyguard/KeyguardSecurityModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/keyguard/KeyguardSecurityModelKosmos.kt new file mode 100644 index 000000000000..fadcecc07190 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/keyguard/KeyguardSecurityModelKosmos.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 + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.keyguardSecurityModel by Kosmos.Fixture { mock<KeyguardSecurityModel>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/keyguard/KeyguardUpdateMonitorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/keyguard/KeyguardUpdateMonitorKosmos.kt new file mode 100644 index 000000000000..b32cbe6da0ec --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/keyguard/KeyguardUpdateMonitorKosmos.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 + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +val Kosmos.keyguardUpdateMonitor by Kosmos.Fixture { mock<KeyguardUpdateMonitor>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/GuestResetOrExitSessionReceiverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/GuestResetOrExitSessionReceiverKosmos.kt new file mode 100644 index 000000000000..4c4cfd541a1f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/GuestResetOrExitSessionReceiverKosmos.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 + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +val Kosmos.guestResetOrExitSessionReceiver by + Kosmos.Fixture { mock<GuestResetOrExitSessionReceiver>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/GuestResumeSessionReceiverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/GuestResumeSessionReceiverKosmos.kt new file mode 100644 index 000000000000..a9855ffda8b8 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/GuestResumeSessionReceiverKosmos.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 + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +val Kosmos.guestResumeSessionReceiver by Kosmos.Fixture { mock<GuestResumeSessionReceiver>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryKosmos.kt new file mode 100644 index 000000000000..ea93e949c83c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryKosmos.kt @@ -0,0 +1,26 @@ +/* + * 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.authentication.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import kotlinx.coroutines.test.currentTime + +var Kosmos.authenticationRepository: AuthenticationRepository by + Kosmos.Fixture { fakeAuthenticationRepository } +val Kosmos.fakeAuthenticationRepository by + Kosmos.Fixture { FakeAuthenticationRepository { testScope.currentTime } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt new file mode 100644 index 000000000000..060ca4c7e912 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.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. + */ + +package com.android.systemui.authentication.domain.interactor + +import com.android.systemui.authentication.data.repository.authenticationRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.user.data.repository.userRepository +import com.android.systemui.util.time.fakeSystemClock + +val Kosmos.authenticationInteractor by + Kosmos.Fixture { + AuthenticationInteractor( + applicationScope = applicationCoroutineScope, + repository = authenticationRepository, + backgroundDispatcher = testDispatcher, + userRepository = userRepository, + clock = fakeSystemClock, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryKosmos.kt new file mode 100644 index 000000000000..2a870749644a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepositoryKosmos.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.bouncer.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.keyguardBouncerRepository: KeyguardBouncerRepository by + Kosmos.Fixture { fakeKeyguardBouncerRepository } +val Kosmos.fakeKeyguardBouncerRepository by Kosmos.Fixture { FakeKeyguardBouncerRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.kt new file mode 100644 index 000000000000..3a72d11cdc18 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingCollectorKosmos.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.classifier + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.falsingCollector by Kosmos.Fixture { FalsingCollectorFake() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/ConfigurationStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/ConfigurationStateKosmos.kt new file mode 100644 index 000000000000..86a8ae5f9cf4 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/ConfigurationStateKosmos.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.common.ui + +import android.content.applicationContext +import android.view.layoutInflater +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.policy.configurationController + +val Kosmos.configurationState: ConfigurationState by + Kosmos.Fixture { + ConfigurationState(configurationController, applicationContext, layoutInflater) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryKosmos.kt new file mode 100644 index 000000000000..77b8bd4ff2de --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryKosmos.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.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.configurationRepository: ConfigurationRepository by + Kosmos.Fixture { fakeConfigurationRepository } +val Kosmos.fakeConfigurationRepository by Kosmos.Fixture { FakeConfigurationRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt index b27926c8ba50..faacce64b2e4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt @@ -65,6 +65,7 @@ object CommunalInteractorFactory { widgetRepository, mediaRepository, smartspaceRepository, + withDeps.keyguardInteractor, appWidgetHost, editWidgetsActivityStarter, ), diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryKosmos.kt new file mode 100644 index 000000000000..3da0681dc45f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/repository/DeviceEntryRepositoryKosmos.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.deviceEntryRepository: DeviceEntryRepository by + Kosmos.Fixture { fakeDeviceEntryRepository } +val Kosmos.fakeDeviceEntryRepository by Kosmos.Fixture { FakeDeviceEntryRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt new file mode 100644 index 000000000000..b600b50b8d2d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.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.systemui.authentication.domain.interactor.authenticationInteractor +import com.android.systemui.deviceentry.data.repository.deviceEntryRepository +import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository +import com.android.systemui.keyguard.data.repository.trustRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.flag.sceneContainerFlags +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.deviceEntryInteractor by + Kosmos.Fixture { + DeviceEntryInteractor( + applicationScope = applicationCoroutineScope, + repository = deviceEntryRepository, + authenticationInteractor = authenticationInteractor, + sceneInteractor = sceneInteractor, + deviceEntryFaceAuthRepository = deviceEntryFaceAuthRepository, + trustRepository = trustRepository, + flags = sceneContainerFlags, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt index a78076338c79..e6b7f62c7d5f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt @@ -18,4 +18,4 @@ package com.android.systemui.flags import com.android.systemui.kosmos.Kosmos -val Kosmos.featureFlags by Kosmos.Fixture { FakeFeatureFlagsClassic() } +val Kosmos.featureFlagsClassic by Kosmos.Fixture { FakeFeatureFlagsClassic() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryKosmos.kt new file mode 100644 index 000000000000..3d729675f7ab --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryKosmos.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.keyguard.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.deviceEntryFaceAuthRepository: DeviceEntryFaceAuthRepository by + Kosmos.Fixture { fakeDeviceEntryFaceAuthRepository } +val Kosmos.fakeDeviceEntryFaceAuthRepository by + Kosmos.Fixture { FakeDeviceEntryFaceAuthRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepositoryKosmos.kt new file mode 100644 index 000000000000..b0e4ba06d7b2 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/InWindowLauncherUnlockAnimationRepositoryKosmos.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.keyguard.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.inWindowLauncherUnlockAnimationRepository by + Kosmos.Fixture { InWindowLauncherUnlockAnimationRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryKosmos.kt new file mode 100644 index 000000000000..453fef5ddca9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryKosmos.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.keyguard.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.keyguardRepository: KeyguardRepository by Kosmos.Fixture { fakeKeyguardRepository } +val Kosmos.fakeKeyguardRepository by Kosmos.Fixture { FakeKeyguardRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryKosmos.kt new file mode 100644 index 000000000000..c900ac9771a7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardSurfaceBehindRepositoryKosmos.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.keyguard.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.keyguardSurfaceBehindRepository: KeyguardSurfaceBehindRepository by + Kosmos.Fixture { fakeKeyguardSurfaceBehindRepository } +val Kosmos.fakeKeyguardSurfaceBehindRepository by + Kosmos.Fixture { FakeKeyguardSurfaceBehindRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt new file mode 100644 index 000000000000..008f79a377e0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.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 + +var Kosmos.keyguardTransitionRepository: KeyguardTransitionRepository by + Kosmos.Fixture { fakeKeyguardTransitionRepository } +val Kosmos.fakeKeyguardTransitionRepository by Kosmos.Fixture { FakeKeyguardTransitionRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/TrustRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/TrustRepositoryKosmos.kt new file mode 100644 index 000000000000..ca87acf88d01 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/TrustRepositoryKosmos.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.keyguard.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.trustRepository: TrustRepository by Kosmos.Fixture { fakeTrustRepository } +val Kosmos.fakeTrustRepository by Kosmos.Fixture { FakeTrustRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt new file mode 100644 index 000000000000..b03d0b822161 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt @@ -0,0 +1,40 @@ +/* + * 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.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.shade.data.repository.shadeRepository +import dagger.Lazy + +val Kosmos.fromLockscreenTransitionInteractor by + Kosmos.Fixture { + FromLockscreenTransitionInteractor( + transitionRepository = keyguardTransitionRepository, + transitionInteractor = keyguardTransitionInteractor, + scope = applicationCoroutineScope, + keyguardInteractor = keyguardInteractor, + flags = featureFlagsClassic, + shadeRepository = shadeRepository, + powerInteractor = powerInteractor, + inWindowLauncherUnlockAnimationInteractor = + Lazy { inWindowLauncherUnlockAnimationInteractor }, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt new file mode 100644 index 000000000000..ade3e1a82297 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt @@ -0,0 +1,39 @@ +/* + * 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.keyguard.keyguardSecurityModel +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.user.domain.interactor.selectedUserInteractor + +val Kosmos.fromPrimaryBouncerTransitionInteractor by + Kosmos.Fixture { + FromPrimaryBouncerTransitionInteractor( + transitionRepository = keyguardTransitionRepository, + transitionInteractor = keyguardTransitionInteractor, + scope = applicationCoroutineScope, + keyguardInteractor = keyguardInteractor, + flags = featureFlagsClassic, + keyguardSecurityModel = keyguardSecurityModel, + selectedUserInteractor = selectedUserInteractor, + powerInteractor = powerInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorKosmos.kt new file mode 100644 index 000000000000..dbbb203b0570 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/InWindowLauncherUnlockAnimationInteractorKosmos.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. + */ + +package com.android.systemui.keyguard.domain.interactor + +import com.android.systemui.keyguard.data.repository.inWindowLauncherUnlockAnimationRepository +import com.android.systemui.keyguard.data.repository.keyguardSurfaceBehindRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.shared.system.activityManagerWrapper +import dagger.Lazy + +val Kosmos.inWindowLauncherUnlockAnimationInteractor by + Kosmos.Fixture { + InWindowLauncherUnlockAnimationInteractor( + repository = inWindowLauncherUnlockAnimationRepository, + scope = applicationCoroutineScope, + transitionInteractor = keyguardTransitionInteractor, + surfaceBehindRepository = Lazy { keyguardSurfaceBehindRepository }, + activityManager = activityManagerWrapper, + ) + } 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 new file mode 100644 index 000000000000..4843ae7ceb1d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorKosmos.kt @@ -0,0 +1,43 @@ +/* + * 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.bouncer.data.repository.keyguardBouncerRepository +import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.flag.sceneContainerFlags +import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.statusbar.commandQueue + +val Kosmos.keyguardInteractor by + Kosmos.Fixture { + KeyguardInteractor( + repository = keyguardRepository, + commandQueue = commandQueue, + powerInteractor = powerInteractor, + featureFlags = featureFlagsClassic, + sceneContainerFlags = sceneContainerFlags, + bouncerRepository = keyguardBouncerRepository, + configurationRepository = configurationRepository, + shadeRepository = shadeRepository, + sceneInteractorProvider = { sceneInteractor }, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt new file mode 100644 index 000000000000..e4d115e16b6a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.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. + */ + +package com.android.systemui.keyguard.domain.interactor + +import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import dagger.Lazy + +val Kosmos.keyguardTransitionInteractor: KeyguardTransitionInteractor by + Kosmos.Fixture { + KeyguardTransitionInteractor( + scope = applicationCoroutineScope, + repository = keyguardTransitionRepository, + keyguardInteractor = Lazy { keyguardInteractor }, + fromLockscreenTransitionInteractor = Lazy { fromLockscreenTransitionInteractor }, + fromPrimaryBouncerTransitionInteractor = + Lazy { fromPrimaryBouncerTransitionInteractor }, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt index b05915c4f678..0b1385865d63 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt @@ -1,16 +1,11 @@ package com.android.systemui.kosmos -import android.content.Context -import android.os.UserManager +import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope -import org.mockito.Mockito var Kosmos.testDispatcher by Fixture { StandardTestDispatcher() } var Kosmos.testScope by Fixture { TestScope(testDispatcher) } -var Kosmos.context by Fixture<Context>() -var Kosmos.lifecycleScope by Fixture<CoroutineScope>() - -val Kosmos.userManager by Fixture { Mockito.mock(UserManager::class.java) } +var Kosmos.applicationCoroutineScope by Fixture { testScope.backgroundScope } +var Kosmos.testCase: SysuiTestCase by Fixture() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/ActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/ActivityStarterKosmos.kt new file mode 100644 index 000000000000..0ec8d49ec29b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/ActivityStarterKosmos.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.plugins + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.activityStarter by Kosmos.Fixture { mock<ActivityStarter>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt new file mode 100644 index 000000000000..cac2646a58f2 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.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.plugins.statusbar + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.statusBarStateController by Kosmos.Fixture { mock<StatusBarStateController>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/PowerRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/PowerRepositoryKosmos.kt new file mode 100644 index 000000000000..c924579d43e5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/PowerRepositoryKosmos.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.power.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.powerRepository: PowerRepository by Kosmos.Fixture { fakePowerRepository } +val Kosmos.fakePowerRepository by Kosmos.Fixture { FakePowerRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/domain/interactor/PowerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/domain/interactor/PowerInteractorKosmos.kt new file mode 100644 index 000000000000..8486691a7b95 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/domain/interactor/PowerInteractorKosmos.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.power.domain.interactor + +import com.android.systemui.classifier.falsingCollector +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.plugins.statusbar.statusBarStateController +import com.android.systemui.power.data.repository.powerRepository +import com.android.systemui.statusbar.phone.screenOffAnimationController + +val Kosmos.powerInteractor by + Kosmos.Fixture { + PowerInteractor( + repository = powerRepository, + falsingCollector = falsingCollector, + screenOffAnimationController = screenOffAnimationController, + statusBarStateController = statusBarStateController, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryKosmos.kt new file mode 100644 index 000000000000..7c4e160f6d05 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryKosmos.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.scene.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.scene.shared.model.sceneContainerConfig + +val Kosmos.sceneContainerRepository by + Kosmos.Fixture { SceneContainerRepository(applicationCoroutineScope, sceneContainerConfig) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt new file mode 100644 index 000000000000..998987602234 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneInteractorKosmos.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.scene.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.data.repository.sceneContainerRepository +import com.android.systemui.scene.shared.logger.sceneLogger + +val Kosmos.sceneInteractor by + Kosmos.Fixture { + SceneInteractor( + applicationScope = applicationCoroutineScope, + repository = sceneContainerRepository, + powerInteractor = powerInteractor, + logger = sceneLogger, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsKosmos.kt new file mode 100644 index 000000000000..a3ceef021c59 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsKosmos.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.scene.shared.flag + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.sceneContainerFlags by Kosmos.Fixture { FakeSceneContainerFlags() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/logger/SceneLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/logger/SceneLoggerKosmos.kt new file mode 100644 index 000000000000..c5f24f4f049d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/logger/SceneLoggerKosmos.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.scene.shared.logger + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.sceneLogger by Kosmos.Fixture { mock<SceneLogger>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/SceneContainerConfigKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/SceneContainerConfigKosmos.kt new file mode 100644 index 000000000000..f9cdc1bea309 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/SceneContainerConfigKosmos.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.scene.shared.model + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.sceneContainerConfig by + Kosmos.Fixture { FakeSceneContainerConfigModule().sceneContainerConfig } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeRepositoryKosmos.kt new file mode 100644 index 000000000000..38cedbca3886 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeRepositoryKosmos.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.shade.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.shadeRepository: ShadeRepository by Kosmos.Fixture { fakeShadeRepository } +val Kosmos.fakeShadeRepository by Kosmos.Fixture { FakeShadeRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt new file mode 100644 index 000000000000..7da57f024ec7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.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.shade.domain.interactor + +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.flag.sceneContainerFlags +import com.android.systemui.shade.ShadeModule +import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository +import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor +import com.android.systemui.statusbar.phone.dozeParameters +import com.android.systemui.statusbar.pipeline.mobile.data.repository.userSetupRepository +import com.android.systemui.statusbar.policy.data.repository.deviceProvisioningRepository +import com.android.systemui.user.domain.interactor.userSwitcherInteractor + +var Kosmos.baseShadeInteractor: BaseShadeInteractor by + Kosmos.Fixture { + ShadeModule.provideBaseShadeInteractor( + sceneContainerFlags = sceneContainerFlags, + sceneContainerOn = { shadeInteractorSceneContainerImpl }, + sceneContainerOff = { shadeInteractorLegacyImpl }, + ) + } +val Kosmos.shadeInteractorSceneContainerImpl by + Kosmos.Fixture { + ShadeInteractorSceneContainerImpl( + scope = applicationCoroutineScope, + sceneInteractor = sceneInteractor, + sharedNotificationContainerInteractor = sharedNotificationContainerInteractor, + ) + } +val Kosmos.shadeInteractorLegacyImpl by + Kosmos.Fixture { + ShadeInteractorLegacyImpl( + scope = applicationCoroutineScope, + keyguardRepository = keyguardRepository, + sharedNotificationContainerInteractor = sharedNotificationContainerInteractor, + repository = shadeRepository + ) + } +var Kosmos.shadeInteractor: ShadeInteractor by Kosmos.Fixture { shadeInteractorImpl } +val Kosmos.shadeInteractorImpl by + Kosmos.Fixture { + ShadeInteractorImpl( + scope = applicationCoroutineScope, + deviceProvisioningRepository = deviceProvisioningRepository, + disableFlagsRepository = disableFlagsRepository, + dozeParams = dozeParameters, + keyguardRepository = fakeKeyguardRepository, + keyguardTransitionInteractor = keyguardTransitionInteractor, + powerInteractor = powerInteractor, + userSetupRepository = userSetupRepository, + userSwitcherInteractor = userSwitcherInteractor, + baseShadeInteractor = baseShadeInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shared/system/ActivityManagerWrapperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shared/system/ActivityManagerWrapperKosmos.kt new file mode 100644 index 000000000000..e75359386b2f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shared/system/ActivityManagerWrapperKosmos.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.shared.system + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.activityManagerWrapper by Kosmos.Fixture { mock<ActivityManagerWrapper>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/CommandQueueKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/CommandQueueKosmos.kt new file mode 100644 index 000000000000..27f7f6823cc7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/CommandQueueKosmos.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 + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +var Kosmos.commandQueue by Kosmos.Fixture { mock<CommandQueue>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/NotificationListenerSettingsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/NotificationListenerSettingsRepositoryKosmos.kt new file mode 100644 index 000000000000..10151ac92c35 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/NotificationListenerSettingsRepositoryKosmos.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.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.notificationListenerSettingsRepository by + Kosmos.Fixture { NotificationListenerSettingsRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryKosmos.kt new file mode 100644 index 000000000000..a373a8e1844d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryKosmos.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.statusbar.disableflags.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.disableFlagsRepository: DisableFlagsRepository by + Kosmos.Fixture { fakeDisableFlagsRepository } +val Kosmos.fakeDisableFlagsRepository by Kosmos.Fixture { FakeDisableFlagsRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepositoryKosmos.kt new file mode 100644 index 000000000000..5507d6c2c90d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepositoryKosmos.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.notification.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.activeNotificationListRepository by Kosmos.Fixture { ActiveNotificationListRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationIconViewStateRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationIconViewStateRepositoryKosmos.kt new file mode 100644 index 000000000000..ed62fda6fc99 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpNotificationIconViewStateRepositoryKosmos.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.notification.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.headsUpNotificationIconViewStateRepository by + Kosmos.Fixture { HeadsUpNotificationIconViewStateRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryKosmos.kt new file mode 100644 index 000000000000..f2b9da413c22 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryKosmos.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.statusbar.notification.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.notificationsKeyguardViewStateRepository: NotificationsKeyguardViewStateRepository by + Kosmos.Fixture { fakeNotificationsKeyguardViewStateRepository } +val Kosmos.fakeNotificationsKeyguardViewStateRepository by + Kosmos.Fixture { FakeNotificationsKeyguardViewStateRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.kt new file mode 100644 index 000000000000..3d7fb6d91393 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorKosmos.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.statusbar.notification.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository + +val Kosmos.activeNotificationsInteractor by + Kosmos.Fixture { ActiveNotificationsInteractor(activeNotificationListRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractorKosmos.kt new file mode 100644 index 000000000000..d14c8548f3cf --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationIconInteractorKosmos.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.statusbar.notification.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.notification.data.repository.headsUpNotificationIconViewStateRepository + +val Kosmos.headsUpNotificationIconInteractor by + Kosmos.Fixture { HeadsUpNotificationIconInteractor(headsUpNotificationIconViewStateRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt new file mode 100644 index 000000000000..e7bd5ea2b174 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt @@ -0,0 +1,50 @@ +/* + * 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.statusbar.notification.icon.domain.interactor + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.data.repository.notificationListenerSettingsRepository +import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository +import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor +import com.android.wm.shell.bubbles.bubblesOptional +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.alwaysOnDisplayNotificationIconsInteractor by + Kosmos.Fixture { + AlwaysOnDisplayNotificationIconsInteractor( + deviceEntryInteractor = deviceEntryInteractor, + iconsInteractor = notificationIconsInteractor, + ) + } +val Kosmos.statusBarNotificationIconsInteractor by + Kosmos.Fixture { + StatusBarNotificationIconsInteractor( + iconsInteractor = notificationIconsInteractor, + settingsRepository = notificationListenerSettingsRepository, + ) + } +val Kosmos.notificationIconsInteractor by + Kosmos.Fixture { + NotificationIconsInteractor( + activeNotificationsInteractor = activeNotificationsInteractor, + bubbles = bubblesOptional, + keyguardViewStateRepository = notificationsKeyguardViewStateRepository, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelKosmos.kt new file mode 100644 index 000000000000..6295b83a2bd0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelKosmos.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. + */ + +package com.android.systemui.statusbar.notification.icon.ui.viewmodel + +import android.content.res.mainResources +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.statusbar.notification.icon.domain.interactor.alwaysOnDisplayNotificationIconsInteractor + +val Kosmos.notificationIconContainerAlwaysOnDisplayViewModel by + Kosmos.Fixture { + NotificationIconContainerAlwaysOnDisplayViewModel( + iconsInteractor = alwaysOnDisplayNotificationIconsInteractor, + keyguardInteractor = keyguardInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + resources = mainResources, + shadeInteractor = shadeInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelKosmos.kt new file mode 100644 index 000000000000..04bb52d101db --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelKosmos.kt @@ -0,0 +1,39 @@ +/* + * 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.notification.icon.ui.viewmodel + +import android.content.res.mainResources +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor +import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor +import com.android.systemui.statusbar.notification.icon.domain.interactor.statusBarNotificationIconsInteractor +import com.android.systemui.statusbar.phone.domain.interactor.darkIconInteractor + +val Kosmos.notificationIconContainerStatusBarViewModel by + Kosmos.Fixture { + NotificationIconContainerStatusBarViewModel( + darkIconInteractor = darkIconInteractor, + iconsInteractor = statusBarNotificationIconsInteractor, + headsUpIconInteractor = headsUpNotificationIconInteractor, + keyguardInteractor = keyguardInteractor, + notificationsInteractor = activeNotificationsInteractor, + resources = mainResources, + shadeInteractor = shadeInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt new file mode 100644 index 000000000000..3403227f6d27 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.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.statusbar.notification.stack.domain.interactor + +import android.content.applicationContext +import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.policy.splitShadeStateController + +val Kosmos.sharedNotificationContainerInteractor by + Kosmos.Fixture { + SharedNotificationContainerInteractor( + configurationRepository = configurationRepository, + context = applicationContext, + splitShadeStateController = splitShadeStateController, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeParametersKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeParametersKosmos.kt new file mode 100644 index 000000000000..9f6b181f8348 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeParametersKosmos.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.dozeParameters by Kosmos.Fixture { mock<DozeParameters>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ScreenOffAnimationControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ScreenOffAnimationControllerKosmos.kt new file mode 100644 index 000000000000..d4c21f66d394 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ScreenOffAnimationControllerKosmos.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.screenOffAnimationController by Kosmos.Fixture { mock<ScreenOffAnimationController>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepositoryKosmos.kt new file mode 100644 index 000000000000..977dcb738ba1 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepositoryKosmos.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.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.darkIconRepository: DarkIconRepository by Kosmos.Fixture { fakeDarkIconRepository } +val Kosmos.fakeDarkIconRepository by Kosmos.Fixture { FakeDarkIconRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/domain/interactor/DarkIconInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/domain/interactor/DarkIconInteractorKosmos.kt new file mode 100644 index 000000000000..db678d487b3d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/domain/interactor/DarkIconInteractorKosmos.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.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.phone.data.repository.darkIconRepository + +val Kosmos.darkIconInteractor by Kosmos.Fixture { DarkIconInteractor(darkIconRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt new file mode 100644 index 000000000000..7b9634a7abb5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.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.pipeline.mobile.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository } +val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt new file mode 100644 index 000000000000..18a2f9482df8 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.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.policy + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +val Kosmos.configurationController by Kosmos.Fixture { mock<ConfigurationController>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerKosmos.kt new file mode 100644 index 000000000000..6a77c882eaa1 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerKosmos.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.statusbar.policy + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.deviceProvisionedController: DeviceProvisionedController by + Kosmos.Fixture { fakeDeviceProvisionedController } +val Kosmos.fakeDeviceProvisionedController by Kosmos.Fixture { FakeDeviceProvisionedController() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/SplitShadeStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/SplitShadeStateControllerKosmos.kt new file mode 100644 index 000000000000..5e430381e293 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/SplitShadeStateControllerKosmos.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.statusbar.policy + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.splitShadeStateController: SplitShadeStateController by + Kosmos.Fixture { resourcesSplitShadeStateController } +val Kosmos.resourcesSplitShadeStateController by + Kosmos.Fixture { ResourcesSplitShadeStateController() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryKosmos.kt new file mode 100644 index 000000000000..56a0e02e41dc --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/DeviceProvisioningRepositoryKosmos.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.statusbar.policy.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.deviceProvisioningRepository: DeviceProvisioningRepository by + Kosmos.Fixture { fakeDeviceProvisioningRepository } +val Kosmos.fakeDeviceProvisioningRepository by Kosmos.Fixture { FakeDeviceProvisioningRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryKosmos.kt new file mode 100644 index 000000000000..6bb5ec5f0313 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryKosmos.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.telephony.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.telephonyRepository: TelephonyRepository by Kosmos.Fixture { fakeTelephonyRepository } +val Kosmos.fakeTelephonyRepository by Kosmos.Fixture { FakeTelephonyRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractorKosmos.kt new file mode 100644 index 000000000000..02ca96e3521b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractorKosmos.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.telephony.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.telephony.data.repository.telephonyRepository + +val Kosmos.telephonyInteractor by Kosmos.Fixture { TelephonyInteractor(telephonyRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/UserRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/UserRepositoryKosmos.kt index 8bce9b6d461d..9bb52623bdcd 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/UserRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/UserRepositoryKosmos.kt @@ -18,4 +18,5 @@ package com.android.systemui.user.data.repository import com.android.systemui.kosmos.Kosmos -val Kosmos.userRepository by Kosmos.Fixture { FakeUserRepository() } +var Kosmos.userRepository: UserRepository by Kosmos.Fixture { fakeUserRepository } +val Kosmos.fakeUserRepository by Kosmos.Fixture { FakeUserRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/GuestUserInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/GuestUserInteractorKosmos.kt index e69570433d43..3b1c3f0198c7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/GuestUserInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/GuestUserInteractorKosmos.kt @@ -16,28 +16,32 @@ package com.android.systemui.user.domain.interactor +import android.app.admin.devicePolicyManager +import android.content.applicationContext +import android.os.userManager +import com.android.internal.logging.uiEventLogger +import com.android.systemui.guestResetOrExitSessionReceiver +import com.android.systemui.guestResumeSessionReceiver import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.context -import com.android.systemui.kosmos.lifecycleScope +import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher -import com.android.systemui.kosmos.userManager +import com.android.systemui.statusbar.policy.deviceProvisionedController import com.android.systemui.user.data.repository.userRepository -import com.android.systemui.util.mockito.mock val Kosmos.guestUserInteractor by Kosmos.Fixture { GuestUserInteractor( - applicationContext = context, - applicationScope = lifecycleScope, + applicationContext = applicationContext, + applicationScope = applicationCoroutineScope, mainDispatcher = testDispatcher, backgroundDispatcher = testDispatcher, manager = userManager, - deviceProvisionedController = mock(), repository = userRepository, - devicePolicyManager = mock(), + deviceProvisionedController = deviceProvisionedController, + devicePolicyManager = devicePolicyManager, refreshUsersScheduler = refreshUsersScheduler, - uiEventLogger = mock(), - resumeSessionReceiver = mock(), - resetOrExitSessionReceiver = mock(), + uiEventLogger = uiEventLogger, + resumeSessionReceiver = guestResumeSessionReceiver, + resetOrExitSessionReceiver = guestResetOrExitSessionReceiver, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeKosmos.kt new file mode 100644 index 000000000000..de9f69bc9215 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeKosmos.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.user.domain.interactor + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.headlessSystemUserMode by Kosmos.Fixture { HeadlessSystemUserModeImpl() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerKosmos.kt index 87a2fe0249e3..14da8b0f461c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerKosmos.kt @@ -17,15 +17,11 @@ package com.android.systemui.user.domain.interactor import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.lifecycleScope +import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.user.data.repository.userRepository val Kosmos.refreshUsersScheduler by Kosmos.Fixture { - RefreshUsersScheduler( - applicationScope = lifecycleScope, - mainDispatcher = testDispatcher, - repository = userRepository, - ) + RefreshUsersScheduler(applicationCoroutineScope, testDispatcher, userRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt new file mode 100644 index 000000000000..427f92a7f514 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.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.user.domain.interactor + +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.user.data.repository.userRepository + +val Kosmos.selectedUserInteractor by + Kosmos.Fixture { SelectedUserInteractor(userRepository, featureFlagsClassic) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorKosmos.kt index 6d6b2683a7ea..42c77aaac53f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorKosmos.kt @@ -16,42 +16,41 @@ package com.android.systemui.user.domain.interactor +import android.app.activityManager +import android.content.applicationContext +import android.os.userManager +import com.android.internal.logging.uiEventLogger +import com.android.keyguard.keyguardUpdateMonitor import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.flags.featureFlags -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.context -import com.android.systemui.kosmos.lifecycleScope +import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher -import com.android.systemui.kosmos.userManager -import com.android.systemui.telephony.data.repository.FakeTelephonyRepository -import com.android.systemui.telephony.domain.interactor.TelephonyInteractor +import com.android.systemui.plugins.activityStarter +import com.android.systemui.telephony.domain.interactor.telephonyInteractor import com.android.systemui.user.data.repository.userRepository -import com.android.systemui.util.mockito.mock +import com.android.systemui.utils.userRestrictionChecker val Kosmos.userSwitcherInteractor by Kosmos.Fixture { UserSwitcherInteractor( - applicationContext = context, + applicationContext = applicationContext, repository = userRepository, - activityStarter = mock(), - keyguardInteractor = - KeyguardInteractorFactory.create(featureFlags = featureFlags).keyguardInteractor, - featureFlags = featureFlags, + activityStarter = activityStarter, + keyguardInteractor = keyguardInteractor, + featureFlags = featureFlagsClassic, manager = userManager, - headlessSystemUserMode = mock(), - applicationScope = lifecycleScope, - telephonyInteractor = - TelephonyInteractor( - repository = FakeTelephonyRepository(), - ), + headlessSystemUserMode = headlessSystemUserMode, + applicationScope = applicationCoroutineScope, + telephonyInteractor = telephonyInteractor, broadcastDispatcher = broadcastDispatcher, - keyguardUpdateMonitor = mock(), + keyguardUpdateMonitor = keyguardUpdateMonitor, backgroundDispatcher = testDispatcher, - activityManager = mock(), + activityManager = activityManager, refreshUsersScheduler = refreshUsersScheduler, guestUserInteractor = guestUserInteractor, - uiEventLogger = mock(), - userRestrictionChecker = mock() + uiEventLogger = uiEventLogger, + userRestrictionChecker = userRestrictionChecker, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt new file mode 100644 index 000000000000..914e65427f41 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.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.util.time + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.fakeSystemClock by Kosmos.Fixture { FakeSystemClock() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/UserRestrictionCheckerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/UserRestrictionCheckerKosmos.kt new file mode 100644 index 000000000000..24d5d2f72289 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/UserRestrictionCheckerKosmos.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.utils + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.userRestrictionChecker by Kosmos.Fixture { UserRestrictionChecker() } diff --git a/packages/SystemUI/tests/utils/src/com/android/wm/shell/bubbles/BubblesKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/wm/shell/bubbles/BubblesKosmos.kt new file mode 100644 index 000000000000..a7a37b22c969 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/wm/shell/bubbles/BubblesKosmos.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.wm.shell.bubbles + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock +import java.util.Optional + +var Kosmos.bubblesOptional by Kosmos.Fixture { Optional.of(bubbles) } +var Kosmos.bubbles by Kosmos.Fixture { mock<Bubbles> {} } diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java index 1d315798d647..f02f06c056bd 100644 --- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java +++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeep.java @@ -18,7 +18,6 @@ package android.ravenwood.annotation; 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; @@ -32,7 +31,7 @@ import java.lang.annotation.Target; * * @hide */ -@Target({TYPE, FIELD, METHOD, CONSTRUCTOR}) +@Target({FIELD, METHOD, CONSTRUCTOR}) @Retention(RetentionPolicy.CLASS) public @interface RavenwoodKeep { } diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepPartialClass.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepPartialClass.java new file mode 100644 index 000000000000..784727410188 --- /dev/null +++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepPartialClass.java @@ -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. + */ +package android.ravenwood.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY + * QUESTIONS ABOUT IT. + * + * TODO: Javadoc + * + * @hide + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface RavenwoodKeepPartialClass { +} diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepStaticInitializer.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepStaticInitializer.java new file mode 100644 index 000000000000..eeebee985e4a --- /dev/null +++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodKeepStaticInitializer.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.ravenwood.annotation; + +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY + * QUESTIONS ABOUT IT. + * + * @hide + */ +@Target(TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface RavenwoodKeepStaticInitializer { +} diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt index 28639d4960a4..48e93280f73f 100644 --- a/ravenwood/framework-minus-apex-ravenwood-policies.txt +++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt @@ -17,12 +17,14 @@ class android.util.MapCollections stubclass class android.util.Log stubclass class android.util.Log !com.android.hoststubgen.nativesubstitution.Log_host class android.util.LogPrinter stubclass +class android.util.LocalLog stubclass # String Manipulation class android.util.Printer stubclass class android.util.PrintStreamPrinter stubclass class android.util.PrintWriterPrinter stubclass class android.util.StringBuilderPrinter stubclass +class android.util.IndentingPrintWriter stubclass # Properties class android.util.Property stubclass @@ -76,6 +78,7 @@ class android.util.Patterns stubclass class android.util.UtilConfig stubclass # Internals +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.Preconditions stubclass diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt index df44fde2ed72..a791f682fecf 100644 --- a/ravenwood/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/ravenwood-annotation-allowed-classes.txt @@ -2,6 +2,12 @@ com.android.internal.util.ArrayUtils +android.util.DataUnit +android.util.EventLog +android.util.IntArray +android.util.LongArray +android.util.Slog +android.util.TimeUtils android.util.Xml android.os.Binder diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/ravenwood-standard-options.txt index 4b07ef6e35a8..f842f33bc95b 100644 --- a/ravenwood/ravenwood-standard-options.txt +++ b/ravenwood/ravenwood-standard-options.txt @@ -18,6 +18,9 @@ --keep-annotation android.ravenwood.annotation.RavenwoodKeep +--keep-annotation + android.ravenwood.annotation.RavenwoodKeepPartialClass + --keep-class-annotation android.ravenwood.annotation.RavenwoodKeepWholeClass @@ -35,3 +38,6 @@ --class-load-hook-annotation android.ravenwood.annotation.RavenwoodClassLoadHook + +--keep-static-initializer-annotation + android.ravenwood.annotation.RavenwoodKeepStaticInitializer diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java index 1f6261383961..23e7ce68c1d0 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java @@ -20,6 +20,7 @@ import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_S import android.companion.AssociationInfo; import android.companion.ContextSyncMessage; +import android.companion.Flags; import android.companion.Telecom; import android.companion.datatransfer.PermissionSyncRequest; import android.net.MacAddress; @@ -65,7 +66,14 @@ class CompanionDeviceShellCommand extends ShellCommand { public int onCommand(String cmd) { final PrintWriter out = getOutPrintWriter(); final int associationId; + try { + if ("simulate-device-event".equals(cmd) && Flags.devicePresence()) { + associationId = getNextIntArgRequired(); + int event = getNextIntArgRequired(); + mDevicePresenceMonitor.simulateDeviceEvent(associationId, event); + return 0; + } switch (cmd) { case "list": { final int userId = getNextIntArgRequired(); @@ -107,10 +115,15 @@ class CompanionDeviceShellCommand extends ShellCommand { mService.loadAssociationsFromDisk(); break; - case "simulate-device-event": + case "simulate-device-appeared": + associationId = getNextIntArgRequired(); + mDevicePresenceMonitor.simulateDeviceEvent(associationId, /* event */ 0); + break; + + case "simulate-device-disappeared": associationId = getNextIntArgRequired(); - int event = getNextIntArgRequired(); - mDevicePresenceMonitor.simulateDeviceEvent(associationId, event); + mDevicePresenceMonitor.simulateDeviceEvent(associationId, /* event */ 1); + break; case "remove-inactive-associations": { // This command should trigger the same "clean-up" job as performed by the @@ -346,9 +359,7 @@ class CompanionDeviceShellCommand extends ShellCommand { pw.println(" information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY."); pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY."); - pw.println(" simulate-device-event ASSOCIATION_ID EVENT"); - pw.println(" Simulate the companion device event changes:"); - pw.println(" Case(0): "); + pw.println(" simulate-device-appeared ASSOCIATION_ID"); pw.println(" Make CDM act as if the given companion device has appeared."); pw.println(" I.e. bind the associated companion application's"); pw.println(" CompanionDeviceService(s) and trigger onDeviceAppeared() callback."); @@ -356,18 +367,43 @@ class CompanionDeviceShellCommand extends ShellCommand { pw.println(" will act as if device disappeared, unless 'simulate-device-disappeared'"); pw.println(" or 'simulate-device-appeared' is called again before 60 seconds run out" + "."); - pw.println(" Case(1): "); + pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY."); + + pw.println(" simulate-device-disappeared ASSOCIATION_ID"); pw.println(" Make CDM act as if the given companion device has disappeared."); pw.println(" I.e. unbind the associated companion application's"); pw.println(" CompanionDeviceService(s) and trigger onDeviceDisappeared() callback."); pw.println(" NOTE: This will only have effect if 'simulate-device-appeared' was"); pw.println(" invoked for the same device (same ASSOCIATION_ID) no longer than"); pw.println(" 60 seconds ago."); - pw.println(" Case(2): "); - pw.println(" Make CDM act as if the given companion device is BT connected "); - pw.println(" Case(3): "); - pw.println(" Make CDM act as if the given companion device is BT disconnected "); - pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY."); + + if (Flags.devicePresence()) { + pw.println(" simulate-device-event ASSOCIATION_ID EVENT"); + pw.println(" Simulate the companion device event changes:"); + pw.println(" Case(0): "); + pw.println(" Make CDM act as if the given companion device has appeared."); + pw.println(" I.e. bind the associated companion application's"); + pw.println(" CompanionDeviceService(s) and trigger onDeviceAppeared() callback."); + pw.println(" The CDM will consider the devices as present for" + + "60 seconds and then"); + pw.println(" will act as if device disappeared, unless" + + "'simulate-device-disappeared'"); + pw.println(" or 'simulate-device-appeared' is called again before 60 seconds" + + "run out."); + pw.println(" Case(1): "); + pw.println(" Make CDM act as if the given companion device has disappeared."); + pw.println(" I.e. unbind the associated companion application's"); + pw.println(" CompanionDeviceService(s) and trigger onDeviceDisappeared()" + + "callback."); + pw.println(" NOTE: This will only have effect if 'simulate-device-appeared' was"); + pw.println(" invoked for the same device (same ASSOCIATION_ID) no longer than"); + pw.println(" 60 seconds ago."); + pw.println(" Case(2): "); + pw.println(" Make CDM act as if the given companion device is BT connected "); + pw.println(" Case(3): "); + pw.println(" Make CDM act as if the given companion device is BT disconnected "); + pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY."); + } pw.println(" remove-inactive-associations"); pw.println(" Remove self-managed associations that have not been active "); diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java index 8fea078c3183..e42b9356cca3 100644 --- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java +++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java @@ -79,7 +79,7 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange void onDeviceDisappeared(int associationId); /**Invoked when device has corresponding event changes. */ - void onDeviceEvent(int associationId, int state); + void onDeviceEvent(int associationId, int event); } private final @NonNull AssociationStore mAssociationStore; diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index 8cd5ce1f4ff8..ce1a8756a849 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -158,6 +158,10 @@ public final class PinnerService extends SystemService { @GuardedBy("this") private ArraySet<Integer> mPinKeys; + // Note that we don't use the `_BOOT` namespace for anonymous pinnings, as we want + // them to be responsive to dynamic flag changes for experimentation. + private static final String DEVICE_CONFIG_NAMESPACE_ANON_SIZE = + DeviceConfig.NAMESPACE_RUNTIME_NATIVE; private static final String DEVICE_CONFIG_KEY_ANON_SIZE = "pin_shared_anon_size"; private static final long DEFAULT_ANON_SIZE = SystemProperties.getLong("pinner.pin_shared_anon_size", 0); @@ -188,11 +192,11 @@ public final class PinnerService extends SystemService { } }; - private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener = + private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigAnonSizeListener = new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { - if (DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT.equals(properties.getNamespace()) + if (DEVICE_CONFIG_NAMESPACE_ANON_SIZE.equals(properties.getNamespace()) && properties.getKeyset().contains(DEVICE_CONFIG_KEY_ANON_SIZE)) { refreshPinAnonConfig(); } @@ -246,9 +250,9 @@ public final class PinnerService extends SystemService { registerUserSetupCompleteListener(); mDeviceConfigInterface.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, + DEVICE_CONFIG_NAMESPACE_ANON_SIZE, new HandlerExecutor(mPinnerHandler), - mDeviceConfigListener); + mDeviceConfigAnonSizeListener); } @Override @@ -733,7 +737,7 @@ public final class PinnerService extends SystemService { private void refreshPinAnonConfig() { long newPinAnonSize = mDeviceConfigInterface.getLong( - DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, + DEVICE_CONFIG_NAMESPACE_ANON_SIZE, DEVICE_CONFIG_KEY_ANON_SIZE, DEFAULT_ANON_SIZE); newPinAnonSize = Math.max(0, Math.min(newPinAnonSize, MAX_ANON_SIZE)); diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java index b852ef56fceb..d372108e0a47 100644 --- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java +++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java @@ -67,10 +67,8 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal.OomAdjReason; import android.content.pm.ServiceInfo; -import android.os.IBinder; import android.os.SystemClock; import android.os.Trace; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -80,7 +78,6 @@ import com.android.server.ServiceThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.function.Consumer; @@ -504,6 +501,28 @@ public class OomAdjusterModernImpl extends OomAdjuster { } } + /** + * A helper consumer for collecting processes that have not been reached yet. To avoid object + * allocations every OomAdjuster update, the results will be stored in + * {@link UnreachedProcessCollector#processList}. The process list reader is responsible + * for setting it before usage, as well as, clearing the reachable state of each process in the + * list. + */ + private static class UnreachedProcessCollector implements Consumer<ProcessRecord> { + public ArrayList<ProcessRecord> processList = null; + @Override + public void accept(ProcessRecord process) { + if (process.mState.isReachable()) { + return; + } + process.mState.setReachable(true); + processList.add(process); + } + } + + private final UnreachedProcessCollector mUnreachedProcessCollector = + new UnreachedProcessCollector(); + OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) { this(service, processList, activeUids, createAdjusterThread()); @@ -755,23 +774,8 @@ public class OomAdjusterModernImpl extends OomAdjuster { // We'll need to collect the upstream processes of the target apps here, because those // processes would potentially impact the procstate/adj via bindings. if (!fullUpdate) { - final boolean containsCycle = collectReversedReachableProcessesLocked(targetProcesses, - clientProcesses); - - // If any of its upstream processes are in a cycle, - // move them into the candidate targets. - if (containsCycle) { - // Add all client apps to the target process list. - for (int i = 0, size = clientProcesses.size(); i < size; i++) { - final ProcessRecord client = clientProcesses.get(i); - final UidRecord uidRec = client.getUidRecord(); - targetProcesses.add(client); - if (uidRec != null) { - uids.put(uidRec.getUid(), uidRec); - } - } - clientProcesses.clear(); - } + collectExcludedClientProcessesLocked(targetProcesses, clientProcesses); + for (int i = 0, size = targetProcesses.size(); i < size; i++) { final ProcessRecord app = targetProcesses.valueAt(i); app.mState.resetCachedInfo(); @@ -807,102 +811,36 @@ public class OomAdjusterModernImpl extends OomAdjuster { } /** - * Collect the reversed reachable processes from the given {@code apps}, the result will be - * returned in the given {@code processes}, which will <em>NOT</em> include the processes from - * the given {@code apps}. + * Collect the client processes from the given {@code apps}, the result will be returned in the + * given {@code clientProcesses}, which will <em>NOT</em> include the processes from the given + * {@code apps}. */ @GuardedBy("mService") - private boolean collectReversedReachableProcessesLocked(ArraySet<ProcessRecord> apps, + private void collectExcludedClientProcessesLocked(ArraySet<ProcessRecord> apps, ArrayList<ProcessRecord> clientProcesses) { - final ArrayDeque<ProcessRecord> queue = mTmpQueue; - queue.clear(); - clientProcesses.clear(); - for (int i = 0, size = apps.size(); i < size; i++) { + // Mark all of the provided apps as reachable to avoid including them in the client list. + final int appsSize = apps.size(); + for (int i = 0; i < appsSize; i++) { final ProcessRecord app = apps.valueAt(i); app.mState.setReachable(true); - app.mState.setReversedReachable(true); - queue.offer(app); } - // Track if any of them reachables could include a cycle - boolean containsCycle = false; - - // Scan upstreams of the process record - for (ProcessRecord pr = queue.poll(); pr != null; pr = queue.poll()) { - if (!pr.mState.isReachable()) { - // If not in the given initial set of apps, add it. - clientProcesses.add(pr); - } - final ProcessServiceRecord psr = pr.mServices; - for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) { - final ServiceRecord s = psr.getRunningServiceAt(i); - final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = - s.getConnections(); - for (int j = serviceConnections.size() - 1; j >= 0; j--) { - final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j); - for (int k = clist.size() - 1; k >= 0; k--) { - final ConnectionRecord cr = clist.get(k); - final ProcessRecord client = cr.binding.client; - containsCycle |= client.mState.isReversedReachable(); - if (client.mState.isReversedReachable()) { - continue; - } - queue.offer(client); - client.mState.setReversedReachable(true); - } - } - } - final ProcessProviderRecord ppr = pr.mProviders; - for (int i = ppr.numberOfProviders() - 1; i >= 0; i--) { - final ContentProviderRecord cpr = ppr.getProviderAt(i); - for (int j = cpr.connections.size() - 1; j >= 0; j--) { - final ContentProviderConnection conn = cpr.connections.get(j); - final ProcessRecord client = conn.client; - containsCycle |= client.mState.isReversedReachable(); - if (client.mState.isReversedReachable()) { - continue; - } - queue.offer(client); - client.mState.setReversedReachable(true); - } - } - // If this process is a sandbox itself, also add the app on whose behalf - // its running - if (pr.isSdkSandbox) { - for (int is = psr.numberOfRunningServices() - 1; is >= 0; is--) { - ServiceRecord s = psr.getRunningServiceAt(is); - ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = - s.getConnections(); - for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) { - ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni); - for (int i = clist.size() - 1; i >= 0; i--) { - ConnectionRecord cr = clist.get(i); - ProcessRecord attributedApp = cr.binding.attributedClient; - if (attributedApp == null || attributedApp == pr) { - continue; - } - containsCycle |= attributedApp.mState.isReversedReachable(); - if (attributedApp.mState.isReversedReachable()) { - continue; - } - queue.offer(attributedApp); - attributedApp.mState.setReversedReachable(true); - } - } - } - } + clientProcesses.clear(); + mUnreachedProcessCollector.processList = clientProcesses; + for (int i = 0; i < appsSize; i++) { + final ProcessRecord app = apps.valueAt(i); + app.forEachClient(mUnreachedProcessCollector); } + mUnreachedProcessCollector.processList = null; // Reset the temporary bits. for (int i = clientProcesses.size() - 1; i >= 0; i--) { - clientProcesses.get(i).mState.setReversedReachable(false); + clientProcesses.get(i).mState.setReachable(false); } for (int i = 0, size = apps.size(); i < size; i++) { final ProcessRecord app = apps.valueAt(i); app.mState.setReachable(false); - app.mState.setReversedReachable(false); } - return containsCycle; } @GuardedBy({"mService", "mProcLock"}) @@ -917,10 +855,6 @@ public class OomAdjusterModernImpl extends OomAdjuster { final int procStateTarget = mProcessRecordProcStateNodes.size() - 1; final int adjTarget = mProcessRecordAdjNodes.size() - 1; - final int appUid = !fullUpdate && targetProcesses.size() > 0 - ? targetProcesses.valueAt(0).uid : -1; - final int logUid = mService.mCurOomAdjUid; - mAdjSeq++; // All apps to be updated will be moved to the lowest slot. if (fullUpdate) { @@ -974,7 +908,7 @@ public class OomAdjusterModernImpl extends OomAdjuster { // We don't update the adj list since we're resetting it below. } - // Now nodes are set into their slots, without facting in the bindings. + // Now nodes are set into their slots, without factoring in the bindings. // The nodes between the `lastNode` pointer and the TAIL should be the new nodes. // // The whole rationale here is that, the bindings from client to host app, won't elevate diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 2c6e598ef0a4..b2082d9e8dc0 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -69,8 +69,10 @@ import com.android.server.wm.WindowProcessController; import com.android.server.wm.WindowProcessListener; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.Consumer; /** * Full information about a particular process that @@ -1613,4 +1615,50 @@ class ProcessRecord implements WindowProcessListener { public boolean wasForceStopped() { return mWasForceStopped; } + + /** + * Traverses all client processes and feed them to consumer. + */ + @GuardedBy("mProcLock") + void forEachClient(@NonNull Consumer<ProcessRecord> consumer) { + for (int i = mServices.numberOfRunningServices() - 1; i >= 0; i--) { + final ServiceRecord s = mServices.getRunningServiceAt(i); + final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = + s.getConnections(); + for (int j = serviceConnections.size() - 1; j >= 0; j--) { + final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j); + for (int k = clist.size() - 1; k >= 0; k--) { + final ConnectionRecord cr = clist.get(k); + consumer.accept(cr.binding.client); + } + } + } + for (int i = mProviders.numberOfProviders() - 1; i >= 0; i--) { + final ContentProviderRecord cpr = mProviders.getProviderAt(i); + for (int j = cpr.connections.size() - 1; j >= 0; j--) { + final ContentProviderConnection conn = cpr.connections.get(j); + consumer.accept(conn.client); + } + } + // If this process is a sandbox itself, also add the app on whose behalf + // its running + if (isSdkSandbox) { + for (int is = mServices.numberOfRunningServices() - 1; is >= 0; is--) { + ServiceRecord s = mServices.getRunningServiceAt(is); + ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = + s.getConnections(); + for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) { + ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni); + for (int i = clist.size() - 1; i >= 0; i--) { + ConnectionRecord cr = clist.get(i); + ProcessRecord attributedApp = cr.binding.attributedClient; + if (attributedApp == null || attributedApp == this) { + continue; + } + consumer.accept(attributedApp); + } + } + } + } + } } diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index 8723c5d549e4..5ad921fd0bae 100644 --- a/services/core/java/com/android/server/am/ProcessStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -379,12 +379,6 @@ final class ProcessStateRecord { private boolean mReachable; /** - * Whether or not this process is reversed reachable from given process. - */ - @GuardedBy("mService") - private boolean mReversedReachable; - - /** * The most recent time when the last visible activity within this process became invisible. * * <p> It'll be set to 0 if there is never a visible activity, or Long.MAX_VALUE if there is @@ -997,16 +991,6 @@ final class ProcessStateRecord { } @GuardedBy("mService") - boolean isReversedReachable() { - return mReversedReachable; - } - - @GuardedBy("mService") - void setReversedReachable(boolean reversedReachable) { - mReversedReachable = reversedReachable; - } - - @GuardedBy("mService") void resetCachedInfo() { mCachedHasActivities = VALUE_INVALID; mCachedIsHeavyWeight = VALUE_INVALID; diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index b9ccbfbf55e7..c5073001a672 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -576,7 +576,7 @@ public final class AuthSession implements IBinder.DeathRecipient { } void onDialogAnimatedIn(boolean startFingerprintNow) { - if (mState != STATE_AUTH_STARTED) { + if (mState != STATE_AUTH_STARTED && mState != STATE_ERROR_PENDING_SYSUI) { Slog.e(TAG, "onDialogAnimatedIn, unexpected state: " + mState); return; } diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index fac727f17283..dff14b5fbdd0 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -1114,12 +1114,22 @@ public final class DeviceStateManagerService extends SystemService { public void notifyDeviceStateInfoAsync(@NonNull DeviceStateInfo info) { mHandler.post(() -> { + boolean tracingEnabled = Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER); + if (tracingEnabled) { // To avoid creating the string when not needed. + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, + "notifyDeviceStateInfoAsync(pid=" + mPid + ")"); + } try { mCallback.onDeviceStateInfoChanged(info); } catch (RemoteException ex) { Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.", ex); } + finally { + if (tracingEnabled) { + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + } + } }); } diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java index 669580189d7c..9fcaa1e2af16 100644 --- a/services/core/java/com/android/server/display/DisplayBrightnessState.java +++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java @@ -38,6 +38,7 @@ public final class DisplayBrightnessState { private final boolean mShouldUseAutoBrightness; private final boolean mIsSlowChange; + private final boolean mShouldUpdateScreenBrightnessSetting; private final float mCustomAnimationRate; @@ -50,6 +51,7 @@ public final class DisplayBrightnessState { mIsSlowChange = builder.isSlowChange(); mMaxBrightness = builder.getMaxBrightness(); mCustomAnimationRate = builder.getCustomAnimationRate(); + mShouldUpdateScreenBrightnessSetting = builder.shouldUpdateScreenBrightnessSetting(); } /** @@ -109,6 +111,13 @@ public final class DisplayBrightnessState { return mCustomAnimationRate; } + /** + * @return {@code true} if the screen brightness setting should be updated + */ + public boolean shouldUpdateScreenBrightnessSetting() { + return mShouldUpdateScreenBrightnessSetting; + } + @Override public String toString() { StringBuilder stringBuilder = new StringBuilder("DisplayBrightnessState:"); @@ -123,6 +132,8 @@ public final class DisplayBrightnessState { stringBuilder.append("\n isSlowChange:").append(mIsSlowChange); stringBuilder.append("\n maxBrightness:").append(mMaxBrightness); stringBuilder.append("\n customAnimationRate:").append(mCustomAnimationRate); + stringBuilder.append("\n shouldUpdateScreenBrightnessSetting:") + .append(mShouldUpdateScreenBrightnessSetting); return stringBuilder.toString(); } @@ -149,13 +160,16 @@ public final class DisplayBrightnessState { && mShouldUseAutoBrightness == otherState.getShouldUseAutoBrightness() && mIsSlowChange == otherState.isSlowChange() && mMaxBrightness == otherState.getMaxBrightness() - && mCustomAnimationRate == otherState.getCustomAnimationRate(); + && mCustomAnimationRate == otherState.getCustomAnimationRate() + && mShouldUpdateScreenBrightnessSetting + == otherState.shouldUpdateScreenBrightnessSetting(); } @Override public int hashCode() { return Objects.hash(mBrightness, mSdrBrightness, mBrightnessReason, - mShouldUseAutoBrightness, mIsSlowChange, mMaxBrightness, mCustomAnimationRate); + mShouldUseAutoBrightness, mIsSlowChange, mMaxBrightness, mCustomAnimationRate, + mShouldUpdateScreenBrightnessSetting); } /** @@ -177,6 +191,7 @@ public final class DisplayBrightnessState { private boolean mIsSlowChange; private float mMaxBrightness; private float mCustomAnimationRate = CUSTOM_ANIMATION_RATE_NOT_SET; + private boolean mShouldUpdateScreenBrightnessSetting; /** * Create a builder starting with the values from the specified {@link @@ -194,6 +209,8 @@ public final class DisplayBrightnessState { builder.setIsSlowChange(state.isSlowChange()); builder.setMaxBrightness(state.getMaxBrightness()); builder.setCustomAnimationRate(state.getCustomAnimationRate()); + builder.setShouldUpdateScreenBrightnessSetting( + state.shouldUpdateScreenBrightnessSetting()); return builder; } @@ -290,8 +307,8 @@ public final class DisplayBrightnessState { /** * See {@link DisplayBrightnessState#isSlowChange()}. */ - public Builder setIsSlowChange(boolean shouldUseAutoBrightness) { - this.mIsSlowChange = shouldUseAutoBrightness; + public Builder setIsSlowChange(boolean isSlowChange) { + this.mIsSlowChange = isSlowChange; return this; } @@ -334,6 +351,22 @@ public final class DisplayBrightnessState { } /** + * See {@link DisplayBrightnessState#shouldUpdateScreenBrightnessSetting()}. + */ + public boolean shouldUpdateScreenBrightnessSetting() { + return mShouldUpdateScreenBrightnessSetting; + } + + /** + * See {@link DisplayBrightnessState#shouldUpdateScreenBrightnessSetting()}. + */ + public Builder setShouldUpdateScreenBrightnessSetting( + boolean shouldUpdateScreenBrightnessSetting) { + mShouldUpdateScreenBrightnessSetting = shouldUpdateScreenBrightnessSetting; + return this; + } + + /** * This is used to construct an immutable DisplayBrightnessState object from its builder */ public DisplayBrightnessState build() { diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 9f4f78794659..2fdf90d7d286 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -209,7 +209,7 @@ abstract class DisplayDevice { int state, float brightnessState, float sdrBrightnessState, - @Nullable DisplayOffloadSession displayOffloadSession) { + @Nullable DisplayOffloadSessionImpl displayOffloadSession) { return null; } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 11f4e5f75b11..e99f82aee96d 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -4948,20 +4948,8 @@ public final class DisplayManagerService extends SystemService { return null; } - DisplayOffloadSession session = - new DisplayOffloadSession() { - @Override - public void setDozeStateOverride(int displayState) { - synchronized (mSyncRoot) { - displayPowerController.overrideDozeScreenState(displayState); - } - } - - @Override - public DisplayOffloader getDisplayOffloader() { - return displayOffloader; - } - }; + DisplayOffloadSessionImpl session = new DisplayOffloadSessionImpl(displayOffloader, + displayPowerController); logicalDisplay.setDisplayOffloadSessionLocked(session); displayPowerController.setDisplayOffloadSession(session); return session; diff --git a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java new file mode 100644 index 000000000000..1bd556bdcc4f --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java @@ -0,0 +1,91 @@ +/* + * 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.display; + +import android.annotation.Nullable; +import android.hardware.display.DisplayManagerInternal; +import android.os.PowerManager; +import android.os.Trace; + +/** + * An implementation of the offload session that keeps track of whether the session is active. + * An offload session is used to control the display's brightness using the offload chip. + */ +public class DisplayOffloadSessionImpl implements DisplayManagerInternal.DisplayOffloadSession { + + @Nullable + private final DisplayManagerInternal.DisplayOffloader mDisplayOffloader; + private final DisplayPowerControllerInterface mDisplayPowerController; + private boolean mIsActive; + + public DisplayOffloadSessionImpl( + @Nullable DisplayManagerInternal.DisplayOffloader displayOffloader, + DisplayPowerControllerInterface displayPowerController) { + mDisplayOffloader = displayOffloader; + mDisplayPowerController = displayPowerController; + } + + @Override + public void setDozeStateOverride(int displayState) { + mDisplayPowerController.overrideDozeScreenState(displayState); + } + + @Override + public boolean isActive() { + return mIsActive; + } + + @Override + public void updateBrightness(float brightness) { + if (mIsActive) { + mDisplayPowerController.setBrightnessFromOffload(brightness); + } + } + + /** + * Start the offload session. The method returns if the session is already active. + * @return Whether the session was started successfully + */ + public boolean startOffload() { + if (mDisplayOffloader == null || mIsActive) { + return false; + } + Trace.traceBegin(Trace.TRACE_TAG_POWER, "DisplayOffloader#startOffload"); + try { + return mIsActive = mDisplayOffloader.startOffload(); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_POWER); + } + } + + /** + * Stop the offload session. The method returns if the session is not active. + */ + public void stopOffload() { + if (mDisplayOffloader == null || !mIsActive) { + return; + } + Trace.traceBegin(Trace.TRACE_TAG_POWER, "DisplayOffloader#stopOffload"); + try { + mDisplayOffloader.stopOffload(); + mIsActive = false; + mDisplayPowerController.setBrightnessFromOffload(PowerManager.BRIGHTNESS_INVALID_FLOAT); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_POWER); + } + } +} diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 5761c31b29bf..f3d761a7372b 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -2224,6 +2224,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } @Override + public void setBrightnessFromOffload(float brightness) { + // The old DPC is no longer supported + } + + @Override public BrightnessInfo getBrightnessInfo() { synchronized (mCachedBrightnessInfo) { return new BrightnessInfo( diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index a6155da86f9a..d4e0cbb126ed 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -151,6 +151,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private static final int MSG_SET_DWBC_STRONG_MODE = 14; private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 15; private static final int MSG_SET_DWBC_LOGGING_ENABLED = 16; + private static final int MSG_SET_BRIGHTNESS_FROM_OFFLOAD = 17; @@ -562,7 +563,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal new DisplayBrightnessController(context, null, mDisplayId, mLogicalDisplay.getDisplayInfoLocked().brightnessDefault, brightnessSetting, () -> postBrightnessChangeRunnable(), - new HandlerExecutor(mHandler)); + new HandlerExecutor(mHandler), flags); mBrightnessClamperController = mInjector.getBrightnessClamperController( mHandler, modeChangeCallback::run, @@ -1394,7 +1395,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); - boolean updateScreenBrightnessSetting = false; + boolean updateScreenBrightnessSetting = + displayBrightnessState.shouldUpdateScreenBrightnessSetting(); float currentBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness(); // Apply auto-brightness. int brightnessAdjustmentFlags = 0; @@ -1854,6 +1856,13 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } @Override + public void setBrightnessFromOffload(float brightness) { + Message msg = mHandler.obtainMessage(MSG_SET_BRIGHTNESS_FROM_OFFLOAD, + Float.floatToIntBits(brightness), 0 /*unused*/); + mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); + } + + @Override public BrightnessInfo getBrightnessInfo() { synchronized (mCachedBrightnessInfo) { return new BrightnessInfo( @@ -2886,6 +2895,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal case MSG_SET_DWBC_LOGGING_ENABLED: setDwbcLoggingEnabled(msg.arg1); break; + case MSG_SET_BRIGHTNESS_FROM_OFFLOAD: + mDisplayBrightnessController.setBrightnessFromOffload( + Float.intBitsToFloat(msg.arg1)); + updatePowerState(); + break; } } } diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java index 181386a93c71..72079a4c82fe 100644 --- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java +++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java @@ -22,6 +22,7 @@ import android.hardware.display.BrightnessChangeEvent; import android.hardware.display.BrightnessConfiguration; import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManagerInternal; +import android.os.PowerManager; import java.io.PrintWriter; @@ -150,6 +151,14 @@ public interface DisplayPowerControllerInterface { void setTemporaryAutoBrightnessAdjustment(float adjustment); /** + * Sets temporary brightness from the offload chip until we get a brightness value from + * the light sensor. + * @param brightness The brightness value between {@link PowerManager.BRIGHTNESS_MIN} and + * {@link PowerManager.BRIGHTNESS_MAX}. Values outside of that range will be ignored. + */ + void setBrightnessFromOffload(float brightness); + + /** * Gets the screen brightness setting */ float getScreenBrightnessSetting(); diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index be3207dfb4ee..ff9a1ab61b13 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -19,11 +19,11 @@ package com.android.server.display; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.Mode.INVALID_MODE_ID; +import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; import android.content.res.Resources; import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; -import android.hardware.display.DisplayManagerInternal.DisplayOffloader; import android.hardware.sidekick.SidekickInternal; import android.os.Build; import android.os.Handler; @@ -238,7 +238,6 @@ final class LocalDisplayAdapter extends DisplayAdapter { private boolean mAllmRequested; private boolean mGameContentTypeRequested; private boolean mSidekickActive; - private boolean mDisplayOffloadActive; private SurfaceControl.StaticDisplayInfo mStaticDisplayInfo; // The supported display modes according to SurfaceFlinger private SurfaceControl.DisplayMode[] mSfDisplayModes; @@ -765,7 +764,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { final int state, final float brightnessState, final float sdrBrightnessState, - DisplayOffloadSession displayOffloadSession) { + @Nullable DisplayOffloadSessionImpl displayOffloadSession) { // Assume that the brightness is off if the display is being turned off. assert state != Display.STATE_OFF @@ -832,25 +831,13 @@ final class LocalDisplayAdapter extends DisplayAdapter { + ", state=" + Display.stateToString(state) + ")"); } - DisplayOffloader displayOffloader = - displayOffloadSession == null - ? null - : displayOffloadSession.getDisplayOffloader(); - boolean isDisplayOffloadEnabled = mFlags.isDisplayOffloadEnabled(); // We must tell sidekick/displayoffload to stop controlling the display // before we can change its power mode, so do that first. if (isDisplayOffloadEnabled) { - if (mDisplayOffloadActive && displayOffloader != null) { - Trace.traceBegin(Trace.TRACE_TAG_POWER, - "DisplayOffloader#stopOffload"); - try { - displayOffloader.stopOffload(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_POWER); - } - mDisplayOffloadActive = false; + if (displayOffloadSession != null) { + displayOffloadSession.stopOffload(); } } else { if (mSidekickActive) { @@ -881,16 +868,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { // have a sidekick/displayoffload available, tell it now that it can take // control. if (isDisplayOffloadEnabled) { - if (DisplayOffloadSession.isSupportedOffloadState(state) && - displayOffloader != null - && !mDisplayOffloadActive) { - Trace.traceBegin( - Trace.TRACE_TAG_POWER, "DisplayOffloader#startOffload"); - try { - mDisplayOffloadActive = displayOffloader.startOffload(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_POWER); - } + if (DisplayOffloadSession.isSupportedOffloadState(state) + && displayOffloadSession != null) { + displayOffloadSession.startOffload(); } } else { if (Display.isSuspendedState(state) && state != Display.STATE_OFF diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 3d4209e0d6f3..ba321ae5d807 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -138,7 +138,7 @@ final class LogicalDisplay { private final Rect mTempDisplayRect = new Rect(); /** A session token that controls the offloading operations of this logical display. */ - private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; + private DisplayOffloadSessionImpl mDisplayOffloadSession; /** * Name of a display group to which the display is assigned. @@ -969,12 +969,11 @@ final class LogicalDisplay { return mDisplayGroupName; } - public void setDisplayOffloadSessionLocked( - DisplayManagerInternal.DisplayOffloadSession session) { + public void setDisplayOffloadSessionLocked(DisplayOffloadSessionImpl session) { mDisplayOffloadSession = session; } - public DisplayManagerInternal.DisplayOffloadSession getDisplayOffloadSessionLocked() { + public DisplayOffloadSessionImpl getDisplayOffloadSessionLocked() { return mDisplayOffloadSession; } diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 90e32a685a34..edbd42465534 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -43,7 +43,6 @@ import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; import android.annotation.Nullable; import android.content.Context; import android.graphics.Point; -import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplayConfig; import android.media.projection.IMediaProjection; @@ -380,7 +379,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { @Override public Runnable requestDisplayStateLocked(int state, float brightnessState, - float sdrBrightnessState, DisplayOffloadSession displayOffloadSession) { + float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession) { if (state != mDisplayState) { mDisplayState = state; if (state == Display.STATE_OFF) { diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java index d7ae2699ee2d..8fe5f213d766 100644 --- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java +++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java @@ -39,7 +39,8 @@ public final class BrightnessReason { public static final int REASON_BOOST = 8; public static final int REASON_SCREEN_OFF_BRIGHTNESS_SENSOR = 9; public static final int REASON_FOLLOWER = 10; - public static final int REASON_MAX = REASON_FOLLOWER; + public static final int REASON_OFFLOAD = 11; + public static final int REASON_MAX = REASON_OFFLOAD; public static final int MODIFIER_DIMMED = 0x1; public static final int MODIFIER_LOW_POWER = 0x2; @@ -196,6 +197,8 @@ public final class BrightnessReason { return "screen_off_brightness_sensor"; case REASON_FOLLOWER: return "follower"; + case REASON_OFFLOAD: + return "offload"; default: return Integer.toString(reason); } diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java index d6f0098c13cb..617befbbd17d 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java @@ -31,6 +31,7 @@ import com.android.server.display.BrightnessSetting; import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy; import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy; +import com.android.server.display.feature.DisplayManagerFlags; import java.io.PrintWriter; @@ -104,7 +105,8 @@ public final class DisplayBrightnessController { */ public DisplayBrightnessController(Context context, Injector injector, int displayId, float defaultScreenBrightness, BrightnessSetting brightnessSetting, - Runnable onBrightnessChangeRunnable, HandlerExecutor brightnessChangeExecutor) { + Runnable onBrightnessChangeRunnable, HandlerExecutor brightnessChangeExecutor, + DisplayManagerFlags flags) { if (injector == null) { injector = new Injector(); } @@ -116,7 +118,7 @@ public final class DisplayBrightnessController { mCurrentScreenBrightness = getScreenBrightnessSetting(); mOnBrightnessChangeRunnable = onBrightnessChangeRunnable; mDisplayBrightnessStrategySelector = injector.getDisplayBrightnessStrategySelector(context, - displayId); + displayId, flags); mBrightnessChangeExecutor = brightnessChangeExecutor; mPersistBrightnessNitsForDefaultDisplay = context.getResources().getBoolean( com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay); @@ -172,6 +174,18 @@ public final class DisplayBrightnessController { } /** + * Sets the brightness from the offload session. + */ + public void setBrightnessFromOffload(float brightness) { + synchronized (mLock) { + if (mDisplayBrightnessStrategySelector.getOffloadBrightnessStrategy() != null) { + mDisplayBrightnessStrategySelector.getOffloadBrightnessStrategy() + .setOffloadScreenBrightness(brightness); + } + } + } + + /** * Returns a boolean flag indicating if the light sensor is to be used to decide the screen * brightness when dozing */ @@ -423,8 +437,9 @@ public final class DisplayBrightnessController { @VisibleForTesting static class Injector { DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector(Context context, - int displayId) { - return new DisplayBrightnessStrategySelector(context, /* injector= */ null, displayId); + int displayId, DisplayManagerFlags flags) { + return new DisplayBrightnessStrategySelector(context, /* injector= */ null, displayId, + flags); } } diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java index f141c20158cd..055f94a23363 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java @@ -17,6 +17,7 @@ package com.android.server.display.brightness; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.display.DisplayManagerInternal; import android.util.IndentingPrintWriter; @@ -31,9 +32,11 @@ import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy; import com.android.server.display.brightness.strategy.DozeBrightnessStrategy; import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy; import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy; +import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy; import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy; import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy; import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy; +import com.android.server.display.feature.DisplayManagerFlags; import java.io.PrintWriter; @@ -63,6 +66,10 @@ public class DisplayBrightnessStrategySelector { private final InvalidBrightnessStrategy mInvalidBrightnessStrategy; // Controls brightness when automatic (adaptive) brightness is running. private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy; + // Controls the brightness if adaptive brightness is on and there exists an active offload + // session. Brightness value is provided by the offload session. + @Nullable + private final OffloadBrightnessStrategy mOffloadBrightnessStrategy; // We take note of the old brightness strategy so that we can know when the strategy changes. private String mOldBrightnessStrategyName; @@ -72,7 +79,8 @@ public class DisplayBrightnessStrategySelector { /** * The constructor of DozeBrightnessStrategy. */ - public DisplayBrightnessStrategySelector(Context context, Injector injector, int displayId) { + public DisplayBrightnessStrategySelector(Context context, Injector injector, int displayId, + DisplayManagerFlags flags) { if (injector == null) { injector = new Injector(); } @@ -85,6 +93,11 @@ public class DisplayBrightnessStrategySelector { mFollowerBrightnessStrategy = injector.getFollowerBrightnessStrategy(displayId); mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy(); mAutomaticBrightnessStrategy = injector.getAutomaticBrightnessStrategy(context, displayId); + if (flags.isDisplayOffloadEnabled()) { + mOffloadBrightnessStrategy = injector.getOffloadBrightnessStrategy(); + } else { + mOffloadBrightnessStrategy = null; + } mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean( R.bool.config_allowAutoBrightnessWhileDozing); mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName(); @@ -114,6 +127,9 @@ public class DisplayBrightnessStrategySelector { } else if (BrightnessUtils.isValidBrightnessValue( mTemporaryBrightnessStrategy.getTemporaryScreenBrightness())) { displayBrightnessStrategy = mTemporaryBrightnessStrategy; + } else if (mOffloadBrightnessStrategy != null && BrightnessUtils.isValidBrightnessValue( + mOffloadBrightnessStrategy.getOffloadScreenBrightness())) { + displayBrightnessStrategy = mOffloadBrightnessStrategy; } if (!mOldBrightnessStrategyName.equals(displayBrightnessStrategy.getName())) { @@ -138,6 +154,11 @@ public class DisplayBrightnessStrategySelector { return mAutomaticBrightnessStrategy; } + @Nullable + public OffloadBrightnessStrategy getOffloadBrightnessStrategy() { + return mOffloadBrightnessStrategy; + } + /** * Returns a boolean flag indicating if the light sensor is to be used to decide the screen * brightness when dozing @@ -159,6 +180,9 @@ public class DisplayBrightnessStrategySelector { + mAllowAutoBrightnessWhileDozingConfig); IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " "); mTemporaryBrightnessStrategy.dump(ipw); + if (mOffloadBrightnessStrategy != null) { + mOffloadBrightnessStrategy.dump(ipw); + } } /** @@ -210,5 +234,9 @@ public class DisplayBrightnessStrategySelector { AutomaticBrightnessStrategy getAutomaticBrightnessStrategy(Context context, int displayId) { return new AutomaticBrightnessStrategy(context, displayId); } + + OffloadBrightnessStrategy getOffloadBrightnessStrategy() { + return new OffloadBrightnessStrategy(); + } } } diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java index bcd52598edd2..3c23b5c10671 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java @@ -107,6 +107,7 @@ public class AutomaticBrightnessStrategy { mIsAutoBrightnessEnabled = shouldUseAutoBrightness() && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze) && brightnessReason != BrightnessReason.REASON_OVERRIDE + && brightnessReason != BrightnessReason.REASON_OFFLOAD && mAutomaticBrightnessController != null; mAutoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness() && !(targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze); diff --git a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java new file mode 100644 index 000000000000..55f8914e26f6 --- /dev/null +++ b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java @@ -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.server.display.brightness.strategy; + +import android.hardware.display.DisplayManagerInternal; +import android.os.PowerManager; + +import com.android.server.display.DisplayBrightnessState; +import com.android.server.display.brightness.BrightnessReason; + +import java.io.PrintWriter; + +/** + * Manages the brightness of the display when auto-brightness is on, the screen has just turned on + * and there is no available lux reading yet. The brightness value is read from the offload chip. + */ +public class OffloadBrightnessStrategy implements DisplayBrightnessStrategy { + + private float mOffloadScreenBrightness; + + public OffloadBrightnessStrategy() { + mOffloadScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; + } + + @Override + public DisplayBrightnessState updateBrightness( + DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) { + BrightnessReason brightnessReason = new BrightnessReason(); + brightnessReason.setReason(BrightnessReason.REASON_OFFLOAD); + return new DisplayBrightnessState.Builder() + .setBrightness(mOffloadScreenBrightness) + .setSdrBrightness(mOffloadScreenBrightness) + .setBrightnessReason(brightnessReason) + .setDisplayBrightnessStrategyName(getName()) + .setIsSlowChange(false) + .setShouldUpdateScreenBrightnessSetting(true) + .build(); + } + + @Override + public String getName() { + return "OffloadBrightnessStrategy"; + } + + public float getOffloadScreenBrightness() { + return mOffloadScreenBrightness; + } + + public void setOffloadScreenBrightness(float offloadScreenBrightness) { + mOffloadScreenBrightness = offloadScreenBrightness; + } + + /** + * Dumps the state of this class. + */ + public void dump(PrintWriter writer) { + writer.println("OffloadBrightnessStrategy:"); + writer.println(" mOffloadScreenBrightness:" + mOffloadScreenBrightness); + } +} diff --git a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java index 360a6a721988..6bdfae2dc02f 100644 --- a/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java +++ b/services/core/java/com/android/server/media/AudioPoliciesDeviceRouteController.java @@ -110,7 +110,7 @@ import java.util.Objects; @Override @NonNull - public synchronized MediaRoute2Info getDeviceRoute() { + public synchronized MediaRoute2Info getSelectedRoute() { if (mSelectedRoute != null) { return mSelectedRoute; } diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java index 7876095a548a..0fdaaa7604e5 100644 --- a/services/core/java/com/android/server/media/DeviceRouteController.java +++ b/services/core/java/com/android/server/media/DeviceRouteController.java @@ -72,13 +72,9 @@ import com.android.media.flags.Flags; */ boolean selectRoute(@Nullable @MediaRoute2Info.Type Integer type); - /** - * Returns currently selected device (built-in or wired) route. - * - * @return non-null device route. - */ + /** Returns the currently selected device (built-in or wired) route. */ @NonNull - MediaRoute2Info getDeviceRoute(); + MediaRoute2Info getSelectedRoute(); /** * Updates device route volume. diff --git a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java index 6ba40ae33f3c..65874e23dcdc 100644 --- a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java +++ b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java @@ -107,7 +107,7 @@ import java.util.Objects; @Override @NonNull - public synchronized MediaRoute2Info getDeviceRoute() { + public synchronized MediaRoute2Info getSelectedRoute() { return mDeviceRoute; } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index c24d6a054236..994d3ca1124f 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -76,6 +76,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; +import android.util.Slog; import android.view.KeyEvent; import com.android.server.LocalServices; @@ -348,16 +349,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } else { if (mVolumeControlType == VOLUME_CONTROL_FIXED) { if (DEBUG) { - Log.d(TAG, "Session does not support volume adjustment"); + Slog.d(TAG, "Session does not support volume adjustment"); } } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE || direction == AudioManager.ADJUST_MUTE || direction == AudioManager.ADJUST_UNMUTE) { - Log.w(TAG, "Muting remote playback is not supported"); + Slog.w(TAG, "Muting remote playback is not supported"); } else { if (DEBUG) { - Log.w(TAG, "adjusting volume, pkg=" + packageName + ", asSystemService=" - + asSystemService + ", dir=" + direction); + Slog.w( + TAG, + "adjusting volume, pkg=" + packageName + + ", asSystemService=" + asSystemService + + ", dir=" + direction); } mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction); @@ -371,8 +375,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } if (DEBUG) { - Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is " - + mMaxVolume); + Slog.d( + TAG, + "Adjusted optimistic volume to " + mOptimisticVolume + + " max is " + mMaxVolume); } } // Always notify, even if the volume hasn't changed. This is important to ensure that @@ -388,23 +394,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR if (mVolumeType == PLAYBACK_TYPE_LOCAL) { int stream = getVolumeStream(mAudioAttrs); final int volumeValue = value; - mHandler.post(new Runnable() { - @Override - public void run() { - try { - mAudioManager.setStreamVolumeForUid(stream, volumeValue, flags, - opPackageName, uid, pid, - mContext.getApplicationInfo().targetSdkVersion); - } catch (IllegalArgumentException | SecurityException e) { - Log.e(TAG, "Cannot set volume: stream=" + stream + ", value=" + volumeValue - + ", flags=" + flags, e); - } - } - }); + mHandler.post( + new Runnable() { + @Override + public void run() { + try { + mAudioManager.setStreamVolumeForUid( + stream, + volumeValue, + flags, + opPackageName, + uid, + pid, + mContext.getApplicationInfo().targetSdkVersion); + } catch (IllegalArgumentException | SecurityException e) { + Slog.e( + TAG, + "Cannot set volume: stream=" + stream + + ", value=" + volumeValue + + ", flags=" + flags, + e); + } + } + }); } else { if (mVolumeControlType != VOLUME_CONTROL_ABSOLUTE) { if (DEBUG) { - Log.d(TAG, "Session does not support setting volume"); + Slog.d(TAG, "Session does not support setting volume"); } } else { value = Math.max(0, Math.min(value, mMaxVolume)); @@ -419,8 +435,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } if (DEBUG) { - Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is " - + mMaxVolume); + Slog.d( + TAG, + "Set optimistic volume to " + mOptimisticVolume + + " max is " + mMaxVolume); } } // Always notify, even if the volume hasn't changed. @@ -528,25 +546,25 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR public boolean canHandleVolumeKey() { if (isPlaybackTypeLocal()) { if (DEBUG) { - Log.d(TAG, "Local MediaSessionRecord can handle volume key"); + Slog.d(TAG, "Local MediaSessionRecord can handle volume key"); } return true; } if (mVolumeControlType == VOLUME_CONTROL_FIXED) { if (DEBUG) { - Log.d( + Slog.d( TAG, "Local MediaSessionRecord with FIXED volume control can't handle volume" - + " key"); + + " key"); } return false; } if (mVolumeAdjustmentForRemoteGroupSessions) { if (DEBUG) { - Log.d( + Slog.d( TAG, "Volume adjustment for remote group sessions allowed so MediaSessionRecord" - + " can handle volume key"); + + " can handle volume key"); } return true; } @@ -556,7 +574,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR boolean foundNonSystemSession = false; boolean remoteSessionAllowVolumeAdjustment = true; if (DEBUG) { - Log.d( + Slog.d( TAG, "Found " + sessions.size() @@ -565,7 +583,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } for (RoutingSessionInfo session : sessions) { if (DEBUG) { - Log.d(TAG, "Found routingSessionInfo: " + session); + Slog.d(TAG, "Found routingSessionInfo: " + session); } if (!session.isSystemSession()) { foundNonSystemSession = true; @@ -576,10 +594,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } if (!foundNonSystemSession) { if (DEBUG) { - Log.d( + Slog.d( TAG, - "Package " - + mPackageName + "Package " + mPackageName + " has a remote media session but no associated routing session"); } } @@ -669,8 +686,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR final boolean asSystemService, final boolean useSuggested, final int previousFlagPlaySound) { if (DEBUG) { - Log.w(TAG, "adjusting local volume, stream=" + stream + ", dir=" + direction - + ", asSystemService=" + asSystemService + ", useSuggested=" + useSuggested); + Slog.w( + TAG, + "adjusting local volume, stream=" + stream + ", dir=" + direction + + ", asSystemService=" + asSystemService + + ", useSuggested=" + useSuggested); } // Must use opPackageName for adjusting volumes with UID. final String opPackageName; @@ -685,40 +705,61 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR uid = callingUid; pid = callingPid; } - mHandler.post(new Runnable() { - @Override - public void run() { - try { - if (useSuggested) { - if (AudioSystem.isStreamActive(stream, 0)) { - mAudioManager.adjustSuggestedStreamVolumeForUid(stream, - direction, flags, opPackageName, uid, pid, - mContext.getApplicationInfo().targetSdkVersion); - } else { - mAudioManager.adjustSuggestedStreamVolumeForUid( - AudioManager.USE_DEFAULT_STREAM_TYPE, direction, - flags | previousFlagPlaySound, opPackageName, uid, pid, - mContext.getApplicationInfo().targetSdkVersion); + mHandler.post( + new Runnable() { + @Override + public void run() { + try { + if (useSuggested) { + if (AudioSystem.isStreamActive(stream, 0)) { + mAudioManager.adjustSuggestedStreamVolumeForUid( + stream, + direction, + flags, + opPackageName, + uid, + pid, + mContext.getApplicationInfo().targetSdkVersion); + } else { + mAudioManager.adjustSuggestedStreamVolumeForUid( + AudioManager.USE_DEFAULT_STREAM_TYPE, + direction, + flags | previousFlagPlaySound, + opPackageName, + uid, + pid, + mContext.getApplicationInfo().targetSdkVersion); + } + } else { + mAudioManager.adjustStreamVolumeForUid( + stream, + direction, + flags, + opPackageName, + uid, + pid, + mContext.getApplicationInfo().targetSdkVersion); + } + } catch (IllegalArgumentException | SecurityException e) { + Slog.e( + TAG, + "Cannot adjust volume: direction=" + direction + + ", stream=" + stream + ", flags=" + flags + + ", opPackageName=" + opPackageName + ", uid=" + uid + + ", useSuggested=" + useSuggested + + ", previousFlagPlaySound=" + previousFlagPlaySound, + e); } - } else { - mAudioManager.adjustStreamVolumeForUid(stream, direction, flags, - opPackageName, uid, pid, - mContext.getApplicationInfo().targetSdkVersion); } - } catch (IllegalArgumentException | SecurityException e) { - Log.e(TAG, "Cannot adjust volume: direction=" + direction + ", stream=" - + stream + ", flags=" + flags + ", opPackageName=" + opPackageName - + ", uid=" + uid + ", useSuggested=" + useSuggested - + ", previousFlagPlaySound=" + previousFlagPlaySound, e); - } - } - }); + }); } private void logCallbackException( String msg, ISessionControllerCallbackHolder holder, Exception e) { - Log.v(TAG, msg + ", this=" + this + ", callback package=" + holder.mPackageName - + ", exception=" + e); + Slog.v( + TAG, + msg + ", this=" + this + ", callback package=" + holder.mPackageName + + ", exception=" + e); } private void pushPlaybackStateUpdate() { @@ -1115,7 +1156,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR throw new IllegalArgumentException( "The media button receiver cannot be set to an activity."); } else { - Log.w(TAG, "Ignoring invalid media button receiver targeting an activity."); + Slog.w( + TAG, + "Ignoring invalid media button receiver targeting an activity."); return; } } @@ -1151,7 +1194,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR if (CompatChanges.isChangeEnabled(THROW_FOR_INVALID_BROADCAST_RECEIVER, uid)) { throw new IllegalArgumentException("Invalid component name: " + receiver); } else { - Log.w( + Slog.w( TAG, "setMediaButtonBroadcastReceiver(): " + "Ignoring invalid component name=" @@ -1290,7 +1333,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR if (attributes != null) { mAudioAttrs = attributes; } else { - Log.e(TAG, "Received null audio attributes, using existing attributes"); + Slog.e(TAG, "Received null audio attributes, using existing attributes"); } } if (typeChanged) { @@ -1352,7 +1395,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } return true; } catch (RemoteException e) { - Log.e(TAG, "Remote failure in sendMediaRequest.", e); + Slog.e(TAG, "Remote failure in sendMediaRequest.", e); } return false; } @@ -1375,7 +1418,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } return true; } catch (RemoteException e) { - Log.e(TAG, "Remote failure in sendMediaRequest.", e); + Slog.e(TAG, "Remote failure in sendMediaRequest.", e); } return false; } @@ -1388,7 +1431,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onCommand(packageName, pid, uid, command, args, cb); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in sendCommand.", e); + Slog.e(TAG, "Remote failure in sendCommand.", e); } } @@ -1400,7 +1443,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onCustomAction(packageName, pid, uid, action, args); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in sendCustomAction.", e); + Slog.e(TAG, "Remote failure in sendCustomAction.", e); } } @@ -1411,7 +1454,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPrepare(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in prepare.", e); + Slog.e(TAG, "Remote failure in prepare.", e); } } @@ -1423,7 +1466,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in prepareFromMediaId.", e); + Slog.e(TAG, "Remote failure in prepareFromMediaId.", e); } } @@ -1435,7 +1478,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPrepareFromSearch(packageName, pid, uid, query, extras); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in prepareFromSearch.", e); + Slog.e(TAG, "Remote failure in prepareFromSearch.", e); } } @@ -1446,7 +1489,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPrepareFromUri(packageName, pid, uid, uri, extras); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in prepareFromUri.", e); + Slog.e(TAG, "Remote failure in prepareFromUri.", e); } } @@ -1457,7 +1500,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPlay(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in play.", e); + Slog.e(TAG, "Remote failure in play.", e); } } @@ -1469,7 +1512,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in playFromMediaId.", e); + Slog.e(TAG, "Remote failure in playFromMediaId.", e); } } @@ -1481,7 +1524,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPlayFromSearch(packageName, pid, uid, query, extras); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in playFromSearch.", e); + Slog.e(TAG, "Remote failure in playFromSearch.", e); } } @@ -1492,7 +1535,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPlayFromUri(packageName, pid, uid, uri, extras); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in playFromUri.", e); + Slog.e(TAG, "Remote failure in playFromUri.", e); } } @@ -1503,7 +1546,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onSkipToTrack(packageName, pid, uid, id); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in skipToTrack", e); + Slog.e(TAG, "Remote failure in skipToTrack", e); } } @@ -1514,7 +1557,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPause(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in pause.", e); + Slog.e(TAG, "Remote failure in pause.", e); } } @@ -1525,7 +1568,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onStop(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in stop.", e); + Slog.e(TAG, "Remote failure in stop.", e); } } @@ -1536,7 +1579,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onNext(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in next.", e); + Slog.e(TAG, "Remote failure in next.", e); } } @@ -1547,7 +1590,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onPrevious(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in previous.", e); + Slog.e(TAG, "Remote failure in previous.", e); } } @@ -1558,7 +1601,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onFastForward(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in fastForward.", e); + Slog.e(TAG, "Remote failure in fastForward.", e); } } @@ -1569,7 +1612,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onRewind(packageName, pid, uid); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in rewind.", e); + Slog.e(TAG, "Remote failure in rewind.", e); } } @@ -1580,7 +1623,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onSeekTo(packageName, pid, uid, pos); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in seekTo.", e); + Slog.e(TAG, "Remote failure in seekTo.", e); } } @@ -1591,7 +1634,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onRate(packageName, pid, uid, rating); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in rate.", e); + Slog.e(TAG, "Remote failure in rate.", e); } } @@ -1602,7 +1645,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onSetPlaybackSpeed(packageName, pid, uid, speed); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in setPlaybackSpeed.", e); + Slog.e(TAG, "Remote failure in setPlaybackSpeed.", e); } } @@ -1619,7 +1662,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR mCb.onAdjustVolume(packageName, pid, uid, direction); } } catch (RemoteException e) { - Log.e(TAG, "Remote failure in adjustVolume.", e); + Slog.e(TAG, "Remote failure in adjustVolume.", e); } } @@ -1630,7 +1673,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR pid, uid, packageName, reason); mCb.onSetVolumeTo(packageName, pid, uid, value); } catch (RemoteException e) { - Log.e(TAG, "Remote failure in setVolumeTo.", e); + Slog.e(TAG, "Remote failure in setVolumeTo.", e); } } @@ -1673,8 +1716,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR cb, packageName, Binder.getCallingUid(), () -> unregisterCallback(cb)); mControllerCallbackHolders.add(holder); if (DEBUG) { - Log.d(TAG, "registering controller callback " + cb + " from controller" - + packageName); + Slog.d( + TAG, + "registering controller callback " + cb + + " from controller" + packageName); } // Avoid callback leaks try { @@ -1683,7 +1728,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR cb.asBinder().linkToDeath(holder.mDeathMonitor, 0); } catch (RemoteException e) { unregisterCallback(cb); - Log.w(TAG, "registerCallback failed to linkToDeath", e); + Slog.w(TAG, "registerCallback failed to linkToDeath", e); } } } @@ -1698,12 +1743,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR cb.asBinder().unlinkToDeath( mControllerCallbackHolders.get(index).mDeathMonitor, 0); } catch (NoSuchElementException e) { - Log.w(TAG, "error unlinking to binder death", e); + Slog.w(TAG, "error unlinking to binder death", e); } mControllerCallbackHolders.remove(index); } if (DEBUG) { - Log.d(TAG, "unregistering callback " + cb.asBinder()); + Slog.d(TAG, "unregistering callback " + cb.asBinder()); } } } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 78077a831622..c8dba800a017 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -228,8 +228,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { return; } - MediaRoute2Info deviceRoute = mDeviceRouteController.getDeviceRoute(); - if (TextUtils.equals(routeId, deviceRoute.getId())) { + MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute(); + if (TextUtils.equals(routeId, selectedDeviceRoute.getId())) { mBluetoothRouteController.transferTo(null); } else { mBluetoothRouteController.transferTo(routeId); @@ -278,11 +278,11 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { return null; } - MediaRoute2Info deviceRoute = mDeviceRouteController.getDeviceRoute(); + MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute(); RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( SYSTEM_SESSION_ID, packageName).setSystemSession(true); - builder.addSelectedRoute(deviceRoute.getId()); + builder.addSelectedRoute(selectedDeviceRoute.getId()); for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) { builder.addTransferableRoute(route.getId()); } @@ -314,7 +314,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); // We must have a device route in the provider info. - builder.addRoute(mDeviceRouteController.getDeviceRoute()); + builder.addRoute(mDeviceRouteController.getSelectedRoute()); for (MediaRoute2Info route : mBluetoothRouteController.getAllBluetoothRoutes()) { builder.addRoute(route); @@ -338,12 +338,12 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { SYSTEM_SESSION_ID, "" /* clientPackageName */) .setSystemSession(true); - MediaRoute2Info deviceRoute = mDeviceRouteController.getDeviceRoute(); - MediaRoute2Info selectedRoute = deviceRoute; + MediaRoute2Info selectedDeviceRoute = mDeviceRouteController.getSelectedRoute(); + MediaRoute2Info selectedRoute = selectedDeviceRoute; MediaRoute2Info selectedBtRoute = mBluetoothRouteController.getSelectedRoute(); if (selectedBtRoute != null) { selectedRoute = selectedBtRoute; - builder.addTransferableRoute(deviceRoute.getId()); + builder.addTransferableRoute(selectedDeviceRoute.getId()); } mSelectedRouteId = selectedRoute.getId(); mDefaultRoute = diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index d38c0a0920b1..47d1df5df1c0 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -3586,21 +3586,30 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { params.setDontKillApp(false); } + boolean existingSplitReplacedOrRemoved = false; // Inherit splits if not overridden. if (!ArrayUtils.isEmpty(existing.getSplitNames())) { for (int i = 0; i < existing.getSplitNames().length; i++) { final String splitName = existing.getSplitNames()[i]; final File splitFile = new File(existing.getSplitApkPaths()[i]); final boolean splitRemoved = removeSplitList.contains(splitName); - if (!stagedSplits.contains(splitName) && !splitRemoved) { + final boolean splitReplaced = stagedSplits.contains(splitName); + if (!splitReplaced && !splitRemoved) { inheritFileLocked(splitFile); // Collect the requiredSplitTypes and staged splitTypes from splits CollectionUtils.addAll(requiredSplitTypes, existing.getRequiredSplitTypes()[i]); CollectionUtils.addAll(stagedSplitTypes, existing.getSplitTypes()[i]); + } else { + existingSplitReplacedOrRemoved = true; } } } + if (existingSplitReplacedOrRemoved + && (params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) { + // Some splits are being replaced or removed. Make sure the app is restarted. + params.setDontKillApp(false); + } // Inherit compiled oat directory. final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile(); 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 17499bb77239..940feb580a96 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -24,12 +24,14 @@ import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_PASSTHROUGH; import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_UNSUPPORTED; import static android.hardware.graphics.common.Hdr.DOLBY_VISION; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkTemplate.MATCH_ETHERNET; import static android.net.NetworkTemplate.MATCH_MOBILE; +import static android.net.NetworkTemplate.MATCH_PROXY; import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.OEM_MANAGED_ALL; import static android.net.NetworkTemplate.OEM_MANAGED_PAID; @@ -488,6 +490,7 @@ public class StatsPullAtomService extends SystemService { case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: case FrameworkStatsLog.MOBILE_BYTES_TRANSFER: case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: + case FrameworkStatsLog.PROXY_BYTES_TRANSFER_BY_FG_BG: case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER: case FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER: @@ -973,21 +976,33 @@ public class StatsPullAtomService extends SystemService { if (DEBUG) { Slog.d(TAG, "Registering NetworkStats pullers with statsd"); } + + boolean canQueryTypeProxy = canQueryNetworkStatsForTypeProxy(); + // Initialize NetworkStats baselines. - mNetworkStatsBaselines.addAll( - collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.WIFI_BYTES_TRANSFER)); - mNetworkStatsBaselines.addAll( - collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG)); - mNetworkStatsBaselines.addAll( - collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.MOBILE_BYTES_TRANSFER)); - mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom( - FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG)); - mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom( - FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED)); - mNetworkStatsBaselines.addAll( - collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER)); - mNetworkStatsBaselines.addAll( - collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER)); + synchronized (mDataBytesTransferLock) { + mNetworkStatsBaselines.addAll( + collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.WIFI_BYTES_TRANSFER)); + mNetworkStatsBaselines.addAll( + collectNetworkStatsSnapshotForAtom( + FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG)); + mNetworkStatsBaselines.addAll( + collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.MOBILE_BYTES_TRANSFER)); + mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom( + FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG)); + mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom( + FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED)); + mNetworkStatsBaselines.addAll( + collectNetworkStatsSnapshotForAtom( + FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER)); + mNetworkStatsBaselines.addAll( + collectNetworkStatsSnapshotForAtom( + FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER)); + if (canQueryTypeProxy) { + mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom( + FrameworkStatsLog.PROXY_BYTES_TRANSFER_BY_FG_BG)); + } + } // Listen to subscription changes to record historical subscriptions that activated before // pulling, this is used by {@code DATA_USAGE_BYTES_TRANSFER}. @@ -1001,6 +1016,9 @@ public class StatsPullAtomService extends SystemService { registerBytesTransferByTagAndMetered(); registerDataUsageBytesTransfer(); registerOemManagedBytesTransfer(); + if (canQueryTypeProxy) { + registerProxyBytesTransferBackground(); + } } private void initAndRegisterDeferredPullers() { @@ -1171,6 +1189,18 @@ public class StatsPullAtomService extends SystemService { } break; } + case FrameworkStatsLog.PROXY_BYTES_TRANSFER_BY_FG_BG: { + final NetworkStats stats = getUidNetworkStatsSnapshotForTemplate( + new NetworkTemplate.Builder(MATCH_PROXY).build(), /*includeTags=*/true); + if (stats != null) { + ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats), + new int[]{TRANSPORT_BLUETOOTH}, + /*slicedByFgbg=*/true, /*slicedByTag=*/false, + /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN, + /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/true)); + } + break; + } case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: { final NetworkStats wifiStats = getUidNetworkStatsSnapshotForTemplate( new NetworkTemplate.Builder(MATCH_WIFI).build(), /*includeTags=*/true); @@ -1183,7 +1213,7 @@ public class StatsPullAtomService extends SystemService { new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false, /*slicedByTag=*/true, /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN, - /*subInfo=*/null, OEM_MANAGED_ALL)); + /*subInfo=*/null, OEM_MANAGED_ALL, /*isTypeProxy=*/false)); } break; } @@ -1225,7 +1255,7 @@ public class StatsPullAtomService extends SystemService { final NetworkStatsExt diff = new NetworkStatsExt( removeEmptyEntries(item.stats.subtract(baseline.stats)), item.transports, item.slicedByFgbg, item.slicedByTag, item.slicedByMetered, item.ratType, - item.subInfo, item.oemManaged); + item.subInfo, item.oemManaged, item.isTypeProxy); // If no diff, skip. if (!diff.stats.iterator().hasNext()) continue; @@ -1363,7 +1393,7 @@ public class StatsPullAtomService extends SystemService { ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats), new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false, /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN, - /*subInfo=*/null, oemManaged)); + /*subInfo=*/null, oemManaged, /*isTypeProxy=*/false)); } } } @@ -1392,6 +1422,21 @@ public class StatsPullAtomService extends SystemService { } /** + * Check if it is possible to query NetworkStats for TYPE_PROXY. This should only be possible + * if the build includes r.android.com/2828315 + * @return true if querying for TYPE_PROXY is allowed + */ + private static boolean canQueryNetworkStatsForTypeProxy() { + try { + new NetworkTemplate.Builder(MATCH_PROXY).build(); + return true; + } catch (IllegalArgumentException e) { + Slog.w(TAG, "Querying network stats for TYPE_PROXY is not allowed"); + return false; + } + } + + /** * Create a snapshot of NetworkStats since boot for the given template, but add 1 bucket * duration before boot as a buffer to ensure at least one full bucket will be included. * Note that this should be only used to calculate diff since the snapshot might contains @@ -1450,7 +1495,7 @@ public class StatsPullAtomService extends SystemService { ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats), new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true, /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo, - OEM_MANAGED_ALL)); + OEM_MANAGED_ALL, /*isTypeProxy=*/false)); } } return ret; @@ -1600,6 +1645,19 @@ public class StatsPullAtomService extends SystemService { ); } + private void registerProxyBytesTransferBackground() { + int tagId = FrameworkStatsLog.PROXY_BYTES_TRANSFER_BY_FG_BG; + PullAtomMetadata metadata = new PullAtomMetadata.Builder() + .setAdditiveFields(new int[]{3, 4, 5, 6}) + .build(); + mStatsManager.setPullAtomCallback( + tagId, + metadata, + DIRECT_EXECUTOR, + mStatsCallbackImpl + ); + } + private void registerBytesTransferByTagAndMetered() { int tagId = FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED; PullAtomMetadata metadata = new PullAtomMetadata.Builder() diff --git a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java index 7dbba0d4337d..512f0bf7ff98 100644 --- a/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java +++ b/services/core/java/com/android/server/stats/pull/netstats/NetworkStatsExt.java @@ -42,15 +42,17 @@ public class NetworkStatsExt { public final int oemManaged; @Nullable public final SubInfo subInfo; + public final boolean isTypeProxy; // True if matching ConnectivityManager#TYPE_PROXY public NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg) { this(stats, transports, slicedByFgbg, /*slicedByTag=*/false, /*slicedByMetered=*/false, - TelephonyManager.NETWORK_TYPE_UNKNOWN, /*subInfo=*/null, OEM_MANAGED_ALL); + TelephonyManager.NETWORK_TYPE_UNKNOWN, /*subInfo=*/null, + OEM_MANAGED_ALL, /*isTypeProxy=*/false); } public NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg, boolean slicedByTag, boolean slicedByMetered, int ratType, - @Nullable SubInfo subInfo, int oemManaged) { + @Nullable SubInfo subInfo, int oemManaged, boolean isTypeProxy) { this.stats = stats; // Sort transports array so that we can test for equality without considering order. @@ -63,6 +65,7 @@ public class NetworkStatsExt { this.ratType = ratType; this.subInfo = subInfo; this.oemManaged = oemManaged; + this.isTypeProxy = isTypeProxy; } /** @@ -72,6 +75,6 @@ public class NetworkStatsExt { return Arrays.equals(transports, other.transports) && slicedByFgbg == other.slicedByFgbg && slicedByTag == other.slicedByTag && slicedByMetered == other.slicedByMetered && ratType == other.ratType && Objects.equals(subInfo, other.subInfo) - && oemManaged == other.oemManaged; + && oemManaged == other.oemManaged && isTypeProxy == other.isTypeProxy; } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index a9f11e488881..34c7eee45f34 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -281,6 +281,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; +import com.android.wm.shell.Flags; import java.io.BufferedReader; import java.io.File; @@ -316,8 +317,6 @@ import java.util.Set; public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private static final String GRAMMATICAL_GENDER_PROPERTY = "persist.sys.grammatical_gender"; private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_ATM; - private static final String ENABLE_PIP2_IMPLEMENTATION = - "persist.wm.debug.enable_pip2_implementation"; static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK; static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; @@ -7262,6 +7261,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } static boolean isPip2ExperimentEnabled() { - return SystemProperties.getBoolean(ENABLE_PIP2_IMPLEMENTATION, false); + return Flags.enablePip2Implementation(); } } diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 287aaf9da42a..8cc197c2f3d0 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -46,7 +46,6 @@ import android.app.BackgroundStartPrivileges; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; -import android.compat.annotation.Overridable; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; @@ -88,7 +87,6 @@ public class BackgroundActivityStartController { /** If enabled the creator will not allow BAL on its behalf by default. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) - @Overridable private static final long DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_CREATOR = 296478951; public static final ActivityOptions ACTIVITY_OPTIONS_SYSTEM_DEFINED = diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index d0d7f493b969..e6bbd52807bd 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -101,10 +101,8 @@ class InsetsPolicy { mPolicy = displayContent.getDisplayPolicy(); final Resources r = mPolicy.getContext().getResources(); mHideNavBarForKeyboard = r.getBoolean(R.bool.config_hideNavBarForKeyboard); - mTransientControlTarget = new ControlTarget( - stateController, displayContent.mWmService.mH, "TransientControlTarget"); - mPermanentControlTarget = new ControlTarget( - stateController, displayContent.mWmService.mH, "PermanentControlTarget"); + mTransientControlTarget = new ControlTarget(displayContent, "TransientControlTarget"); + mPermanentControlTarget = new ControlTarget(displayContent, "PermanentControlTarget"); } /** Updates the target which can control system bars. */ @@ -699,24 +697,35 @@ class InsetsPolicy { } } - private static class ControlTarget implements InsetsControlTarget { + private static class ControlTarget implements InsetsControlTarget, Runnable { + private final Handler mHandler; + private final Object mGlobalLock; private final InsetsState mState = new InsetsState(); - private final InsetsController mInsetsController; private final InsetsStateController mStateController; + private final InsetsController mInsetsController; private final String mName; - ControlTarget(InsetsStateController stateController, Handler handler, String name) { - mStateController = stateController; - mInsetsController = new InsetsController(new Host(handler, name)); + ControlTarget(DisplayContent displayContent, String name) { + mHandler = displayContent.mWmService.mH; + mGlobalLock = displayContent.mWmService.mGlobalLock; + mStateController = displayContent.getInsetsStateController(); + mInsetsController = new InsetsController(new Host(mHandler, name)); mName = name; } @Override public void notifyInsetsControlChanged() { - mState.set(mStateController.getRawInsetsState(), true /* copySources */); - mInsetsController.onStateChanged(mState); - mInsetsController.onControlsChanged(mStateController.getControlsForDispatch(this)); + mHandler.post(this); + } + + @Override + public void run() { + synchronized (mGlobalLock) { + mState.set(mStateController.getRawInsetsState(), true /* copySources */); + mInsetsController.onStateChanged(mState); + mInsetsController.onControlsChanged(mStateController.getControlsForDispatch(this)); + } } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerFlags.java b/services/core/java/com/android/server/wm/WindowManagerFlags.java index b3a36501b7cf..89a70e502415 100644 --- a/services/core/java/com/android/server/wm/WindowManagerFlags.java +++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java @@ -43,8 +43,6 @@ class WindowManagerFlags { /* Start Available Flags */ - final boolean mSyncWindowConfigUpdateFlag = Flags.syncWindowConfigUpdateFlag(); - final boolean mWindowStateResizeItemFlag = Flags.windowStateResizeItemFlag(); final boolean mWallpaperOffsetAsync = Flags.wallpaperOffsetAsync(); diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml index 6c24d6d6e5a6..820628c98dee 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml @@ -21,8 +21,8 @@ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="install-arg" value="-t" /> - <option name="test-file-name" value="FrameworksImeTests.apk" /> <option name="test-file-name" value="SimpleTestIme.apk" /> + <option name="test-file-name" value="FrameworksImeTests.apk" /> </target_preparer> <option name="test-tag" value="FrameworksImeTests" /> diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java index a400f1243afb..eb6e8b4469f0 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayBrightnessStateTest.java @@ -44,6 +44,7 @@ public class DisplayBrightnessStateTest { float brightness = 0.3f; float sdrBrightness = 0.2f; boolean shouldUseAutoBrightness = true; + boolean shouldUpdateScreenBrightnessSetting = true; BrightnessReason brightnessReason = new BrightnessReason(); brightnessReason.setReason(BrightnessReason.REASON_AUTOMATIC); brightnessReason.setModifier(BrightnessReason.MODIFIER_DIMMED); @@ -52,12 +53,15 @@ public class DisplayBrightnessStateTest { .setSdrBrightness(sdrBrightness) .setBrightnessReason(brightnessReason) .setShouldUseAutoBrightness(shouldUseAutoBrightness) + .setShouldUpdateScreenBrightnessSetting(shouldUpdateScreenBrightnessSetting) .build(); assertEquals(displayBrightnessState.getBrightness(), brightness, FLOAT_DELTA); assertEquals(displayBrightnessState.getSdrBrightness(), sdrBrightness, FLOAT_DELTA); assertEquals(displayBrightnessState.getBrightnessReason(), brightnessReason); assertEquals(displayBrightnessState.getShouldUseAutoBrightness(), shouldUseAutoBrightness); + assertEquals(shouldUpdateScreenBrightnessSetting, + displayBrightnessState.shouldUpdateScreenBrightnessSetting()); assertEquals(displayBrightnessState.toString(), getString(displayBrightnessState)); } @@ -71,6 +75,7 @@ public class DisplayBrightnessStateTest { .setBrightness(0.26f) .setSdrBrightness(0.23f) .setShouldUseAutoBrightness(false) + .setShouldUpdateScreenBrightnessSetting(true) .build(); DisplayBrightnessState state2 = DisplayBrightnessState.Builder.from(state1).build(); assertEquals(state1, state2); @@ -92,7 +97,9 @@ public class DisplayBrightnessStateTest { .append("\n maxBrightness:") .append(displayBrightnessState.getMaxBrightness()) .append("\n customAnimationRate:") - .append(displayBrightnessState.getCustomAnimationRate()); + .append(displayBrightnessState.getCustomAnimationRate()) + .append("\n shouldUpdateScreenBrightnessSetting:") + .append(displayBrightnessState.shouldUpdateScreenBrightnessSetting()); return sb.toString(); } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index 0bf46547ce1e..353a7bb580ec 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -2754,8 +2754,7 @@ public class DisplayManagerServiceTest { DisplayOffloader mockDisplayOffloader = mock(DisplayOffloader.class); localService.registerDisplayOffloader(displayId, mockDisplayOffloader); - assertThat(display.getDisplayOffloadSessionLocked().getDisplayOffloader()).isEqualTo( - mockDisplayOffloader); + assertThat(display.getDisplayOffloadSessionLocked()).isNotNull(); } @Test diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayOffloadSessionImplTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayOffloadSessionImplTest.java new file mode 100644 index 000000000000..dea838d3763d --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayOffloadSessionImplTest.java @@ -0,0 +1,91 @@ +/* + * 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.display; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.display.DisplayManagerInternal; +import android.os.PowerManager; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class DisplayOffloadSessionImplTest { + + @Mock + private DisplayManagerInternal.DisplayOffloader mDisplayOffloader; + + @Mock + private DisplayPowerControllerInterface mDisplayPowerController; + + private DisplayOffloadSessionImpl mSession; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mDisplayOffloader.startOffload()).thenReturn(true); + mSession = new DisplayOffloadSessionImpl(mDisplayOffloader, mDisplayPowerController); + } + + @Test + public void testStartOffload() { + mSession.startOffload(); + assertTrue(mSession.isActive()); + + // An active session shouldn't be started again + mSession.startOffload(); + verify(mDisplayOffloader, times(1)).startOffload(); + } + + @Test + public void testStopOffload() { + mSession.startOffload(); + mSession.stopOffload(); + + assertFalse(mSession.isActive()); + verify(mDisplayPowerController).setBrightnessFromOffload( + PowerManager.BRIGHTNESS_INVALID_FLOAT); + + // An inactive session shouldn't be stopped again + mSession.stopOffload(); + verify(mDisplayOffloader, times(1)).stopOffload(); + } + + @Test + public void testUpdateBrightness_sessionInactive() { + mSession.updateBrightness(0.3f); + verify(mDisplayPowerController, never()).setBrightnessFromOffload(anyFloat()); + } + + @Test + public void testUpdateBrightness_sessionActive() { + float brightness = 0.3f; + + mSession.startOffload(); + mSession.updateBrightness(brightness); + + verify(mDisplayPowerController).setBrightnessFromOffload(brightness); + } +} 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 57f392a5887f..693cafefa2c0 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java @@ -127,8 +127,6 @@ public final class DisplayPowerController2Test { private Handler mHandler; private DisplayPowerControllerHolder mHolder; private Sensor mProxSensor; - private DisplayManagerInternal.DisplayOffloader mDisplayOffloader; - private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; @Mock private DisplayPowerCallbacks mDisplayPowerCallbacksMock; @@ -148,6 +146,8 @@ public final class DisplayPowerController2Test { private DisplayWhiteBalanceController mDisplayWhiteBalanceControllerMock; @Mock private DisplayManagerFlags mDisplayManagerFlagsMock; + @Mock + private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; @@ -1160,19 +1160,19 @@ public final class DisplayPowerController2Test { any(AutomaticBrightnessController.Callbacks.class), any(Looper.class), eq(mSensorManagerMock), - any(), + /* lightSensor= */ any(), eq(mHolder.brightnessMappingStrategy), - anyInt(), - anyFloat(), - anyFloat(), - anyFloat(), - anyInt(), - anyInt(), - anyLong(), - anyLong(), - anyLong(), - anyLong(), - anyBoolean(), + /* lightSensorWarmUpTime= */ anyInt(), + /* brightnessMin= */ anyFloat(), + /* brightnessMax= */ anyFloat(), + /* dozeScaleFactor */ anyFloat(), + /* lightSensorRate= */ anyInt(), + /* initialLightSensorRate= */ anyInt(), + /* brighteningLightDebounceConfig */ anyLong(), + /* darkeningLightDebounceConfig */ anyLong(), + /* brighteningLightDebounceConfigIdle= */ anyLong(), + /* darkeningLightDebounceConfigIdle= */ anyLong(), + /* resetAmbientLuxAfterWarmUpConfig= */ anyBoolean(), any(HysteresisLevels.class), any(HysteresisLevels.class), any(HysteresisLevels.class), @@ -1180,9 +1180,9 @@ public final class DisplayPowerController2Test { eq(mContext), any(BrightnessRangeController.class), any(BrightnessThrottler.class), - isNull(), - anyInt(), - anyInt(), + /* idleModeBrightnessMapper= */ isNull(), + /* ambientLightHorizonShort= */ anyInt(), + /* ambientLightHorizonLong= */ anyInt(), eq(lux), eq(brightness) ); @@ -1294,9 +1294,8 @@ public final class DisplayPowerController2Test { public void testRampRateForHdrContent_HdrClamperOn() { float clampedBrightness = 0.6f; float transitionRate = 1.5f; - DisplayManagerFlags flags = mock(DisplayManagerFlags.class); - when(flags.isHdrClamperEnabled()).thenReturn(true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true, flags); + when(mDisplayManagerFlagsMock.isHdrClamperEnabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); DisplayPowerRequest dpr = new DisplayPowerRequest(); when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); @@ -1392,9 +1391,8 @@ public final class DisplayPowerController2Test { @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) public void testRampMaxTimeInteractiveThenIdle_DifferentValues() { - DisplayManagerFlags flags = mock(DisplayManagerFlags.class); - when(flags.isAdaptiveTone1Enabled()).thenReturn(true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true, flags); + when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); // Send a display power request DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -1447,9 +1445,8 @@ public final class DisplayPowerController2Test { @Test @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) public void testRampMaxTimeIdle_DifferentValues() { - DisplayManagerFlags flags = mock(DisplayManagerFlags.class); - when(flags.isAdaptiveTone1Enabled()).thenReturn(true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true, flags); + when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); // Send a display power request DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -1481,8 +1478,6 @@ public final class DisplayPowerController2Test { when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); return null; }).when(mHolder.displayPowerState).setScreenState(anyInt()); - // init displayoffload session and support offloading. - initDisplayOffloadSession(); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); // start with DOZE. @@ -1509,8 +1504,6 @@ public final class DisplayPowerController2Test { when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); return null; }).when(mHolder.displayPowerState).setScreenState(anyInt()); - // init displayoffload session and support offloading. - initDisplayOffloadSession(); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); // start with DOZE. @@ -1536,8 +1529,6 @@ public final class DisplayPowerController2Test { when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); return null; }).when(mHolder.displayPowerState).setScreenState(anyInt()); - // init displayoffload session and support offloading. - initDisplayOffloadSession(); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); // start with OFF. @@ -1553,26 +1544,29 @@ public final class DisplayPowerController2Test { verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); } - private void initDisplayOffloadSession() { - mDisplayOffloader = spy(new DisplayManagerInternal.DisplayOffloader() { - @Override - public boolean startOffload() { - return true; - } - - @Override - public void stopOffload() {} - }); - - mDisplayOffloadSession = new DisplayManagerInternal.DisplayOffloadSession() { - @Override - public void setDozeStateOverride(int displayState) {} - - @Override - public DisplayManagerInternal.DisplayOffloader getDisplayOffloader() { - return mDisplayOffloader; - } - }; + @Test + public void testBrightnessFromOffload() { + when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + float brightness = 0.34f; + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); + + mHolder.dpc.setBrightnessFromOffload(brightness); + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + // One triggered by handleBrightnessModeChange, another triggered by + // setBrightnessFromOffload + verify(mHolder.animator, times(2)).animateTo(eq(brightness), anyFloat(), + eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); } /** @@ -1659,12 +1653,6 @@ public final class DisplayPowerController2Test { private DisplayPowerControllerHolder createDisplayPowerController(int displayId, String uniqueId, boolean isEnabled) { - return createDisplayPowerController(displayId, uniqueId, isEnabled, - mock(DisplayManagerFlags.class)); - } - - private DisplayPowerControllerHolder createDisplayPowerController(int displayId, - String uniqueId, boolean isEnabled, DisplayManagerFlags flags) { final DisplayPowerState displayPowerState = mock(DisplayPowerState.class); final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class); final AutomaticBrightnessController automaticBrightnessController = @@ -1690,7 +1678,7 @@ public final class DisplayPowerController2Test { TestInjector injector = spy(new TestInjector(displayPowerState, animator, automaticBrightnessController, wakelockController, brightnessMappingStrategy, hysteresisLevels, screenOffBrightnessSensorController, hbmController, hdrClamper, - clamperController, flags)); + clamperController, mDisplayManagerFlagsMock)); final LogicalDisplay display = mock(LogicalDisplay.class); final DisplayDevice device = mock(DisplayDevice.class); @@ -1705,7 +1693,7 @@ public final class DisplayPowerController2Test { mSensorManagerMock, mDisplayBlankerMock, display, mBrightnessTrackerMock, brightnessSetting, () -> { }, - hbmMetadata, /* bootCompleted= */ false, flags); + hbmMetadata, /* bootCompleted= */ false, mDisplayManagerFlagsMock); return new DisplayPowerControllerHolder(dpc, display, displayPowerState, brightnessSetting, animator, automaticBrightnessController, wakelockController, 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 9617bd08fd93..b22799377872 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -125,8 +125,6 @@ public final class DisplayPowerControllerTest { private Handler mHandler; private DisplayPowerControllerHolder mHolder; private Sensor mProxSensor; - private DisplayManagerInternal.DisplayOffloader mDisplayOffloader; - private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; @Mock private DisplayPowerCallbacks mDisplayPowerCallbacksMock; @@ -146,6 +144,8 @@ public final class DisplayPowerControllerTest { private DisplayWhiteBalanceController mDisplayWhiteBalanceControllerMock; @Mock private DisplayManagerFlags mDisplayManagerFlagsMock; + @Mock + private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; @@ -1094,19 +1094,19 @@ public final class DisplayPowerControllerTest { any(AutomaticBrightnessController.Callbacks.class), any(Looper.class), eq(mSensorManagerMock), - any(), + /* lightSensor= */ any(), eq(mHolder.brightnessMappingStrategy), - anyInt(), - anyFloat(), - anyFloat(), - anyFloat(), - anyInt(), - anyInt(), - anyLong(), - anyLong(), - anyLong(), - anyLong(), - anyBoolean(), + /* lightSensorWarmUpTime= */ anyInt(), + /* brightnessMin= */ anyFloat(), + /* brightnessMax= */ anyFloat(), + /* dozeScaleFactor */ anyFloat(), + /* lightSensorRate= */ anyInt(), + /* initialLightSensorRate= */ anyInt(), + /* brighteningLightDebounceConfig */ anyLong(), + /* darkeningLightDebounceConfig */ anyLong(), + /* brighteningLightDebounceConfigIdle= */ anyLong(), + /* darkeningLightDebounceConfigIdle= */ anyLong(), + /* resetAmbientLuxAfterWarmUpConfig= */ anyBoolean(), any(HysteresisLevels.class), any(HysteresisLevels.class), any(HysteresisLevels.class), @@ -1114,9 +1114,9 @@ public final class DisplayPowerControllerTest { eq(mContext), any(BrightnessRangeController.class), any(BrightnessThrottler.class), - isNull(), - anyInt(), - anyInt(), + /* idleModeBrightnessMapper= */ isNull(), + /* ambientLightHorizonShort= */ anyInt(), + /* ambientLightHorizonLong= */ anyInt(), eq(lux), eq(brightness) ); @@ -1386,8 +1386,6 @@ public final class DisplayPowerControllerTest { when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); return null; }).when(mHolder.displayPowerState).setScreenState(anyInt()); - // init displayoffload session and support offloading. - initDisplayOffloadSession(); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); // start with DOZE. @@ -1414,8 +1412,6 @@ public final class DisplayPowerControllerTest { when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); return null; }).when(mHolder.displayPowerState).setScreenState(anyInt()); - // init displayoffload session and support offloading. - initDisplayOffloadSession(); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); // start with DOZE. @@ -1441,8 +1437,6 @@ public final class DisplayPowerControllerTest { when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); return null; }).when(mHolder.displayPowerState).setScreenState(anyInt()); - // init displayoffload session and support offloading. - initDisplayOffloadSession(); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); // start with OFF. @@ -1458,28 +1452,6 @@ public final class DisplayPowerControllerTest { verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); } - private void initDisplayOffloadSession() { - mDisplayOffloader = spy(new DisplayManagerInternal.DisplayOffloader() { - @Override - public boolean startOffload() { - return true; - } - - @Override - public void stopOffload() {} - }); - - mDisplayOffloadSession = new DisplayManagerInternal.DisplayOffloadSession() { - @Override - public void setDozeStateOverride(int displayState) {} - - @Override - public DisplayManagerInternal.DisplayOffloader getDisplayOffloader() { - return mDisplayOffloader; - } - }; - } - private void advanceTime(long timeMs) { mClock.fastForward(timeMs); mTestLooper.dispatchAll(); diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java index a77a9586fb43..8270845657c6 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -40,12 +41,12 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; -import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; import android.hardware.display.DisplayManagerInternal.DisplayOffloader; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.PowerManager; import android.view.Display; import android.view.DisplayAddress; import android.view.SurfaceControl; @@ -118,10 +119,12 @@ public class LocalDisplayAdapterTest { private DisplayNotificationManager mMockedDisplayNotificationManager; @Mock private DisplayManagerFlags mFlags; + @Mock + private DisplayPowerControllerInterface mMockedDisplayPowerController; private Handler mHandler; - private DisplayOffloadSession mDisplayOffloadSession; + private DisplayOffloadSessionImpl mDisplayOffloadSession; private DisplayOffloader mDisplayOffloader; @@ -1195,6 +1198,7 @@ public class LocalDisplayAdapterTest { } verify(mDisplayOffloader, times(mDisplayOffloadSupportedStates.size())).startOffload(); + assertTrue(mDisplayOffloadSession.isActive()); } @Test @@ -1217,6 +1221,9 @@ public class LocalDisplayAdapterTest { changeStateToDozeRunnable.run(); verify(mDisplayOffloader).stopOffload(); + assertFalse(mDisplayOffloadSession.isActive()); + verify(mMockedDisplayPowerController).setBrightnessFromOffload( + PowerManager.BRIGHTNESS_INVALID_FLOAT); } private void initDisplayOffloadSession() { @@ -1230,15 +1237,8 @@ public class LocalDisplayAdapterTest { public void stopOffload() {} }); - mDisplayOffloadSession = new DisplayOffloadSession() { - @Override - public void setDozeStateOverride(int displayState) {} - - @Override - public DisplayOffloader getDisplayOffloader() { - return mDisplayOffloader; - } - }; + mDisplayOffloadSession = new DisplayOffloadSessionImpl(mDisplayOffloader, + mMockedDisplayPowerController); } private void setupCutoutAndRoundedCorners() { diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java index c4f483810478..52fa91f5fe0e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java @@ -42,7 +42,9 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.display.AutomaticBrightnessController; import com.android.server.display.BrightnessSetting; import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy; +import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy; import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy; +import com.android.server.display.feature.DisplayManagerFlags; import org.junit.Before; import org.junit.Test; @@ -66,6 +68,8 @@ public final class DisplayBrightnessControllerTest { private BrightnessSetting mBrightnessSetting; @Mock private Runnable mOnBrightnessChangeRunnable; + @Mock + private DisplayManagerFlags mDisplayManagerFlags; @Mock private HandlerExecutor mBrightnessChangeExecutor; @@ -74,7 +78,7 @@ public final class DisplayBrightnessControllerTest { DisplayBrightnessController.Injector() { @Override DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector( - Context context, int displayId) { + Context context, int displayId, DisplayManagerFlags flags) { return mDisplayBrightnessStrategySelector; } }; @@ -92,7 +96,7 @@ public final class DisplayBrightnessControllerTest { .thenReturn(true); mDisplayBrightnessController = new DisplayBrightnessController(mContext, mInjector, DISPLAY_ID, DEFAULT_BRIGHTNESS, mBrightnessSetting, mOnBrightnessChangeRunnable, - mBrightnessChangeExecutor); + mBrightnessChangeExecutor, mDisplayManagerFlags); } @Test @@ -350,7 +354,7 @@ public final class DisplayBrightnessControllerTest { int nonDefaultDisplayId = 1; mDisplayBrightnessController = new DisplayBrightnessController(mContext, mInjector, nonDefaultDisplayId, DEFAULT_BRIGHTNESS, mBrightnessSetting, - mOnBrightnessChangeRunnable, mBrightnessChangeExecutor); + mOnBrightnessChangeRunnable, mBrightnessChangeExecutor, mDisplayManagerFlags); brightness = 0.5f; when(mBrightnessSetting.getBrightness()).thenReturn(brightness); mDisplayBrightnessController.setAutomaticBrightnessController( @@ -384,4 +388,14 @@ public final class DisplayBrightnessControllerTest { verify(mBrightnessSetting).setBrightness(brightnessValue2); verify(mBrightnessSetting).setBrightnessNitsForDefaultDisplay(nits2); } + + @Test + public void setBrightnessFromOffload() { + float brightness = 0.4f; + OffloadBrightnessStrategy offloadBrightnessStrategy = mock(OffloadBrightnessStrategy.class); + when(mDisplayBrightnessStrategySelector.getOffloadBrightnessStrategy()).thenReturn( + offloadBrightnessStrategy); + mDisplayBrightnessController.setBrightnessFromOffload(brightness); + verify(offloadBrightnessStrategy).setOffloadScreenBrightness(brightness); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java index 8497dabba67d..37958faed1ca 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java @@ -17,6 +17,7 @@ package com.android.server.display.brightness; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -35,13 +36,16 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProviderRule; +import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy; import com.android.server.display.brightness.strategy.BoostBrightnessStrategy; import com.android.server.display.brightness.strategy.DozeBrightnessStrategy; import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy; import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy; +import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy; import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy; import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy; import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy; +import com.android.server.display.feature.DisplayManagerFlags; import org.junit.Before; import org.junit.Rule; @@ -71,10 +75,64 @@ public final class DisplayBrightnessStrategySelectorTest { @Mock private FollowerBrightnessStrategy mFollowerBrightnessStrategy; @Mock + private AutomaticBrightnessStrategy mAutomaticBrightnessStrategy; + @Mock + private OffloadBrightnessStrategy mOffloadBrightnessStrategy; + @Mock private Resources mResources; + @Mock + private DisplayManagerFlags mDisplayManagerFlags; private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector; private Context mContext; + private DisplayBrightnessStrategySelector.Injector mInjector = + new DisplayBrightnessStrategySelector.Injector() { + @Override + ScreenOffBrightnessStrategy getScreenOffBrightnessStrategy() { + return mScreenOffBrightnessModeStrategy; + } + + @Override + DozeBrightnessStrategy getDozeBrightnessStrategy() { + return mDozeBrightnessModeStrategy; + } + + @Override + OverrideBrightnessStrategy getOverrideBrightnessStrategy() { + return mOverrideBrightnessStrategy; + } + + @Override + TemporaryBrightnessStrategy getTemporaryBrightnessStrategy() { + return mTemporaryBrightnessStrategy; + } + + @Override + BoostBrightnessStrategy getBoostBrightnessStrategy() { + return mBoostBrightnessStrategy; + } + + @Override + FollowerBrightnessStrategy getFollowerBrightnessStrategy(int displayId) { + return mFollowerBrightnessStrategy; + } + + @Override + InvalidBrightnessStrategy getInvalidBrightnessStrategy() { + return mInvalidBrightnessStrategy; + } + + @Override + AutomaticBrightnessStrategy getAutomaticBrightnessStrategy(Context context, + int displayId) { + return mAutomaticBrightnessStrategy; + } + + @Override + OffloadBrightnessStrategy getOffloadBrightnessStrategy() { + return mOffloadBrightnessStrategy; + } + }; @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); @@ -87,45 +145,8 @@ public final class DisplayBrightnessStrategySelectorTest { when(mContext.getContentResolver()).thenReturn(contentResolver); when(mContext.getResources()).thenReturn(mResources); when(mInvalidBrightnessStrategy.getName()).thenReturn("InvalidBrightnessStrategy"); - DisplayBrightnessStrategySelector.Injector injector = - new DisplayBrightnessStrategySelector.Injector() { - @Override - ScreenOffBrightnessStrategy getScreenOffBrightnessStrategy() { - return mScreenOffBrightnessModeStrategy; - } - - @Override - DozeBrightnessStrategy getDozeBrightnessStrategy() { - return mDozeBrightnessModeStrategy; - } - - @Override - OverrideBrightnessStrategy getOverrideBrightnessStrategy() { - return mOverrideBrightnessStrategy; - } - - @Override - TemporaryBrightnessStrategy getTemporaryBrightnessStrategy() { - return mTemporaryBrightnessStrategy; - } - - @Override - BoostBrightnessStrategy getBoostBrightnessStrategy() { - return mBoostBrightnessStrategy; - } - - @Override - FollowerBrightnessStrategy getFollowerBrightnessStrategy(int displayId) { - return mFollowerBrightnessStrategy; - } - - @Override - InvalidBrightnessStrategy getInvalidBrightnessStrategy() { - return mInvalidBrightnessStrategy; - } - }; mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, - injector, DISPLAY_ID); + mInjector, DISPLAY_ID, mDisplayManagerFlags); } @@ -188,6 +209,7 @@ public final class DisplayBrightnessStrategySelectorTest { displayPowerRequest.screenBrightnessOverride = Float.NaN; when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN); when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN); + when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(Float.NaN); assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest, Display.STATE_ON), mInvalidBrightnessStrategy); } @@ -200,4 +222,35 @@ public final class DisplayBrightnessStrategySelectorTest { assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest, Display.STATE_ON), mFollowerBrightnessStrategy); } + + @Test + public void selectStrategySelectsOffloadStrategyWhenValid() { + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( + DisplayManagerInternal.DisplayPowerRequest.class); + displayPowerRequest.screenBrightnessOverride = Float.NaN; + when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN); + when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN); + when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(0.3f); + assertEquals(mOffloadBrightnessStrategy, mDisplayBrightnessStrategySelector.selectStrategy( + displayPowerRequest, Display.STATE_ON)); + } + + @Test + public void selectStrategyDoesNotSelectOffloadStrategyWhenFeatureFlagDisabled() { + when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(false); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( + DisplayManagerInternal.DisplayPowerRequest.class); + displayPowerRequest.screenBrightnessOverride = Float.NaN; + when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN); + when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN); + when(mOffloadBrightnessStrategy.getOffloadScreenBrightness()).thenReturn(0.3f); + assertNotEquals(mOffloadBrightnessStrategy, + mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest, + Display.STATE_ON)); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java index b652576a75c8..78ec2ff31161 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java @@ -188,6 +188,29 @@ public class AutomaticBrightnessStrategyTest { } @Test + public void testAutoBrightnessState_BrightnessReasonIsOffload() { + mAutomaticBrightnessStrategy.setUseAutoBrightness(true); + int targetDisplayState = Display.STATE_ON; + boolean allowAutoBrightnessWhileDozing = false; + int brightnessReason = BrightnessReason.REASON_OFFLOAD; + int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; + float lastUserSetBrightness = 0.2f; + boolean userSetBrightnessChanged = true; + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(true); + mAutomaticBrightnessStrategy.setAutoBrightnessState(targetDisplayState, + allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness, + userSetBrightnessChanged); + verify(mAutomaticBrightnessController) + .configure(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, + mBrightnessConfiguration, + lastUserSetBrightness, + userSetBrightnessChanged, 0.5f, + false, policy, true); + assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()); + assertFalse(mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff()); + } + + @Test public void testAutoBrightnessState_DisplayIsInDoze_ConfigDoesAllow() { mAutomaticBrightnessStrategy.setUseAutoBrightness(true); int targetDisplayState = Display.STATE_DOZE; diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java new file mode 100644 index 000000000000..36719af10abb --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OffloadBrightnessStrategyTest.java @@ -0,0 +1,64 @@ +/* + * 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.display.brightness.strategy; + +import static org.junit.Assert.assertEquals; + +import android.hardware.display.DisplayManagerInternal; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.display.DisplayBrightnessState; +import com.android.server.display.brightness.BrightnessReason; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class OffloadBrightnessStrategyTest { + + private OffloadBrightnessStrategy mOffloadBrightnessStrategy; + + @Before + public void before() { + mOffloadBrightnessStrategy = new OffloadBrightnessStrategy(); + } + + @Test + public void testUpdateBrightnessWhenOffloadBrightnessIsSet() { + DisplayManagerInternal.DisplayPowerRequest + displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest(); + float brightness = 0.2f; + mOffloadBrightnessStrategy.setOffloadScreenBrightness(brightness); + BrightnessReason brightnessReason = new BrightnessReason(); + brightnessReason.setReason(BrightnessReason.REASON_OFFLOAD); + DisplayBrightnessState expectedDisplayBrightnessState = + new DisplayBrightnessState.Builder() + .setBrightness(brightness) + .setBrightnessReason(brightnessReason) + .setSdrBrightness(brightness) + .setDisplayBrightnessStrategyName(mOffloadBrightnessStrategy.getName()) + .setShouldUpdateScreenBrightnessSetting(true) + .build(); + DisplayBrightnessState updatedDisplayBrightnessState = + mOffloadBrightnessStrategy.updateBrightness(displayPowerRequest); + assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState); + } +} diff --git a/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java b/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java index 2d760a7dabac..1002fba3d60d 100644 --- a/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java @@ -220,7 +220,7 @@ public class PinnerServiceTest { private void setDeviceConfigPinnedAnonSize(long size) { mFakeDeviceConfigInterface.setProperty( - DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, + DeviceConfig.NAMESPACE_RUNTIME_NATIVE, "pin_shared_anon_size", String.valueOf(size), /*makeDefault=*/false); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index 0f3daec263e0..74eb79d7554c 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -28,6 +28,8 @@ import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUT import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING; import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -248,6 +250,45 @@ public class AuthSessionTest { } @Test + public void testOnErrorReceivedBeforeOnDialogAnimatedIn() throws RemoteException { + final int fingerprintId = 0; + final int faceId = 1; + setupFingerprint(fingerprintId, FingerprintSensorProperties.TYPE_REAR); + setupFace(faceId, true /* confirmationAlwaysRequired */, + mock(IBiometricAuthenticator.class)); + final AuthSession session = createAuthSession(mSensors, + false /* checkDevicePolicyManager */, + Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, + 0 /* operationId */, + 0 /* userId */); + session.goToInitialState(); + + for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { + assertThat(sensor.getSensorState()).isEqualTo(BiometricSensor.STATE_WAITING_FOR_COOKIE); + session.onCookieReceived( + session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie()); + } + assertThat(session.allCookiesReceived()).isTrue(); + assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED); + + final BiometricSensor faceSensor = session.mPreAuthInfo.eligibleSensors.get(faceId); + final BiometricSensor fingerprintSensor = session.mPreAuthInfo.eligibleSensors.get( + fingerprintId); + final int cookie = faceSensor.getCookie(); + session.onErrorReceived(0, cookie, BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL, 0); + + assertThat(faceSensor.getSensorState()).isEqualTo(BiometricSensor.STATE_STOPPED); + assertThat(session.getState()).isEqualTo(STATE_ERROR_PENDING_SYSUI); + + session.onDialogAnimatedIn(true); + + assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED_UI_SHOWING); + assertThat(fingerprintSensor.getSensorState()).isEqualTo( + BiometricSensor.STATE_AUTHENTICATING); + } + + @Test public void testCancelReducesAppetiteForCookies() throws Exception { setupFace(0 /* id */, false /* confirmationAlwaysRequired */, mock(IBiometricAuthenticator.class)); diff --git a/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java index 1e73a45a0c22..5aef7a320930 100644 --- a/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/AudioPoliciesDeviceRouteControllerTest.java @@ -90,7 +90,7 @@ public class AudioPoliciesDeviceRouteControllerTest { @Test public void getDeviceRoute_noSelectedRoutes_returnsDefaultDevice() { - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DEFAULT); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER); @@ -105,7 +105,7 @@ public class AudioPoliciesDeviceRouteControllerTest { audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES; callAudioRoutesObserver(audioRoutesInfo); - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); } @@ -117,7 +117,7 @@ public class AudioPoliciesDeviceRouteControllerTest { mController.selectRoute(MediaRoute2Info.TYPE_DOCK); - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK); } @@ -135,7 +135,7 @@ public class AudioPoliciesDeviceRouteControllerTest { mController.selectRoute(MediaRoute2Info.TYPE_DOCK); - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK); } @@ -155,7 +155,7 @@ public class AudioPoliciesDeviceRouteControllerTest { mController.selectRoute(null); - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); } @@ -171,7 +171,7 @@ public class AudioPoliciesDeviceRouteControllerTest { mController.selectRoute(MediaRoute2Info.TYPE_BLUETOOTH_A2DP); - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); } @@ -202,7 +202,7 @@ public class AudioPoliciesDeviceRouteControllerTest { mController.updateVolume(VOLUME_SAMPLE_1); - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1); } @@ -222,7 +222,7 @@ public class AudioPoliciesDeviceRouteControllerTest { mController.selectRoute(MediaRoute2Info.TYPE_DOCK); - MediaRoute2Info route2Info = mController.getDeviceRoute(); + MediaRoute2Info route2Info = mController.getSelectedRoute(); assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK); assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1); } diff --git a/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java index 24e48517f280..aed68a5dc7b5 100644 --- a/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java @@ -104,7 +104,7 @@ public class LegacyDeviceRouteControllerTest { mOnDeviceRouteChangedListener ); - MediaRoute2Info actualMediaRoute = deviceRouteController.getDeviceRoute(); + MediaRoute2Info actualMediaRoute = deviceRouteController.getSelectedRoute(); assertThat(actualMediaRoute.getType()).isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER); assertThat(TextUtils.equals(actualMediaRoute.getName(), DEFAULT_ROUTE_NAME)) @@ -129,7 +129,7 @@ public class LegacyDeviceRouteControllerTest { mOnDeviceRouteChangedListener ); - MediaRoute2Info actualMediaRoute = deviceRouteController.getDeviceRoute(); + MediaRoute2Info actualMediaRoute = deviceRouteController.getSelectedRoute(); assertThat(actualMediaRoute.getType()).isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER); assertThat(TextUtils.equals(actualMediaRoute.getName(), DEFAULT_ROUTE_NAME)) @@ -243,7 +243,7 @@ public class LegacyDeviceRouteControllerTest { mOnDeviceRouteChangedListener ); - MediaRoute2Info actualMediaRoute = deviceRouteController.getDeviceRoute(); + MediaRoute2Info actualMediaRoute = deviceRouteController.getSelectedRoute(); assertThat(actualMediaRoute.getType()).isEqualTo(mExpectedRouteType); assertThat(TextUtils.equals(actualMediaRoute.getName(), mExpectedRouteNameValue)) @@ -310,7 +310,7 @@ public class LegacyDeviceRouteControllerTest { // Simulating wired device being connected. callAudioRoutesObserver(audioRoutesInfo); - MediaRoute2Info actualMediaRoute = mDeviceRouteController.getDeviceRoute(); + MediaRoute2Info actualMediaRoute = mDeviceRouteController.getSelectedRoute(); assertThat(actualMediaRoute.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES); assertThat(TextUtils.equals(actualMediaRoute.getName(), DEFAULT_HEADPHONES_NAME)) @@ -324,7 +324,7 @@ public class LegacyDeviceRouteControllerTest { AudioRoutesInfo fakeBluetoothAudioRoute = createFakeBluetoothAudioRoute(); callAudioRoutesObserver(fakeBluetoothAudioRoute); - MediaRoute2Info actualMediaRoute = mDeviceRouteController.getDeviceRoute(); + MediaRoute2Info actualMediaRoute = mDeviceRouteController.getSelectedRoute(); assertThat(actualMediaRoute.getType()).isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER); assertThat(TextUtils.equals(actualMediaRoute.getName(), DEFAULT_ROUTE_NAME)) @@ -334,12 +334,12 @@ public class LegacyDeviceRouteControllerTest { @Test public void updateVolume_differentValue_updatesDeviceRouteVolume() { - MediaRoute2Info actualMediaRoute = mDeviceRouteController.getDeviceRoute(); + MediaRoute2Info actualMediaRoute = mDeviceRouteController.getSelectedRoute(); assertThat(actualMediaRoute.getVolume()).isEqualTo(VOLUME_DEFAULT_VALUE); assertThat(mDeviceRouteController.updateVolume(VOLUME_VALUE_SAMPLE_1)).isTrue(); - actualMediaRoute = mDeviceRouteController.getDeviceRoute(); + actualMediaRoute = mDeviceRouteController.getSelectedRoute(); assertThat(actualMediaRoute.getVolume()).isEqualTo(VOLUME_VALUE_SAMPLE_1); } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 63de41f80c23..4c56f33af430 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1953,6 +1953,13 @@ public class UsageStatsService extends SystemService implements } } + // Flags status. + pw.println("Flags:"); + pw.println(" " + Flags.FLAG_USER_INTERACTION_TYPE_API + + ": " + Flags.userInteractionTypeApi()); + pw.println(" " + Flags.FLAG_USE_PARCELED_LIST + + ": " + Flags.useParceledList()); + final int[] userIds; synchronized (mLock) { final int userCount = mUserState.size(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index a584fc9b2216..b77596391be1 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -2437,8 +2437,6 @@ public class VoiceInteractionManagerService extends SystemService { synchronized (VoiceInteractionManagerServiceStub.this) { Slog.i(TAG, "Force stopping current voice recognizer: " + getCurRecognizer(userHandle)); - // TODO: Figure out why the interactor was being cleared and document it. - setCurInteractor(null, userHandle); initRecognizer(userHandle); } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index f8608b8fead2..e12a815a84f5 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -23,6 +23,7 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; import android.annotation.DurationMillisLong; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -70,6 +71,7 @@ import android.util.Pair; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.util.HandlerExecutor; import com.android.internal.util.FunctionalUtils; import com.android.internal.util.Preconditions; @@ -95,7 +97,22 @@ import java.util.function.Consumer; import java.util.stream.Collectors; /** - * Subscription manager provides the mobile subscription information. + * Subscription manager provides the mobile subscription information that are associated with the + * calling user profile {@link UserHandle} for Android SDK 35(V) and above, while Android SDK 34(U) + * and below can see all subscriptions as it does today. + * + * <p>For example, if we have + * <ul> + * <li> Subscription 1 associated with personal profile. + * <li> Subscription 2 associated with work profile. + * </ul> + * Then for SDK 35+, if the caller identity is personal profile, then + * {@link #getActiveSubscriptionInfoList} will return subscription 1 only and vice versa. + * + * <p>If the caller needs to see all subscriptions across user profiles, + * use {@link #createForAllUserProfiles} to convert the instance to see all. Additional permission + * may be required as documented on the each API. + * */ @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @@ -1446,6 +1463,16 @@ public class SubscriptionManager { } } + /** + * {@code true} if the SubscriptionManager instance should see all subscriptions regardless its + * association with particular user profile. + * + * <p> It only applies to Android SDK 35(V) and above. For Android SDK 34(U) and below, the + * caller can see all subscription across user profiles as it does today today even if it's + * {@code false}. + */ + private boolean mIsForAllUserProfiles = false; + /** @hide */ @UnsupportedAppUsage public SubscriptionManager(Context context) { @@ -1776,8 +1803,23 @@ public class SubscriptionManager { } /** - * Get the SubscriptionInfo(s) of the currently active SIM(s). The records will be sorted - * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}. + * Get the SubscriptionInfo(s) of the currently active SIM(s) associated with the current caller + * user profile {@link UserHandle} for Android SDK 35(V) and above, while Android SDK 34(U) + * and below can see all subscriptions as it does today. + * + * <p>For example, if we have + * <ul> + * <li> Subscription 1 associated with personal profile. + * <li> Subscription 2 associated with work profile. + * </ul> + * Then for SDK 35+, if the caller identity is personal profile, then this will return + * subscription 1 only and vice versa. + * + * <p>If the caller needs to see all subscriptions across user profiles, + * use {@link #createForAllUserProfiles} to convert this instance to see all. + * + * <p> The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by + * {@link SubscriptionInfo#getSubscriptionId}. * * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * or that the calling app has carrier privileges (see @@ -1800,8 +1842,25 @@ public class SubscriptionManager { * </ul> */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + // @RequiresPermission(TODO(b/308809058)) public List<SubscriptionInfo> getActiveSubscriptionInfoList() { - return getActiveSubscriptionInfoList(/* userVisibleonly */true); + List<SubscriptionInfo> activeList = null; + + try { + ISub iSub = TelephonyManager.getSubscriptionService(); + if (iSub != null) { + activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(), + mContext.getAttributionTag(), mIsForAllUserProfiles); + } + } catch (RemoteException ex) { + // ignore it + } + + if (activeList != null) { + activeList = activeList.stream().filter(subInfo -> isSubscriptionVisible(subInfo)) + .collect(Collectors.toList()); + } + return activeList; } /** @@ -1835,6 +1894,26 @@ public class SubscriptionManager { } /** + * Convert this subscription manager instance into one that can see all subscriptions across + * user profiles. + * + * @return a SubscriptionManager that can see all subscriptions regardless its user profile + * association. + * + * @see #getActiveSubscriptionInfoList + * @see #getActiveSubscriptionInfoCount + * @see UserHandle + */ + @FlaggedApi(Flags.FLAG_WORK_PROFILE_API_SPLIT) + // @RequiresPermission(TODO(b/308809058)) + // The permission check for accessing all subscriptions will be enforced upon calling the + // individual APIs linked above. + @NonNull public SubscriptionManager createForAllUserProfiles() { + mIsForAllUserProfiles = true; + return this; + } + + /** * This is similar to {@link #getActiveSubscriptionInfoList()}, but if userVisibleOnly * is true, it will filter out the hidden subscriptions. * @@ -1847,7 +1926,7 @@ public class SubscriptionManager { ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(), - mContext.getAttributionTag()); + mContext.getAttributionTag(), true /*isForAllUserProfiles*/); } } catch (RemoteException ex) { // ignore it @@ -2002,13 +2081,19 @@ public class SubscriptionManager { } /** - * Get the active subscription count. + * Get the active subscription count associated with the current caller user profile for + * Android SDK 35(V) and above, while Android SDK 34(U) and below can see all subscriptions as + * it does today. + * + * <p>If the caller needs to see all subscriptions across user profiles, + * use {@link #createForAllUserProfiles} to convert this instance to see all. * * @return The current number of active subscriptions. * * @see #getActiveSubscriptionInfoList() */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + // @RequiresPermission(TODO(b/308809058)) public int getActiveSubscriptionInfoCount() { int result = 0; @@ -2016,7 +2101,7 @@ public class SubscriptionManager { ISub iSub = TelephonyManager.getSubscriptionService(); if (iSub != null) { result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(), - mContext.getAttributionTag()); + mContext.getAttributionTag(), mIsForAllUserProfiles); } } catch (RemoteException ex) { // ignore it diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index d2dbeb7aff74..3f41d5667107 100644 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -66,6 +66,8 @@ interface ISub { * * @param callingPackage The package maing the call. * @param callingFeatureId The feature in the package + * @param isForAllProfiles whether the caller intends to see all subscriptions regardless + * association. * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device. * <ul> * <li> @@ -83,14 +85,17 @@ interface ISub { * </ul> */ List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage, - String callingFeatureId); + String callingFeatureId, boolean isForAllProfiles); /** * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package. + * @param isForAllProfile whether the caller intends to see all subscriptions regardless + * association. * @return the number of active subscriptions */ - int getActiveSubInfoCount(String callingPackage, String callingFeatureId); + int getActiveSubInfoCount(String callingPackage, String callingFeatureId, + boolean isForAllProfile); /** * @return the maximum number of subscriptions this device will support at any one time. diff --git a/tests/SmokeTestApps/Android.bp b/tests/SmokeTestApps/Android.bp index 3505fe1c4afb..38ee8ac99747 100644 --- a/tests/SmokeTestApps/Android.bp +++ b/tests/SmokeTestApps/Android.bp @@ -11,4 +11,7 @@ android_test { name: "SmokeTestTriggerApps", srcs: ["src/**/*.java"], sdk_version: "current", + errorprone: { + enabled: false, + }, } diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/tools/hoststubgen/hoststubgen/framework-policy-override.txt index ff0fe32ad267..493ad56a5cbb 100644 --- a/tools/hoststubgen/hoststubgen/framework-policy-override.txt +++ b/tools/hoststubgen/hoststubgen/framework-policy-override.txt @@ -78,6 +78,9 @@ class android.util.Log !com.android.hoststubgen.nativesubstitution.Log_host class com.android.internal.util.FastPrintWriter keepclass class com.android.internal.util.LineBreakBufferedWriter keepclass +class android.util.EventLog stubclass +class android.util.EventLog !com.android.hoststubgen.nativesubstitution.EventLog_host +class android.util.EventLog$Event stubclass # Expose Context because it's referred to by AndroidTestCase, but don't need to expose any of # its members. diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java new file mode 100644 index 000000000000..292e8da0de10 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/EventLog_host.java @@ -0,0 +1,69 @@ +/* + * 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.nativesubstitution; + +import android.util.Log; +import android.util.Log.Level; + +import java.util.Collection; + +public class EventLog_host { + public static int writeEvent(int tag, int value) { + return writeEvent(tag, (Object) value); + } + + public static int writeEvent(int tag, long value) { + return writeEvent(tag, (Object) value); + } + + public static int writeEvent(int tag, float value) { + return writeEvent(tag, (Object) value); + } + + public static int writeEvent(int tag, String str) { + return writeEvent(tag, (Object) str); + } + + public static int writeEvent(int tag, Object... list) { + final StringBuilder sb = new StringBuilder(); + sb.append("logd: [event] "); + final String tagName = android.util.EventLog.getTagName(tag); + if (tagName != null) { + sb.append(tagName); + } else { + sb.append(tag); + } + sb.append(": ["); + for (int i = 0; i < list.length; i++) { + sb.append(String.valueOf(list[i])); + if (i < list.length - 1) { + sb.append(','); + } + } + sb.append(']'); + System.out.println(sb.toString()); + return sb.length(); + } + + public static void readEvents(int[] tags, Collection<android.util.EventLog.Event> output) { + throw new UnsupportedOperationException(); + } + + public static void readEventsOnWrapping(int[] tags, long timestamp, + Collection<android.util.EventLog.Event> output) { + throw new UnsupportedOperationException(); + } +} |