diff options
100 files changed, 1165 insertions, 647 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 03eab7c28300..9c93c3aaf4fb 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3434,6 +3434,23 @@ package android.companion { package android.companion.virtual { + @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public final class ActivityPolicyExemption implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.content.ComponentName getComponentName(); + method public int getDisplayId(); + method @Nullable public String getPackageName(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.ActivityPolicyExemption> CREATOR; + } + + public static final class ActivityPolicyExemption.Builder { + ctor public ActivityPolicyExemption.Builder(); + method @NonNull public android.companion.virtual.ActivityPolicyExemption build(); + method @NonNull public android.companion.virtual.ActivityPolicyExemption.Builder setComponentName(@NonNull android.content.ComponentName); + method @NonNull public android.companion.virtual.ActivityPolicyExemption.Builder setDisplayId(int); + method @NonNull public android.companion.virtual.ActivityPolicyExemption.Builder setPackageName(@NonNull String); + } + public final class VirtualDevice implements android.os.Parcelable { method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomAudioInputSupport(); method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomCameraSupport(); @@ -3467,9 +3484,7 @@ package android.companion.virtual { public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable { method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener); method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull android.content.ComponentName); - method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull String); - method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull android.content.ComponentName, int); - method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull String, int); + method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption); method public void addSoundEffectListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener); method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close(); method @NonNull public android.content.Context createContext(); @@ -3494,9 +3509,7 @@ package android.companion.virtual { method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback); method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener); method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull android.content.ComponentName); - method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull String); - method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull android.content.ComponentName, int); - method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull String, int); + method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull android.companion.virtual.ActivityPolicyExemption); method public void removeSoundEffectListener(@NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener); method @FlaggedApi("android.companion.virtual.flags.dynamic_policy") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setDevicePolicy(int, int); method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setDevicePolicy(int, int, int); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 80764afd3644..dbf9afdd52ff 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -112,6 +112,8 @@ import android.os.storage.VolumeInfo; import android.permission.PermissionControllerManager; import android.permission.PermissionManager; import android.provider.Settings; +import android.ravenwood.annotation.RavenwoodKeepPartialClass; +import android.ravenwood.annotation.RavenwoodReplace; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -157,6 +159,7 @@ import java.util.function.Consumer; import java.util.function.Function; /** @hide */ +@RavenwoodKeepPartialClass public class ApplicationPackageManager extends PackageManager { private static final String TAG = "ApplicationPackageManager"; private static final boolean DEBUG_ICONS = false; @@ -2163,6 +2166,7 @@ public class ApplicationPackageManager extends PackageManager { } @UnsupportedAppUsage + @RavenwoodReplace(reason = "<cinit> crashes due to unsupported class PropertyInvalidatedCache") static void configurationChanged() { synchronized (sSync) { sIconCache.clear(); @@ -2170,6 +2174,10 @@ public class ApplicationPackageManager extends PackageManager { } } + private static void configurationChanged$ravenwood() { + /* no-op */ + } + @UnsupportedAppUsage protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 2d5dad05f54e..84a4eb4acddc 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -41,6 +41,7 @@ import android.os.LocaleList; import android.os.Process; import android.os.Trace; import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodReplace; import android.ravenwood.annotation.RavenwoodThrow; import android.util.ArrayMap; import android.util.ArraySet; @@ -1409,6 +1410,7 @@ public class ResourcesManager { return newKey; } + @RavenwoodThrow(reason = "AppInfo update not supported") public void appendPendingAppInfoUpdate(@NonNull String[] oldSourceDirs, @NonNull ApplicationInfo appInfo) { synchronized (mLock) { @@ -1427,6 +1429,7 @@ public class ResourcesManager { } } + @RavenwoodReplace(reason = "AppInfo update not supported") public final void applyAllPendingAppInfoUpdates() { synchronized (mLock) { if (mPendingAppInfoUpdates != null) { @@ -1439,6 +1442,10 @@ public class ResourcesManager { } } + private void applyAllPendingAppInfoUpdates$ravenwood() { + /* no-op */ + } + public final boolean applyConfigurationToResources(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { synchronized (mLock) { diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java index 4b6f406ded9d..b6240a79dda8 100644 --- a/core/java/android/app/appfunctions/AppFunctionManager.java +++ b/core/java/android/app/appfunctions/AppFunctionManager.java @@ -54,9 +54,9 @@ public final class AppFunctionManager { * * @hide */ - public AppFunctionManager(IAppFunctionManager mService, Context context) { - this.mService = mService; - this.mContext = context; + public AppFunctionManager(IAppFunctionManager service, Context context) { + mService = service; + mContext = context; } /** @@ -114,7 +114,7 @@ public final class AppFunctionManager { } }); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } } diff --git a/core/java/android/app/appfunctions/IAppFunctionManager.aidl b/core/java/android/app/appfunctions/IAppFunctionManager.aidl index ef37095fbfa4..28827bb3052c 100644 --- a/core/java/android/app/appfunctions/IAppFunctionManager.aidl +++ b/core/java/android/app/appfunctions/IAppFunctionManager.aidl @@ -31,6 +31,7 @@ interface IAppFunctionManager { * @param request the request to execute an app function. * @param callback the callback to report the result. */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = {android.Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,android.Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional = true)") void executeAppFunction( in ExecuteAppFunctionAidlRequest request, in IExecuteAppFunctionCallback callback diff --git a/core/java/android/companion/virtual/ActivityPolicyExemption.aidl b/core/java/android/companion/virtual/ActivityPolicyExemption.aidl new file mode 100644 index 000000000000..2f89da3464e2 --- /dev/null +++ b/core/java/android/companion/virtual/ActivityPolicyExemption.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.companion.virtual; + +parcelable ActivityPolicyExemption; diff --git a/core/java/android/companion/virtual/ActivityPolicyExemption.java b/core/java/android/companion/virtual/ActivityPolicyExemption.java new file mode 100644 index 000000000000..c81bb43ac1d3 --- /dev/null +++ b/core/java/android/companion/virtual/ActivityPolicyExemption.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.companion.virtual; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.companion.virtualdevice.flags.Flags; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.Display; + +import java.util.Objects; + +/** + * Specifies an exemption from the current default activity launch policy of a virtual device. + * + * <p>Note that changing the virtual device's activity launch policy will clear all current + * exemptions.</p> + * + * @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY + * @see VirtualDeviceManager.VirtualDevice#setDevicePolicy + * @see VirtualDeviceManager.VirtualDevice#addActivityPolicyExemption(ActivityPolicyExemption) + * @see VirtualDeviceManager.VirtualDevice#removeActivityPolicyExemption(ActivityPolicyExemption) + * + * @hide + */ +@FlaggedApi(Flags.FLAG_ACTIVITY_CONTROL_API) +@SystemApi +public final class ActivityPolicyExemption implements Parcelable { + + private final @Nullable ComponentName mComponentName; + private final @Nullable String mPackageName; + private final int mDisplayId; + + private ActivityPolicyExemption(@Nullable ComponentName componentName, + @Nullable String packageName, int displayId) { + mComponentName = componentName; + mPackageName = packageName; + mDisplayId = displayId; + } + + private ActivityPolicyExemption(@NonNull Parcel parcel) { + mComponentName = parcel.readTypedObject(ComponentName.CREATOR); + mPackageName = parcel.readString8(); + mDisplayId = parcel.readInt(); + } + + /** + * Returns the exempt component name if this is a component level exemption, {@code null} + * otherwise. + * + * @see Builder#setComponentName(ComponentName) + */ + public @Nullable ComponentName getComponentName() { + return mComponentName; + } + + /** + * Returns the exempt package name if this is a package level exemption, {@code null} otherwise. + * + * @see Builder#setPackageName(String) + */ + public @Nullable String getPackageName() { + return mPackageName; + } + + /** + * Returns the display ID relevant for this exemption if it is specific to a single display, + * {@link Display#INVALID_DISPLAY} otherwise. + * + * @see Builder#setDisplayId(int) + */ + public int getDisplayId() { + return mDisplayId; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mComponentName, flags); + dest.writeString8(mPackageName); + dest.writeInt(mDisplayId); + } + + @NonNull + public static final Parcelable.Creator<ActivityPolicyExemption> CREATOR = + new Parcelable.Creator<>() { + public ActivityPolicyExemption createFromParcel(Parcel in) { + return new ActivityPolicyExemption(in); + } + + public ActivityPolicyExemption[] newArray(int size) { + return new ActivityPolicyExemption[size]; + } + }; + + /** + * Builder for {@link ActivityPolicyExemption}. + */ + public static final class Builder { + + private @Nullable ComponentName mComponentName; + private @Nullable String mPackageName; + private int mDisplayId = Display.INVALID_DISPLAY; + + /** + * Specifies a component level exemption from the current default activity launch policy. + * + * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity + * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), + * then the specified component will be blocked from launching. + * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches + * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then the + * specified component will be allowed to launch.</p> + * + * <p>Setting a component name will clear any previously set package name.</p> + */ + public @NonNull Builder setComponentName(@NonNull ComponentName componentName) { + mComponentName = Objects.requireNonNull(componentName); + mPackageName = null; + return this; + } + + /** + * Specifies a package level exemption from the current default activity launch policy. + * + * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity + * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), + * then all activities from the specified package will be blocked from launching. + * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches + * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then all + * activities from the specified package will be allowed to launch.</p> + * + * <p>Package level exemptions are independent of component level exemptions created via + * {@link #setComponentName(ComponentName)}, i.e. removing a package exemption will not + * remove any existing component exemptions, even if the component belongs to that package. + * </p> + * + * <p>Setting a package name will clear any previously set component name.</p> + */ + public @NonNull Builder setPackageName(@NonNull String packageName) { + mComponentName = null; + mPackageName = Objects.requireNonNull(packageName); + return this; + } + + /** + * Makes this exemption specific to the display with the given ID. If unset, or set to + * {@link Display#INVALID_DISPLAY}, then the exemption is applied to all displays that + * belong to the virtual device. + * + * @param displayId the ID of the display, for which to apply the exemption. The display + * must belong to the virtual device. + */ + public @NonNull Builder setDisplayId(int displayId) { + mDisplayId = displayId; + return this; + } + + /** + * Builds the {@link ActivityPolicyExemption} instance. + * + * @throws IllegalArgumentException if neither the component name nor the package name are + * set. + */ + @NonNull + public ActivityPolicyExemption build() { + if ((mComponentName == null) == (mPackageName == null)) { + throw new IllegalArgumentException( + "Either component name or package name must be set"); + } + return new ActivityPolicyExemption(mComponentName, mPackageName, mDisplayId); + } + } +} diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl index 56d5a74674c9..8916ce27cf68 100644 --- a/core/java/android/companion/virtual/IVirtualDevice.aidl +++ b/core/java/android/companion/virtual/IVirtualDevice.aidl @@ -17,6 +17,7 @@ package android.companion.virtual; import android.app.PendingIntent; +import android.companion.virtual.ActivityPolicyExemption; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.IVirtualDeviceIntentInterceptor; import android.companion.virtual.IVirtualDeviceSoundEffectListener; @@ -103,25 +104,13 @@ interface IVirtualDevice { * Adds an exemption to the default activity launch policy. */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void addActivityPolicyExemption(in ComponentName exemption); + void addActivityPolicyExemption(in ActivityPolicyExemption exemption); /** * Removes an exemption to the default activity launch policy. */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void removeActivityPolicyExemption(in ComponentName exemption); - - /** - * Adds a package level exemption to the default activity launch policy. - */ - @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void addActivityPolicyPackageExemption(in String exemption); - - /** - * Removes a package level exemption to the default activity launch policy. - */ - @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void removeActivityPolicyPackageExemption(in String exemption); + void removeActivityPolicyExemption(in ActivityPolicyExemption exemption); /** * Specifies a policy for this virtual device on the given display. @@ -130,30 +119,6 @@ interface IVirtualDevice { void setDevicePolicyForDisplay(int displayId, int policyType, int devicePolicy); /** - * Adds an exemption to the default activity launch policy on the given display. - */ - @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void addActivityPolicyExemptionForDisplay(int displayId, in ComponentName exemption); - - /** - * Removes an exemption to the default activity launch policy on the given display. - */ - @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void removeActivityPolicyExemptionForDisplay(int displayId, in ComponentName exemption); - - /** - * Adds a package level exemption to the default activity launch policy on the given display. - */ - @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void addActivityPolicyPackageExemptionForDisplay(int displayId, in String exemption); - - /** - * Removes a package level exemption to the default activity launch policy on the given display. - */ - @EnforcePermission("CREATE_VIRTUAL_DEVICE") - void removeActivityPolicyPackageExemptionForDisplay(int displayId, in String exemption); - - /** * Notifies that an audio session being started. */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java index e83f46aa62af..b7bf2d16ba2c 100644 --- a/core/java/android/companion/virtual/VirtualDeviceInternal.java +++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java @@ -306,39 +306,22 @@ public class VirtualDeviceInternal { } } - void addActivityPolicyExemption(@NonNull ComponentName componentName) { + void addActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) { try { - mVirtualDevice.addActivityPolicyExemption(componentName); + mVirtualDevice.addActivityPolicyExemption(exemption); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - void removeActivityPolicyExemption(@NonNull ComponentName componentName) { + void removeActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) { try { - mVirtualDevice.removeActivityPolicyExemption(componentName); + mVirtualDevice.removeActivityPolicyExemption(exemption); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - void addActivityPolicyPackageExemption(@NonNull String packageName) { - try { - mVirtualDevice.addActivityPolicyPackageExemption(packageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - void removeActivityPolicyPackageExemption(@NonNull String packageName) { - try { - mVirtualDevice.removeActivityPolicyPackageExemption(packageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - void setDevicePolicyForDisplay(int displayId, @VirtualDeviceParams.DynamicDisplayPolicyType int policyType, @VirtualDeviceParams.DevicePolicy int devicePolicy) { @@ -358,40 +341,6 @@ public class VirtualDeviceInternal { } } - void addActivityPolicyExemptionForDisplay(int displayId, @NonNull ComponentName componentName) { - try { - mVirtualDevice.addActivityPolicyExemptionForDisplay(displayId, componentName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - void removeActivityPolicyExemptionForDisplay(int displayId, - @NonNull ComponentName componentName) { - try { - mVirtualDevice.removeActivityPolicyExemptionForDisplay(displayId, componentName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - void addActivityPolicyPackageExemptionForDisplay(int displayId, @NonNull String packageName) { - try { - mVirtualDevice.addActivityPolicyPackageExemptionForDisplay(displayId, packageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - void removeActivityPolicyPackageExemptionForDisplay(int displayId, - @NonNull String packageName) { - try { - mVirtualDevice.removeActivityPolicyPackageExemptionForDisplay(displayId, packageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - @NonNull VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) { try { diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index 9e32cbac91eb..40aa6837ad1d 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -765,14 +765,15 @@ public final class VirtualDeviceManager { * <p>Note that changing the activity launch policy will clear current set of exempt * components.</p> * - * @see #removeActivityPolicyExemption + * @see #removeActivityPolicyExemption(ComponentName) * @see #setDevicePolicy */ @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void addActivityPolicyExemption(@NonNull ComponentName componentName) { - mVirtualDeviceInternal.addActivityPolicyExemption( - Objects.requireNonNull(componentName)); + addActivityPolicyExemption(new ActivityPolicyExemption.Builder() + .setComponentName(componentName) + .build()); } /** @@ -788,70 +789,54 @@ public final class VirtualDeviceManager { * <p>Note that changing the activity launch policy will clear current set of exempt * components.</p> * - * @see #addActivityPolicyExemption + * @see #addActivityPolicyExemption(ComponentName) * @see #setDevicePolicy */ @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void removeActivityPolicyExemption(@NonNull ComponentName componentName) { - mVirtualDeviceInternal.removeActivityPolicyExemption( - Objects.requireNonNull(componentName)); + removeActivityPolicyExemption(new ActivityPolicyExemption.Builder() + .setComponentName(componentName) + .build()); } /** - * Specifies a package name to be exempt from the current activity launch policy. + * Specifies an exemption from the current activity launch policy. * * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), - * then all activities from the specified package will be blocked from launching. + * then all exempt activities be blocked from launching. * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then all - * activities from the specified package will be allowed to launch.</p> - * - * <p>Package level exemptions are independent of component level exemptions added via - * {@link #addActivityPolicyExemption(String)}, i.e. removing a package exemption will not - * remove any existing component exemptions, even if the component belongs to that package. - * </p> + * exempt activities will be allowed to launch.</p> * * <p>Note that changing the activity launch policy will clear current set of exempt * packages.</p> + * <p>Any change to the exemptions will only be applied for new activity launches.</p> * - * @see #removeActivityPolicyExemption(String) + * @see #removeActivityPolicyExemption(ActivityPolicyExemption) * @see #setDevicePolicy */ @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void addActivityPolicyExemption(@NonNull String packageName) { - mVirtualDeviceInternal.addActivityPolicyPackageExemption( - Objects.requireNonNull(packageName)); + public void addActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) { + mVirtualDeviceInternal.addActivityPolicyExemption(Objects.requireNonNull(exemption)); } /** - * Makes the specified package name adhere to the default activity launch policy. - * - * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity - * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), - * then all activities from the specified package will be allowed to launch. - * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches - * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then all - * activities from the specified package will be blocked from launching.</p> - * - * <p>Package level exemptions are independent of component level exemptions added via - * {@link #addActivityPolicyExemption(String)}, i.e. removing a package exemption will not - * remove any existing component exemptions, even if the component belongs to that package. - * </p> + * Removes an exemption from the current activity launch policy. * * <p>Note that changing the activity launch policy will clear current set of exempt * packages.</p> + * <p>Any change to the exemptions will only be applied for new activity launches.</p> * - * @see #addActivityPolicyExemption(String) + * @see #addActivityPolicyExemption(ActivityPolicyExemption) * @see #setDevicePolicy */ @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void removeActivityPolicyExemption(@NonNull String packageName) { - mVirtualDeviceInternal.removeActivityPolicyPackageExemption( - Objects.requireNonNull(packageName)); + public void removeActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) { + mVirtualDeviceInternal.removeActivityPolicyExemption(Objects.requireNonNull(exemption)); } /** @@ -881,142 +866,6 @@ public final class VirtualDeviceManager { } /** - * Specifies a component name to be exempt from the given display's activity launch policy. - * - * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity - * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), - * then the specified component will be blocked from launching. - * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches - * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then the - * specified component will be allowed to launch.</p> - * - * <p>Note that changing the activity launch policy will clear current set of exempt - * components.</p> - * <p>Any change to the exemptions will only be applied for new activity launches.</p> - * - * @param componentName the component name to be exempt from the activity launch policy. - * @param displayId the ID of the display, for which to apply the exemption. The display - * must belong to the virtual device. - * @throws IllegalArgumentException if the specified display does not belong to the virtual - * device. - * - * @see #removeActivityPolicyExemption - * @see #setDevicePolicy - * @see Display#getDisplayId - */ - @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void addActivityPolicyExemption( - @NonNull ComponentName componentName, int displayId) { - mVirtualDeviceInternal.addActivityPolicyExemptionForDisplay( - displayId, Objects.requireNonNull(componentName)); - } - - /** - * Makes the specified component name adhere to the given display's activity launch policy. - * - * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity - * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), - * then the specified component will be allowed to launch. - * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches - * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then the - * specified component will be blocked from launching.</p> - * - * <p>Note that changing the activity launch policy will clear current set of exempt - * components.</p> - * - * @param componentName the component name to be removed from the exemption list. - * @param displayId the ID of the display, for which to apply the exemption. The display - * must belong to the virtual device. - * @throws IllegalArgumentException if the specified display does not belong to the virtual - * device. - * - * @see #addActivityPolicyExemption - * @see #setDevicePolicy - * @see Display#getDisplayId - */ - @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void removeActivityPolicyExemption( - @NonNull ComponentName componentName, int displayId) { - mVirtualDeviceInternal.removeActivityPolicyExemptionForDisplay( - displayId, Objects.requireNonNull(componentName)); - } - - /** - * Specifies a package name to be exempt from the given display's activity launch policy. - * - * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity - * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), - * then all activities from the specified package will be blocked from launching. - * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches - * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then all - * activities from the specified package will be allowed to launch.</p> - * - * <p>Note that changing the activity launch policy will clear current set of exempt - * packages.</p> - * <p>Any change to the exemptions will only be applied for new activity launches.</p> - * - * <p>Package level exemptions are independent of component level exemptions added via - * {@link #addActivityPolicyExemption(String, int)}, i.e. removing a package exemption will - * not remove any existing component exemptions, even if the component belongs to that - * package.</p> - * - * @param packageName the package name to be exempt from the activity launch policy. All - * activities from that package will be exempt. - * @param displayId the ID of the display, for which to apply the exemption. The display - * must belong to the virtual device. - * @throws IllegalArgumentException if the specified display does not belong to the virtual - * device. - * - * @see #removeActivityPolicyExemption(String, int) - * @see #setDevicePolicy - * @see Display#getDisplayId - */ - @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void addActivityPolicyExemption(@NonNull String packageName, int displayId) { - mVirtualDeviceInternal.addActivityPolicyPackageExemptionForDisplay( - displayId, Objects.requireNonNull(packageName)); - } - - /** - * Makes the specified package name adhere to the given display's activity launch policy. - * - * <p>If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} allows activity - * launches by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_DEFAULT}), - * then all activities from the specified package will be allowed to launch. - * If the current {@link VirtualDeviceParams#POLICY_TYPE_ACTIVITY} blocks activity launches - * by default, (i.e. it is {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM}), then all - * activities from the specified package will be blocked from launching.</p> - * - * <p>Note that changing the activity launch policy will clear current set of exempt - * packages.</p> - * - * <p>Package level exemptions are independent of component level exemptions added via - * {@link #addActivityPolicyExemption(String, int)}, i.e. removing a package exemption will - * not remove any existing component exemptions, even if the component belongs to that - * package.</p> - * - * @param packageName the package name to be removed from the exemption list. All activities - * from that package stop being exempt from the activity launch policy. - * @param displayId the ID of the display, for which to apply the exemption. The display - * must belong to the virtual device. - * @throws IllegalArgumentException if the specified display does not belong to the virtual - * device. - * - * @see #addActivityPolicyExemption(String, int) - * @see #setDevicePolicy - * @see Display#getDisplayId - */ - @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) - @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void removeActivityPolicyExemption(@NonNull String packageName, int displayId) { - mVirtualDeviceInternal.removeActivityPolicyPackageExemptionForDisplay( - displayId, Objects.requireNonNull(packageName)); - } - - /** * Creates a virtual dpad. * * @param config the configurations of the virtual dpad. @@ -1401,7 +1250,7 @@ public final class VirtualDeviceManager { * activity to a different display. * * @see VirtualDeviceParams#POLICY_TYPE_ACTIVITY - * @see VirtualDevice#addActivityPolicyExemption(ComponentName) + * @see VirtualDevice#addActivityPolicyExemption(ActivityPolicyExemption) */ @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) default void onActivityLaunchBlocked(int displayId, @NonNull ComponentName componentName, diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index da4ecdd8c1f2..9649cab1e09a 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -42,7 +42,7 @@ import java.util.concurrent.atomic.AtomicInteger; * will be invoked on that thread. * <p> * Syncs can be cancelled at any time by the framework. For example a sync that was not - * user-initiated and lasts longer than 30 minutes will be considered timed-out and cancelled. + * user-initiated and lasts longer than 10 minutes will be considered timed-out and cancelled. * Similarly the framework will attempt to determine whether or not an adapter is making progress * by monitoring its network activity over the course of a minute. If the network traffic over this * window is close enough to zero the sync will be cancelled. You can also request the sync be diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index f929c1f03c87..d6620d19ccf0 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -28,6 +28,7 @@ import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Parcel; import android.os.Parcelable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.view.InsetsSourceControl; @@ -42,6 +43,7 @@ import android.view.WindowManager.LayoutParams; * * {@hide} */ +@RavenwoodKeepWholeClass public class CompatibilityInfo implements Parcelable { /** default compatibility info object for compatible applications */ @UnsupportedAppUsage diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 982224b026bc..ef200c328d63 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -58,6 +58,7 @@ import android.os.Build; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Slog; @@ -89,6 +90,7 @@ import java.util.Locale; * with {@link android.app.Activity#getResources}:</p> * <pre>Configuration config = getResources().getConfiguration();</pre> */ +@RavenwoodKeepWholeClass public final class Configuration implements Parcelable, Comparable<Configuration> { /** @hide */ public static final Configuration EMPTY = new Configuration(); diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java index 5e10a5768358..9dc097ae8a81 100644 --- a/core/java/android/content/res/ConfigurationBoundResourceCache.java +++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java @@ -18,6 +18,7 @@ package android.content.res; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; /** * A Cache class which can be used to cache resource objects that are easy to clone but more @@ -25,6 +26,7 @@ import android.content.pm.ActivityInfo.Config; * * @hide For internal use only. */ +@RavenwoodKeepWholeClass public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<ConstantState<T>> { @UnsupportedAppUsage diff --git a/core/java/android/content/res/ConstantState.java b/core/java/android/content/res/ConstantState.java index 09d4a59d1418..cedfe02e43ec 100644 --- a/core/java/android/content/res/ConstantState.java +++ b/core/java/android/content/res/ConstantState.java @@ -16,6 +16,7 @@ package android.content.res; import android.content.pm.ActivityInfo.Config; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; /** * A cache class that can provide new instances of a particular resource which may change @@ -29,6 +30,7 @@ import android.content.pm.ActivityInfo.Config; * changing configurations of each Animator in the set) * @hide */ +@RavenwoodKeepWholeClass abstract public class ConstantState<T> { /** diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java index 24ae31e9f329..8aef45bb59ae 100644 --- a/core/java/android/content/res/FontResourcesParser.java +++ b/core/java/android/content/res/FontResourcesParser.java @@ -18,6 +18,7 @@ package android.content.res; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Typeface; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; @@ -36,6 +37,7 @@ import java.util.List; * Parser for xml type font resources. * @hide */ +@RavenwoodKeepWholeClass public class FontResourcesParser { private static final String TAG = "FontResourcesParser"; diff --git a/core/java/android/content/res/FontScaleConverter.java b/core/java/android/content/res/FontScaleConverter.java index f4312a905110..b2c5afa89e98 100644 --- a/core/java/android/content/res/FontScaleConverter.java +++ b/core/java/android/content/res/FontScaleConverter.java @@ -20,6 +20,7 @@ package android.content.res; import android.annotation.AnyThread; import android.annotation.FlaggedApi; import android.annotation.Nullable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; /** * A converter for non-linear font scaling. Converts font sizes given in "sp" dimensions to a @@ -32,6 +33,7 @@ import android.annotation.Nullable; * scale them slightly to preserve the visual hierarchy when compared to smaller fonts. */ @FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC) +@RavenwoodKeepWholeClass public interface FontScaleConverter { /** * Converts a dimension in "sp" to "dp". diff --git a/core/java/android/content/res/FontScaleConverterFactory.java b/core/java/android/content/res/FontScaleConverterFactory.java index c7237ea35c2a..9087a9a48a75 100644 --- a/core/java/android/content/res/FontScaleConverterFactory.java +++ b/core/java/android/content/res/FontScaleConverterFactory.java @@ -19,6 +19,7 @@ package android.content.res; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.Nullable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.MathUtils; import android.util.SparseArray; @@ -34,6 +35,7 @@ import com.android.internal.annotations.VisibleForTesting; * * @hide */ +@RavenwoodKeepWholeClass public class FontScaleConverterFactory { private static final float SCALE_KEY_MULTIPLIER = 100f; diff --git a/core/java/android/content/res/FontScaleConverterImpl.java b/core/java/android/content/res/FontScaleConverterImpl.java index 1968c4e53109..508507a564bb 100644 --- a/core/java/android/content/res/FontScaleConverterImpl.java +++ b/core/java/android/content/res/FontScaleConverterImpl.java @@ -17,6 +17,7 @@ package android.content.res; import android.annotation.NonNull; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.MathUtils; import com.android.internal.annotations.VisibleForTesting; @@ -33,6 +34,7 @@ import java.util.Arrays; */ // Needs to be public so the Kotlin test can see it @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +@RavenwoodKeepWholeClass public class FontScaleConverterImpl implements FontScaleConverter { /** @hide */ diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java index 690dfcf9619b..c7fcc1a38244 100644 --- a/core/java/android/content/res/ThemedResourceCache.java +++ b/core/java/android/content/res/ThemedResourceCache.java @@ -22,6 +22,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo.Config; import android.content.res.Resources.Theme; import android.content.res.Resources.ThemeKey; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.ArrayMap; import android.util.LongSparseArray; @@ -32,6 +33,7 @@ import java.lang.ref.WeakReference; * * @param <T> type of data to cache */ +@RavenwoodKeepWholeClass abstract class ThemedResourceCache<T> { public static final int UNDEFINED_GENERATION = -1; @UnsupportedAppUsage diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java index bb508493226d..149d9924156f 100644 --- a/core/java/android/view/DisplayAdjustments.java +++ b/core/java/android/view/DisplayAdjustments.java @@ -21,10 +21,12 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import java.util.Objects; /** @hide */ +@RavenwoodKeepWholeClass public class DisplayAdjustments { public static final DisplayAdjustments DEFAULT_DISPLAY_ADJUSTMENTS = new DisplayAdjustments(); diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 61ee13a2693c..be744fde96dd 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -228,6 +228,16 @@ flag { } flag { + name: "ensure_wallpaper_in_wear_transitions" + namespace: "windowing_frontend" + description: "Ensure that wallpaper window tokens are always present/available for collection in transitions on Wear" + bug: "355596979" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "custom_animations_behind_translucent" namespace: "windowing_frontend" description: "A change can use its own layer parameters to animate behind a translucent activity" diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 2bbaf9cb0cda..e86515f8da37 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -164,6 +164,7 @@ android_app { "org.apache.http.legacy", ], sdk_version: "core_platform", + resource_zips: [":FrameworksCoreTests_apks_as_resources"], } // Rules to copy all the test apks to the intermediate raw resource directory @@ -237,6 +238,7 @@ android_ravenwood_test { static_libs: [ "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport "androidx.core_core", + "androidx.core_core-ktx", "androidx.annotation_annotation", "androidx.test.rules", "androidx.test.ext.junit", @@ -255,8 +257,11 @@ android_ravenwood_test { "src/android/content/pm/UserInfoTest.java", "src/android/database/CursorWindowTest.java", "src/android/os/**/*.java", + "src/android/content/res/*.java", + "src/android/content/res/*.kt", "src/android/telephony/PinResultTest.java", "src/android/util/**/*.java", + "src/android/view/DisplayAdjustmentsTests.java", "src/android/view/DisplayTest.java", "src/android/view/DisplayInfoTest.java", "src/com/android/internal/logging/**/*.java", @@ -274,6 +279,10 @@ android_ravenwood_test { ":FrameworksCoreTests-helpers", ":FrameworksCoreTestDoubles-sources", ], + exclude_srcs: [ + "src/android/content/res/FontScaleConverterActivityTest.java", + ], + resource_apk: "FrameworksCoreTests-resonly", aidl: { generate_get_transaction_name: true, local_include_dirs: ["aidl"], diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index fc3c2f31459f..0dcb1ce525d6 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1672,14 +1672,6 @@ </intent-filter> </activity> - <activity android:name="android.content.res.ResourceCacheActivity" - android:exported="true"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> - </intent-filter> - </activity> - <activity android:name="android.print.test.PrintDocumentActivity" android:theme="@style/Theme" /> diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java index 6ffdee1c4b4f..68882eb39e37 100644 --- a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java +++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java @@ -16,80 +16,94 @@ package android.content.res; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; + +import android.content.Context; import android.platform.test.annotations.Presubmit; -import android.test.ActivityInstrumentationTestCase2; +import android.platform.test.ravenwood.RavenwoodRule; import android.util.TypedValue; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.frameworks.coretests.R; -import java.lang.reflect.InvocationTargetException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; @Presubmit -public class ConfigurationBoundResourceCacheTest - extends ActivityInstrumentationTestCase2<ResourceCacheActivity> { +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ConfigurationBoundResourceCacheTest { + + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); - ConfigurationBoundResourceCache<Float> mCache; + private ConfigurationBoundResourceCache<Float> mCache; + private Context mContext; - public ConfigurationBoundResourceCacheTest() { - super(ResourceCacheActivity.class); + private void assertEquals(float expected, float actual) { + Assert.assertEquals(expected, actual, 0); } - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { mCache = new ConfigurationBoundResourceCache<>(); + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); } - @SmallTest + @Test public void testGetEmpty() { - final Resources res = getActivity().getResources(); + final Resources res = mContext.getResources(); assertNull(mCache.getInstance(-1, res, null)); } - @SmallTest + @Test public void testSetGet() { mCache.put(1, null, new DummyFloatConstantState(5f), ThemedResourceCache.UNDEFINED_GENERATION); - final Resources res = getActivity().getResources(); + final Resources res = mContext.getResources(); assertEquals(5f, mCache.getInstance(1, res, null)); assertNotSame(5f, mCache.getInstance(1, res, null)); - assertEquals(null, mCache.getInstance(1, res, getActivity().getTheme())); + assertNull(mCache.getInstance(1, res, mContext.getTheme())); } - @SmallTest + @Test public void testSetGetThemed() { - mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f), + mCache.put(1, mContext.getTheme(), new DummyFloatConstantState(5f), ThemedResourceCache.UNDEFINED_GENERATION); - final Resources res = getActivity().getResources(); - assertEquals(null, mCache.getInstance(1, res, null)); - assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme())); - assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme())); + final Resources res = mContext.getResources(); + assertNull(mCache.getInstance(1, res, null)); + assertEquals(5f, mCache.getInstance(1, res, mContext.getTheme())); + assertNotSame(5f, mCache.getInstance(1, res, mContext.getTheme())); } - @SmallTest + @Test public void testMultiThreadPutGet() { - mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f), + mCache.put(1, mContext.getTheme(), new DummyFloatConstantState(5f), ThemedResourceCache.UNDEFINED_GENERATION); mCache.put(1, null, new DummyFloatConstantState(10f), ThemedResourceCache.UNDEFINED_GENERATION); - final Resources res = getActivity().getResources(); + final Resources res = mContext.getResources(); assertEquals(10f, mCache.getInstance(1, res, null)); assertNotSame(10f, mCache.getInstance(1, res, null)); - assertEquals(5f, mCache.getInstance(1, res, getActivity().getTheme())); - assertNotSame(5f, mCache.getInstance(1, res, getActivity().getTheme())); + assertEquals(5f, mCache.getInstance(1, res, mContext.getTheme())); + assertNotSame(5f, mCache.getInstance(1, res, mContext.getTheme())); } - @SmallTest - public void testVoidConfigChange() - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + @Test + public void testVoidConfigChange() { TypedValue staticValue = new TypedValue(); long key = 3L; - final Resources res = getActivity().getResources(); + final Resources res = mContext.getResources(); res.getValue(R.dimen.resource_cache_test_generic, staticValue, true); float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics()); - mCache.put(key, getActivity().getTheme(), + mCache.put(key, mContext.getTheme(), new DummyFloatConstantState(staticDim, staticValue.changingConfigurations), ThemedResourceCache.UNDEFINED_GENERATION); final Configuration cfg = res.getConfiguration(); @@ -98,21 +112,20 @@ public class ConfigurationBoundResourceCacheTest Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; int changes = calcConfigChanges(res, newCnf); - assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme())); + assertEquals(staticDim, mCache.getInstance(key, res, mContext.getTheme())); mCache.onConfigurationChange(changes); - assertEquals(staticDim, mCache.getInstance(key, res, getActivity().getTheme())); + assertEquals(staticDim, mCache.getInstance(key, res, mContext.getTheme())); } - @SmallTest - public void testEffectiveConfigChange() - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + @Test + public void testEffectiveConfigChange() { TypedValue changingValue = new TypedValue(); long key = 4L; - final Resources res = getActivity().getResources(); + final Resources res = mContext.getResources(); res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true); float changingDim = TypedValue.complexToDimension(changingValue.data, res.getDisplayMetrics()); - mCache.put(key, getActivity().getTheme(), + mCache.put(key, mContext.getTheme(), new DummyFloatConstantState(changingDim, changingValue.changingConfigurations), ThemedResourceCache.UNDEFINED_GENERATION); @@ -123,26 +136,25 @@ public class ConfigurationBoundResourceCacheTest : Configuration.ORIENTATION_LANDSCAPE; int changes = calcConfigChanges(res, newCnf); assertEquals(changingDim, - mCache.getInstance(key, res, getActivity().getTheme())); + mCache.getInstance(key, res, mContext.getTheme())); mCache.onConfigurationChange(changes); - assertNull(mCache.get(key, getActivity().getTheme())); + assertNull(mCache.get(key, mContext.getTheme())); } - @SmallTest - public void testConfigChangeMultipleResources() - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + @Test + public void testConfigChangeMultipleResources() { TypedValue staticValue = new TypedValue(); TypedValue changingValue = new TypedValue(); - final Resources res = getActivity().getResources(); + final Resources res = mContext.getResources(); res.getValue(R.dimen.resource_cache_test_generic, staticValue, true); res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true); float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics()); float changingDim = TypedValue.complexToDimension(changingValue.data, res.getDisplayMetrics()); - mCache.put(R.dimen.resource_cache_test_generic, getActivity().getTheme(), + mCache.put(R.dimen.resource_cache_test_generic, mContext.getTheme(), new DummyFloatConstantState(staticDim, staticValue.changingConfigurations), ThemedResourceCache.UNDEFINED_GENERATION); - mCache.put(R.dimen.resource_cache_test_orientation_dependent, getActivity().getTheme(), + mCache.put(R.dimen.resource_cache_test_orientation_dependent, mContext.getTheme(), new DummyFloatConstantState(changingDim, changingValue.changingConfigurations), ThemedResourceCache.UNDEFINED_GENERATION); final Configuration cfg = res.getConfiguration(); @@ -152,25 +164,24 @@ public class ConfigurationBoundResourceCacheTest : Configuration.ORIENTATION_LANDSCAPE; int changes = calcConfigChanges(res, newCnf); assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res, - getActivity().getTheme())); + mContext.getTheme())); assertEquals(changingDim, mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res, - getActivity().getTheme())); + mContext.getTheme())); mCache.onConfigurationChange(changes); assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res, - getActivity().getTheme())); + mContext.getTheme())); assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res, - getActivity().getTheme())); + mContext.getTheme())); } - @SmallTest - public void testConfigChangeMultipleThemes() - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + @Test + public void testConfigChangeMultipleThemes() { TypedValue[] staticValues = new TypedValue[]{new TypedValue(), new TypedValue()}; TypedValue[] changingValues = new TypedValue[]{new TypedValue(), new TypedValue()}; float staticDim = 0; float changingDim = 0; - final Resources res = getActivity().getResources(); + final Resources res = mContext.getResources(); for (int i = 0; i < 2; i++) { res.getValue(R.dimen.resource_cache_test_generic, staticValues[i], true); staticDim = TypedValue @@ -180,7 +191,7 @@ public class ConfigurationBoundResourceCacheTest true); changingDim = TypedValue.complexToDimension(changingValues[i].data, res.getDisplayMetrics()); - final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null; + final Resources.Theme theme = i == 0 ? mContext.getTheme() : null; mCache.put(R.dimen.resource_cache_test_generic, theme, new DummyFloatConstantState(staticDim, staticValues[i].changingConfigurations), ThemedResourceCache.UNDEFINED_GENERATION); @@ -196,7 +207,7 @@ public class ConfigurationBoundResourceCacheTest : Configuration.ORIENTATION_LANDSCAPE; int changes = calcConfigChanges(res, newCnf); for (int i = 0; i < 2; i++) { - final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null; + final Resources.Theme theme = i == 0 ? mContext.getTheme() : null; assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme)); assertEquals(changingDim, @@ -205,7 +216,7 @@ public class ConfigurationBoundResourceCacheTest } mCache.onConfigurationChange(changes); for (int i = 0; i < 2; i++) { - final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null; + final Resources.Theme theme = i == 0 ? mContext.getTheme() : null; assertEquals(staticDim, mCache.getInstance(R.dimen.resource_cache_test_generic, res, theme)); assertNull(mCache.getInstance(R.dimen.resource_cache_test_orientation_dependent, res, diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java index 0d5cd72a80e4..83c748464608 100644 --- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java +++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java @@ -28,23 +28,27 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.Surface.ROTATION_90; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import android.content.Context; import android.os.LocaleList; import android.platform.test.annotations.Presubmit; +import android.platform.test.ravenwood.RavenwoodRule; import android.util.AtomicFile; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; -import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.server.usage.IntervalStatsProto; -import junit.framework.TestCase; - +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import java.io.File; import java.io.FileInputStream; @@ -54,10 +58,14 @@ import java.util.Locale; /** * Build/install/run: bit FrameworksCoreTests:android.content.res.ConfigurationTest */ -@RunWith(JUnit4.class) +@RunWith(AndroidJUnit4.class) @SmallTest @Presubmit -public class ConfigurationTest extends TestCase { +public class ConfigurationTest { + + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); + @Test public void testUpdateFromPreservesRoundBit() { Configuration config = new Configuration(); @@ -82,7 +90,7 @@ public class ConfigurationTest extends TestCase { @Test public void testReadWriteProto() throws Exception { - final Context context = InstrumentationRegistry.getTargetContext(); + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); final File testDir = new File(context.getFilesDir(), "ConfigurationTest"); testDir.mkdirs(); final File proto = new File(testDir, "configs"); diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java index 85f5d698d516..3fcd37298da1 100644 --- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java +++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java @@ -26,16 +26,17 @@ import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import android.app.Instrumentation; import android.platform.test.annotations.Presubmit; +import android.platform.test.ravenwood.RavenwoodRule; -import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.frameworks.coretests.R; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParserException; @@ -51,13 +52,14 @@ import java.util.List; @RunWith(AndroidJUnit4.class) public class FontResourcesParserTest { - private Instrumentation mInstrumentation; + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); + private Resources mResources; @Before public void setup() { - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mResources = mInstrumentation.getContext().getResources(); + mResources = InstrumentationRegistry.getInstrumentation().getContext().getResources(); } @Test diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt index c7d5825733ae..c0a9bc2cdd24 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt @@ -20,6 +20,8 @@ import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.CheckFlagsRule import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.platform.test.flag.junit.RavenwoodFlagsValueProvider +import android.platform.test.ravenwood.RavenwoodRule import android.util.SparseArray import androidx.core.util.forEach import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -27,15 +29,14 @@ import androidx.test.filters.LargeTest import androidx.test.filters.SmallTest import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage +import kotlin.math.ceil +import kotlin.math.floor +import kotlin.random.Random.Default.nextFloat import org.junit.After import org.junit.Before import org.junit.Rule -import kotlin.math.ceil -import kotlin.math.floor import org.junit.Test import org.junit.runner.RunWith -import java.lang.IllegalStateException -import kotlin.random.Random.Default.nextFloat /** * Unit tests for FontScaleConverterFactory. Note that some similar tests are in @@ -46,7 +47,15 @@ import kotlin.random.Random.Default.nextFloat class FontScaleConverterFactoryTest { @get:Rule - val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + val ravenwoodRule: RavenwoodRule = RavenwoodRule.Builder().build() + + @get:Rule + val checkFlagsRule: CheckFlagsRule = + if (RavenwoodRule.isOnRavenwood()) { + RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule() + } else { + DeviceFlagsValueProvider.createCheckFlagsRule() + } private var defaultLookupTables: SparseArray<FontScaleConverter>? = null diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt index 2c614424a9a5..0e5d92688123 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt @@ -17,8 +17,10 @@ package android.content.res import android.platform.test.annotations.Presubmit +import android.platform.test.ravenwood.RavenwoodRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertWithMessage +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -26,6 +28,9 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class FontScaleConverterTest { + @get:Rule + val ravenwoodRule: RavenwoodRule = RavenwoodRule.Builder().build() + @Test fun straightInterpolation() { val table = createTable(8f to 8f, 10f to 10f, 20f to 20f) diff --git a/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java b/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java deleted file mode 100644 index f37e549940ec..000000000000 --- a/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -* Copyright (C) 2014 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.annotation.Nullable; -import android.app.Activity; -import android.os.Bundle; - -import java.lang.ref.WeakReference; - -public class ResourceCacheActivity extends Activity { - static WeakReference<ResourceCacheActivity> lastCreatedInstance; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - lastCreatedInstance = new WeakReference<ResourceCacheActivity>(this); - } - - public static ResourceCacheActivity getLastCreatedInstance() { - return lastCreatedInstance == null ? null : lastCreatedInstance.get(); - } -} diff --git a/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java index ac69a0f3687c..6a0984809a97 100644 --- a/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java +++ b/core/tests/coretests/src/android/content/res/ResourcesDrawableTest.java @@ -24,22 +24,29 @@ import android.content.Context; import android.graphics.drawable.ColorStateListDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; +import android.platform.test.ravenwood.RavenwoodRule; -import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.frameworks.coretests.R; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @Presubmit @SmallTest +@DisabledOnRavenwood(blockedBy = Drawable.class) @RunWith(AndroidJUnit4.class) public class ResourcesDrawableTest { + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); + @Test public void testLoadColorAsDrawable() { Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java index 26e4349243a5..fdfddc8d5b60 100644 --- a/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java +++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleTest.java @@ -16,29 +16,52 @@ package android.content.res; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import android.content.Context; import android.os.FileUtils; import android.os.LocaleList; import android.platform.test.annotations.Presubmit; -import android.test.AndroidTestCase; +import android.platform.test.ravenwood.RavenwoodRule; import android.util.DisplayMetrics; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.frameworks.coretests.R; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.File; import java.io.InputStream; import java.util.Arrays; import java.util.Locale; @Presubmit -public class ResourcesLocaleTest extends AndroidTestCase { +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ResourcesLocaleTest { + + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); + + private Context mContext; + + @Before + public void setup() { + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + } private String extractApkAndGetPath(int id) throws Exception { - final Resources resources = getContext().getResources(); + final Resources resources = mContext.getResources(); try (InputStream is = resources.openRawResource(id)) { - File path = new File(getContext().getFilesDir(), resources.getResourceEntryName(id)); + File path = new File(mContext.getFilesDir(), resources.getResourceEntryName(id)); FileUtils.copyToFileOrThrow(is, path); return path.getAbsolutePath(); } @@ -53,6 +76,15 @@ public class ResourcesLocaleTest extends AndroidTestCase { return new Resources(assets, dm, new Configuration()); } + private Resources createResourcesWithSelfApk() { + final AssetManager assets = new AssetManager(); + assertTrue(assets.addAssetPath(mContext.getPackageResourcePath()) != 0); + + final DisplayMetrics dm = new DisplayMetrics(); + dm.setToDefaults(); + return new Resources(assets, dm, new Configuration()); + } + private static void ensureNoLanguage(Resources resources, String language) { final String[] supportedLocales = resources.getAssets().getNonSystemLocales(); for (String languageTag : supportedLocales) { @@ -65,7 +97,7 @@ public class ResourcesLocaleTest extends AndroidTestCase { } } - @SmallTest + @Test public void testEnglishIsAlwaysConsideredSupported() throws Exception { final Resources resources = createResourcesWithApk(R.raw.locales); ensureNoLanguage(resources, "en"); @@ -82,7 +114,7 @@ public class ResourcesLocaleTest extends AndroidTestCase { resources.getConfiguration().getLocales().get(0)); } - @SmallTest + @Test public void testSelectFirstSupportedLanguage() throws Exception { final Resources resources = createResourcesWithApk(R.raw.locales); ensureNoLanguage(resources, "fr"); @@ -99,7 +131,7 @@ public class ResourcesLocaleTest extends AndroidTestCase { resources.getConfiguration().getLocales().get(0)); } - @SmallTest + @Test public void testDeprecatedISOLanguageCode() { assertResGetString(Locale.US, R.string.locale_test_res_1, "Testing ID"); assertResGetString(Locale.forLanguageTag("id"), R.string.locale_test_res_2, "Pengujian IN"); @@ -115,7 +147,8 @@ public class ResourcesLocaleTest extends AndroidTestCase { LocaleList locales = new LocaleList(locale); final Configuration config = new Configuration(); config.setLocales(locales); - Context newContext = getContext().createConfigurationContext(config); - assertEquals(expectedString, newContext.getResources().getString(resId)); + final Resources resources = createResourcesWithSelfApk(); + resources.updateConfiguration(config, null); + assertEquals(expectedString, resources.getString(resId)); } } diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java index ee1b6589f7e6..3eefe044de90 100644 --- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java +++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java @@ -16,27 +16,34 @@ package android.content.res; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + import android.annotation.NonNull; import android.app.ResourcesManager; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Binder; import android.os.LocaleList; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Postsubmit; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.flag.junit.RavenwoodFlagsValueProvider; +import android.platform.test.ravenwood.RavenwoodRule; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Display; import android.view.DisplayAdjustments; -import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; - -import junit.framework.TestCase; +import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Before; import org.junit.Rule; @@ -49,7 +56,7 @@ import java.util.Map; @Postsubmit @RunWith(AndroidJUnit4.class) -public class ResourcesManagerTest extends TestCase { +public class ResourcesManagerTest { private static final int SECONDARY_DISPLAY_ID = 1; private static final String APP_ONE_RES_DIR = "app_one.apk"; private static final String APP_ONE_RES_SPLIT_DIR = "app_one_split.apk"; @@ -57,14 +64,20 @@ public class ResourcesManagerTest extends TestCase { private static final String LIB_RES_DIR = "lib.apk"; private static final String TEST_LIB = "com.android.frameworks.coretests.bdr_helper_app1"; + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = + RavenwoodRule.isOnRavenwood() + ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule() + : DeviceFlagsValueProvider.createCheckFlagsRule(); + private ResourcesManager mResourcesManager; private Map<Integer, DisplayMetrics> mDisplayMetricsMap; - private PackageManager mPackageManager; @Before public void setUp() throws Exception { - super.setUp(); - mDisplayMetricsMap = new HashMap<>(); DisplayMetrics defaultDisplayMetrics = new DisplayMetrics(); @@ -110,12 +123,11 @@ public class ResourcesManagerTest extends TestCase { return mDisplayMetricsMap.get(displayId); } }; - - mPackageManager = InstrumentationRegistry.getContext().getPackageManager(); } - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private PackageManager getPackageManager() { + return InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(); + } @Test @SmallTest @@ -356,6 +368,7 @@ public class ResourcesManagerTest extends TestCase { @Test @SmallTest @RequiresFlagsEnabled(Flags.FLAG_REGISTER_RESOURCE_PATHS) + @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testExistingResourcesAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all @@ -370,7 +383,7 @@ public class ResourcesManagerTest extends TestCase { assertNotNull(resources); ResourcesImpl oriResImpl = resources.getImpl(); - ApplicationInfo appInfo = mPackageManager.getApplicationInfo(TEST_LIB, 0); + ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_LIB, 0); Resources.registerResourcePaths(TEST_LIB, appInfo); assertNotSame(oriResImpl, resources.getImpl()); @@ -390,6 +403,7 @@ public class ResourcesManagerTest extends TestCase { @Test @SmallTest @RequiresFlagsEnabled(Flags.FLAG_REGISTER_RESOURCE_PATHS) + @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testNewResourcesAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all @@ -397,7 +411,7 @@ public class ResourcesManagerTest extends TestCase { ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); ResourcesManager.setInstance(mResourcesManager); - ApplicationInfo appInfo = mPackageManager.getApplicationInfo(TEST_LIB, 0); + ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_LIB, 0); Resources.registerResourcePaths(TEST_LIB, appInfo); // Create a Resources after register resources' paths for a package. @@ -420,6 +434,7 @@ public class ResourcesManagerTest extends TestCase { @Test @SmallTest @RequiresFlagsEnabled(Flags.FLAG_REGISTER_RESOURCE_PATHS) + @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testExistingResourcesCreatedByConstructorAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { // Inject ResourcesManager instance from this test to the ResourcesManager class so that all @@ -437,7 +452,7 @@ public class ResourcesManagerTest extends TestCase { ResourcesImpl oriResImpl = resources.getImpl(); - ApplicationInfo appInfo = mPackageManager.getApplicationInfo(TEST_LIB, 0); + ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_LIB, 0); Resources.registerResourcePaths(TEST_LIB, appInfo); assertNotSame(oriResImpl, resources.getImpl()); @@ -456,6 +471,7 @@ public class ResourcesManagerTest extends TestCase { @Test @SmallTest @RequiresFlagsEnabled(Flags.FLAG_REGISTER_RESOURCE_PATHS) + @DisabledOnRavenwood(blockedBy = PackageManager.class) public void testNewResourcesWithOutdatedImplAfterResourcePathsRegistration() throws PackageManager.NameNotFoundException { ResourcesManager oriResourcesManager = ResourcesManager.getInstance(); @@ -467,7 +483,7 @@ public class ResourcesManagerTest extends TestCase { assertNotNull(old_resources); ResourcesImpl oldImpl = old_resources.getImpl(); - ApplicationInfo appInfo = mPackageManager.getApplicationInfo(TEST_LIB, 0); + ApplicationInfo appInfo = getPackageManager().getApplicationInfo(TEST_LIB, 0); Resources.registerResourcePaths(TEST_LIB, appInfo); // Create another resources with identical parameters. diff --git a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java index afbf8db3cd2d..b86029ba04e5 100644 --- a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java +++ b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java @@ -19,9 +19,11 @@ package android.view; import static org.junit.Assert.assertEquals; import android.content.res.Configuration; +import android.platform.test.ravenwood.RavenwoodRule; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,6 +36,9 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class DisplayAdjustmentsTests { + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); + @Test public void testDefaultConstructor_hasEmptyConfiguration() { DisplayAdjustments emptyAdjustments = new DisplayAdjustments(); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt index c44836a70642..620e90dcaa62 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapperTest.kt @@ -117,7 +117,11 @@ class InternetTileMapperTest : SysuiTestCase() { label, activationState, secondaryLabel, - setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK), + setOf( + QSTileState.UserAction.CLICK, + QSTileState.UserAction.TOGGLE_CLICK, + QSTileState.UserAction.LONG_CLICK + ), contentDescription, null, QSTileState.SideViewIcon.Chevron, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt index e1f3d97eb35c..52c476ec92cc 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt @@ -27,6 +27,7 @@ import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandl import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx import com.android.systemui.qs.tiles.dialog.InternetDialogManager +import com.android.systemui.qs.tiles.dialog.WifiStateWorker import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel import com.android.systemui.statusbar.connectivity.AccessPointController import com.android.systemui.util.mockito.mock @@ -40,6 +41,8 @@ import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.verify +import org.mockito.kotlin.times +import org.mockito.kotlin.whenever @SmallTest @EnabledOnRavenwood @@ -51,17 +54,20 @@ class InternetTileUserActionInteractorTest : SysuiTestCase() { private lateinit var underTest: InternetTileUserActionInteractor @Mock private lateinit var internetDialogManager: InternetDialogManager + @Mock private lateinit var wifiStateWorker: WifiStateWorker @Mock private lateinit var controller: AccessPointController @Before fun setup() { internetDialogManager = mock<InternetDialogManager>() + wifiStateWorker = mock<WifiStateWorker>() controller = mock<AccessPointController>() underTest = InternetTileUserActionInteractor( kosmos.testScope.coroutineContext, internetDialogManager, + wifiStateWorker, controller, inputHandler, ) @@ -110,4 +116,24 @@ class InternetTileUserActionInteractorTest : SysuiTestCase() { Truth.assertThat(it.intent.action).isEqualTo(Settings.ACTION_WIFI_SETTINGS) } } + + @Test + fun handleSecondaryClickWhenWifiOn() = + kosmos.testScope.runTest { + whenever(wifiStateWorker.isWifiEnabled).thenReturn(true) + + underTest.handleInput(QSTileInputTestKtx.toggleClick(InternetTileModel.Active())) + + verify(wifiStateWorker, times(1)).isWifiEnabled = eq(false) + } + + @Test + fun handleSecondaryClickWhenWifiOff() = + kosmos.testScope.runTest { + whenever(wifiStateWorker.isWifiEnabled).thenReturn(false) + + underTest.handleInput(QSTileInputTestKtx.toggleClick(InternetTileModel.Inactive())) + + verify(wifiStateWorker, times(1)).isWifiEnabled = eq(true) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index 355669bd8a59..f72a2e861be5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -43,6 +43,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.scene.data.repository.Idle import com.android.systemui.scene.data.repository.setTransition +import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes @@ -112,6 +113,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest { kosmos.sceneInteractor }, { kosmos.sceneContainerOcclusionInteractor }, { kosmos.keyguardClockInteractor }, + { kosmos.sceneBackInteractor }, ) { override fun createDarkAnimator(): ObjectAnimator { return mockDarkAnimator @@ -320,12 +322,23 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest assertThat(deviceUnlockStatus!!.isUnlocked).isTrue() - kosmos.sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason") + kosmos.sceneInteractor.changeScene( + toScene = Scenes.Lockscreen, + loggingReason = "reason" + ) runCurrent() - assertThat(currentScene).isEqualTo(Scenes.Gone) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) // Call start to begin hydrating based on the scene framework: underTest.start() + runCurrent() + + assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) + + kosmos.sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason") + runCurrent() + assertThat(currentScene).isEqualTo(Scenes.Gone) + assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") runCurrent() diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java index d13c75082790..be44dee0aae6 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java @@ -169,6 +169,7 @@ public interface QSTile { public boolean isTransient = false; public String expandedAccessibilityClassName; public boolean handlesLongClick = true; + public boolean handlesSecondaryClick = false; @Nullable public Drawable sideViewCustomDrawable; public String spec; @@ -212,6 +213,7 @@ public interface QSTile { || !Objects.equals(other.isTransient, isTransient) || !Objects.equals(other.dualTarget, dualTarget) || !Objects.equals(other.handlesLongClick, handlesLongClick) + || !Objects.equals(other.handlesSecondaryClick, handlesSecondaryClick) || !Objects.equals(other.sideViewCustomDrawable, sideViewCustomDrawable); other.spec = spec; other.icon = icon; @@ -227,6 +229,7 @@ public interface QSTile { other.dualTarget = dualTarget; other.isTransient = isTransient; other.handlesLongClick = handlesLongClick; + other.handlesSecondaryClick = handlesSecondaryClick; other.sideViewCustomDrawable = sideViewCustomDrawable; return changed; } @@ -252,6 +255,7 @@ public interface QSTile { sb.append(",disabledByPolicy=").append(disabledByPolicy); sb.append(",dualTarget=").append(dualTarget); sb.append(",isTransient=").append(isTransient); + sb.append(",handlesSecondaryClick=").append(handlesSecondaryClick); sb.append(",state=").append(state); sb.append(",sideViewCustomDrawable=").append(sideViewCustomDrawable); return sb.append(']'); diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/data/model/UserDeviceConnectionStatus.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/data/model/UserDeviceConnectionStatus.kt new file mode 100644 index 000000000000..1a22d3c76a4f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/data/model/UserDeviceConnectionStatus.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.inputdevice.data.model + +data class UserDeviceConnectionStatus(val isConnected: Boolean, val userId: Int) diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepository.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepository.kt new file mode 100644 index 000000000000..b8e73a3a5927 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepository.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.inputdevice.data.repository + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.inputdevice.data.model.UserDeviceConnectionStatus +import com.android.systemui.keyboard.data.repository.KeyboardRepository +import com.android.systemui.touchpad.data.repository.TouchpadRepository +import com.android.systemui.user.data.model.SelectionStatus +import com.android.systemui.user.data.repository.UserRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +/** + * Allow listening keyboard and touchpad device connection changes for current user. It emits new + * value when user is changed. + */ +@SysUISingleton +class UserInputDeviceRepository +@Inject +constructor( + @Background private val backgroundDispatcher: CoroutineDispatcher, + keyboardRepository: KeyboardRepository, + touchpadRepository: TouchpadRepository, + userRepository: UserRepository, +) { + private val selectedUserId = + userRepository.selectedUser + .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE } + .map { it.userInfo.id } + + val isAnyKeyboardConnectedForUser = + keyboardRepository.isAnyKeyboardConnected + .combine(selectedUserId) { isAnyKeyboardConnected, userId -> + UserDeviceConnectionStatus(isAnyKeyboardConnected, userId) + } + .flowOn(backgroundDispatcher) + + val isAnyTouchpadConnectedForUser = + touchpadRepository.isAnyTouchpadConnected + .combine(selectedUserId) { isAnyTouchpadConnected, userId -> + UserDeviceConnectionStatus(isAnyTouchpadConnected, userId) + } + .flowOn(backgroundDispatcher) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt index 19b46e3689aa..04aa04d1f2af 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt @@ -63,7 +63,11 @@ constructor( if (categories.isEmpty()) { ShortcutsUiState.Inactive } else { - val filteredCategories = filterCategoriesBySearchQuery(query, categories) + /* temporarily hiding launcher shortcut categories until b/327141011 + * is completed. */ + val categoriesWithLauncherExcluded = excludeLauncherApp(categories) + val filteredCategories = + filterCategoriesBySearchQuery(query, categoriesWithLauncherExcluded) ShortcutsUiState.Active( searchQuery = query, shortcutCategories = filteredCategories, @@ -77,15 +81,27 @@ constructor( initialValue = ShortcutsUiState.Inactive ) + private suspend fun excludeLauncherApp( + categories: List<ShortcutCategory> + ): List<ShortcutCategory> { + val launcherAppCategory = + categories.firstOrNull { it.type is CurrentApp && isLauncherApp(it.type.packageName) } + return if (launcherAppCategory != null) { + categories - launcherAppCategory + } else { + categories + } + } + private suspend fun getDefaultSelectedCategory( categories: List<ShortcutCategory> ): ShortcutCategoryType? { val currentAppShortcuts = - categories.firstOrNull { it.type is CurrentApp && !isAppLauncher(it.type.packageName) } + categories.firstOrNull { it.type is CurrentApp && !isLauncherApp(it.type.packageName) } return currentAppShortcuts?.type ?: categories.firstOrNull()?.type } - private suspend fun isAppLauncher(packageName: String): Boolean { + private suspend fun isLauncherApp(packageName: String): Boolean { return withContext(backgroundDispatcher) { roleManager .getRoleHoldersAsUser(RoleManager.ROLE_HOME, userTracker.userHandle) diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt index c06d6d2dc957..6eacb2ef9f14 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt @@ -109,6 +109,7 @@ import com.android.systemui.qs.panels.ui.model.GridCell import com.android.systemui.qs.panels.ui.model.SpacerGridCell import com.android.systemui.qs.panels.ui.model.TileGridCell import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel +import com.android.systemui.qs.panels.ui.viewmodel.TileUiState import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel import com.android.systemui.qs.panels.ui.viewmodel.toUiState import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor @@ -129,7 +130,7 @@ fun Tile( ) { val state by tile.state.collectAsStateWithLifecycle(tile.currentState) val uiState = remember(state) { state.toUiState() } - val colors = TileDefaults.getColorForState(uiState.state) + val colors = TileDefaults.getColorForState(uiState) TileContainer( colors = colors, @@ -150,9 +151,13 @@ fun Tile( secondaryLabel = uiState.secondaryLabel, icon = icon, colors = colors, - clickEnabled = true, - onClick = tile::onSecondaryClick, - onLongClick = tile::onLongClick, + toggleClickSupported = state.handlesSecondaryClick, + onClick = { + if (state.handlesSecondaryClick) { + tile.onSecondaryClick() + } + }, + onLongClick = { tile.onLongClick(it) }, ) } } @@ -168,7 +173,7 @@ private fun TileContainer( onClick: (Expandable) -> Unit = {}, onLongClick: (Expandable) -> Unit = {}, modifier: Modifier = Modifier, - content: @Composable BoxScope.() -> Unit, + content: @Composable BoxScope.(Expandable) -> Unit, ) { Column( horizontalAlignment = Alignment.CenterHorizontally, @@ -200,7 +205,7 @@ private fun TileContainer( } .tilePadding(), ) { - content() + content(it) } } @@ -222,36 +227,27 @@ private fun LargeTileContent( secondaryLabel: String?, icon: Icon, colors: TileColors, - clickEnabled: Boolean = false, - onClick: (Expandable) -> Unit = {}, - onLongClick: (Expandable) -> Unit = {}, + toggleClickSupported: Boolean = false, + onClick: () -> Unit = {}, + onLongClick: () -> Unit = {}, ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = tileHorizontalArrangement() ) { - Expandable( - color = colors.iconBackground, - shape = TileDefaults.TileShape, - modifier = Modifier.fillMaxHeight().aspectRatio(1f) + // Icon + Box( + modifier = + Modifier.fillMaxHeight().aspectRatio(1f).thenIf(toggleClickSupported) { + Modifier.clip(TileDefaults.TileShape) + .background(colors.iconBackground, { 1f }) + .combinedClickable(onClick = onClick, onLongClick = onLongClick) + } ) { - Box( - modifier = - Modifier.fillMaxSize().clip(TileDefaults.TileShape).thenIf(clickEnabled) { - Modifier.combinedClickable( - onClick = { onClick(it) }, - onLongClick = { onLongClick(it) } - ) - } - ) { - TileIcon( - icon = icon, - color = colors.icon, - modifier = Modifier.align(Alignment.Center) - ) - } + TileIcon(icon = icon, color = colors.icon, modifier = Modifier.align(Alignment.Center)) } + // Labels Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) { Text( label, @@ -743,9 +739,21 @@ private object TileDefaults { val TileShape = CircleShape val IconTileWithLabelHeight = 140.dp + /** An active tile without dual target uses the active color as background */ @Composable fun activeTileColors(): TileColors = TileColors( + background = MaterialTheme.colorScheme.primary, + iconBackground = MaterialTheme.colorScheme.primary, + label = MaterialTheme.colorScheme.onPrimary, + secondaryLabel = MaterialTheme.colorScheme.onPrimary, + icon = MaterialTheme.colorScheme.onPrimary, + ) + + /** An active tile with dual target only show the active color on the icon */ + @Composable + fun activeDualTargetTileColors(): TileColors = + TileColors( background = MaterialTheme.colorScheme.surfaceVariant, iconBackground = MaterialTheme.colorScheme.primary, label = MaterialTheme.colorScheme.onSurfaceVariant, @@ -774,9 +782,15 @@ private object TileDefaults { ) @Composable - fun getColorForState(state: Int): TileColors { - return when (state) { - STATE_ACTIVE -> activeTileColors() + fun getColorForState(uiState: TileUiState): TileColors { + return when (uiState.state) { + STATE_ACTIVE -> { + if (uiState.handlesSecondaryClick) { + activeDualTargetTileColors() + } else { + activeTileColors() + } + } STATE_INACTIVE -> inactiveTileColors() else -> unavailableTileColors() } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt index c83e3b2a0e06..45051fea76b6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt @@ -25,6 +25,7 @@ data class TileUiState( val label: String, val secondaryLabel: String, val state: Int, + val handlesSecondaryClick: Boolean, val icon: Supplier<QSTile.Icon?>, ) @@ -33,6 +34,7 @@ fun QSTile.State.toUiState(): TileUiState { label?.toString() ?: "", secondaryLabel?.toString() ?: "", state, + handlesSecondaryClick, icon?.let { Supplier { icon } } ?: iconSupplier ?: Supplier { null }, ) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt index 8578bb0ef9a1..44dd801a8b9f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileViewModel.kt @@ -50,8 +50,8 @@ class TileViewModel(private val tile: QSTile, val spec: TileSpec) { tile.longClick(expandable) } - fun onSecondaryClick(expandable: Expandable?) { - tile.secondaryClick(expandable) + fun onSecondaryClick() { + tile.secondaryClick(null) } fun startListening(token: Any) = tile.setListening(token, true) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 9f41d98b6969..7ceb78638f6c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -114,7 +114,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { @Override public BooleanState newTileState() { - return new BooleanState(); + BooleanState s = new BooleanState(); + s.handlesSecondaryClick = true; + return s; } @Override @@ -141,10 +143,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { mDialogViewModel.showDialog(expandable); } else { // Secondary clicks are header clicks, just toggle. - final boolean isEnabled = mState.value; - // Immediately enter transient enabling state when turning bluetooth on. - refreshState(isEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING); - mController.setBluetoothEnabled(!isEnabled); + toggleBluetooth(); } } @@ -160,9 +159,7 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { new Intent(Settings.ACTION_BLUETOOTH_SETTINGS), 0); return; } - if (!mState.value) { - mController.setBluetoothEnabled(true); - } + toggleBluetooth(); } @Override @@ -228,6 +225,13 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { state.forceExpandIcon = mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG); } + private void toggleBluetooth() { + final boolean isEnabled = mState.value; + // Immediately enter transient enabling state when turning bluetooth on. + refreshState(isEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING); + mController.setBluetoothEnabled(!isEnabled); + } + /** * Returns the secondary label to use for the given bluetooth connection in the form of the * battery level or bluetooth profile name. If the bluetooth is disabled, there's no connected diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 6d98da4bac61..02f6f80d7282 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -52,6 +52,7 @@ import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.qs.tiles.dialog.InternetDialogManager; +import com.android.systemui.qs.tiles.dialog.WifiStateWorker; import com.android.systemui.res.R; import com.android.systemui.statusbar.connectivity.AccessPointController; import com.android.systemui.statusbar.connectivity.IconState; @@ -84,6 +85,7 @@ public class InternetTile extends QSTileImpl<QSTile.BooleanState> { protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback(); private final InternetDialogManager mInternetDialogManager; + private final WifiStateWorker mWifiStateWorker; final Handler mHandler; @Inject @@ -99,11 +101,13 @@ public class InternetTile extends QSTileImpl<QSTile.BooleanState> { QSLogger qsLogger, NetworkController networkController, AccessPointController accessPointController, - InternetDialogManager internetDialogManager + InternetDialogManager internetDialogManager, + WifiStateWorker wifiStateWorker ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); mInternetDialogManager = internetDialogManager; + mWifiStateWorker = wifiStateWorker; mHandler = mainHandler; mController = networkController; mAccessPointController = accessPointController; @@ -115,6 +119,7 @@ public class InternetTile extends QSTileImpl<QSTile.BooleanState> { public BooleanState newTileState() { BooleanState s = new BooleanState(); s.forceExpandIcon = true; + s.handlesSecondaryClick = true; return s; } @@ -131,6 +136,13 @@ public class InternetTile extends QSTileImpl<QSTile.BooleanState> { } @Override + public void secondaryClick(@Nullable Expandable expandable) { + // TODO(b/358352265): Figure out the correct action for the secondary click + // Toggle Wifi + mWifiStateWorker.setWifiEnabled(!mWifiStateWorker.isWifiEnabled()); + } + + @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_internet_label); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt index 932dec5af950..42ef0cd3abb7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt @@ -34,6 +34,7 @@ import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.dialog.InternetDialogManager +import com.android.systemui.qs.tiles.dialog.WifiStateWorker import com.android.systemui.res.R import com.android.systemui.statusbar.connectivity.AccessPointController import com.android.systemui.statusbar.pipeline.shared.ui.binder.InternetTileBinder @@ -55,6 +56,7 @@ constructor( qsLogger: QSLogger, viewModel: InternetTileViewModel, private val internetDialogManager: InternetDialogManager, + private val wifiStateWorker: WifiStateWorker, private val accessPointController: AccessPointController, ) : QSTileImpl<QSTile.BooleanState>( @@ -81,7 +83,10 @@ constructor( mContext.getString(R.string.quick_settings_internet_label) override fun newTileState(): QSTile.BooleanState { - return QSTile.BooleanState().also { it.forceExpandIcon = true } + return QSTile.BooleanState().also { + it.forceExpandIcon = true + it.handlesSecondaryClick = true + } } override fun handleClick(expandable: Expandable?) { @@ -95,6 +100,12 @@ constructor( } } + override fun secondaryClick(expandable: Expandable?) { + // TODO(b/358352265): Figure out the correct action for the secondary click + // Toggle wifi + wifiStateWorker.isWifiEnabled = !wifiStateWorker.isWifiEnabled + } + override fun handleUpdateState(state: QSTile.BooleanState, arg: Any?) { state.label = mContext.resources.getString(R.string.quick_settings_internet_label) state.expandedAccessibilityClassName = Switch::class.java.name diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalytics.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalytics.kt index 0d15a5b6b4d4..1d427775dad6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalytics.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalytics.kt @@ -47,6 +47,7 @@ constructor( private fun QSTileUserAction.getQSEvent(): QSEvent = when (this) { is QSTileUserAction.Click -> QSEvent.QS_ACTION_CLICK + is QSTileUserAction.ToggleClick -> QSEvent.QS_ACTION_SECONDARY_CLICK is QSTileUserAction.LongClick -> QSEvent.QS_ACTION_LONG_PRESS } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt index f0d72065397d..8ec8a6d1e730 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/logging/QSTileLogger.kt @@ -222,6 +222,7 @@ constructor( private fun QSTileUserAction.toLogString(): String = when (this) { is QSTileUserAction.Click -> "click" + is QSTileUserAction.ToggleClick -> "toggle click" is QSTileUserAction.LongClick -> "long click" } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt index 9e84f01c6bc4..d8c5af289048 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt @@ -229,7 +229,8 @@ class QSTileViewModelImpl<DATA_TYPE>( filter { action -> val isFalseAction = when (action) { - is QSTileUserAction.Click -> + is QSTileUserAction.Click, + is QSTileUserAction.ToggleClick -> falsingManager.isFalseTap(FalsingManager.LOW_PENALTY) is QSTileUserAction.LongClick -> falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileUserActionInteractor.kt index bf0f8f6577de..50532918b170 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/interactor/AirplaneModeTileUserActionInteractor.kt @@ -57,6 +57,7 @@ constructor( Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt index 14fc57c0f83f..79fcd3721877 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt @@ -49,6 +49,7 @@ constructor( } } is QSTileUserAction.LongClick -> {} + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/domain/interactor/BatterySaverTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/domain/interactor/BatterySaverTileUserActionInteractor.kt index d4b4fe06ded8..3bbb9aa8505c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/domain/interactor/BatterySaverTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/domain/interactor/BatterySaverTileUserActionInteractor.kt @@ -48,6 +48,7 @@ constructor( Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt index 534bd734f5bd..dfdec3b458a9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt @@ -49,6 +49,7 @@ constructor( Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt index 9bdf6316b069..af2bb9d0d2f7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractor.kt @@ -74,6 +74,7 @@ constructor( click(action.expandable, data.tile.activityLaunchForClick) is QSTileUserAction.LongClick -> longClick(user, action.expandable, data.componentName, data.tile.state) + is QSTileUserAction.ToggleClick -> {} } qsTileLogger.logCustomTileUserActionDelivered(tileSpec) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileUserActionInteractor.kt index bedd65e0072f..13afc15d17ef 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileUserActionInteractor.kt @@ -42,6 +42,7 @@ constructor( flashlightController.setFlashlight(!input.data.isEnabled) } } + is QSTileUserAction.ToggleClick -> {} else -> {} } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt index d308ec889136..6ab5796dceaa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt @@ -66,8 +66,7 @@ constructor( INTERACTION_JANK_TAG ) ) - ?.let { dialogTransitionAnimator.show(dialog, it) } - ?: dialog.show() + ?.let { dialogTransitionAnimator.show(dialog, it) } ?: dialog.show() } else { dialog.show() } @@ -89,8 +88,10 @@ constructor( Intent(Settings.ACTION_TEXT_READING_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } + companion object { private const val INTERACTION_JANK_TAG = "font_scaling" } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt index e543e4bdc930..8965ef2bc493 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/InternetTileMapper.kt @@ -72,6 +72,10 @@ constructor( else QSTileState.ActivationState.INACTIVE supportedActions = - setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK) + setOf( + QSTileState.UserAction.CLICK, + QSTileState.UserAction.TOGGLE_CLICK, + QSTileState.UserAction.LONG_CLICK + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt index c0b089d84dc8..a963b2875154 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt @@ -23,6 +23,7 @@ import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.dialog.InternetDialogManager +import com.android.systemui.qs.tiles.dialog.WifiStateWorker import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import com.android.systemui.statusbar.connectivity.AccessPointController @@ -36,6 +37,7 @@ class InternetTileUserActionInteractor constructor( @Main private val mainContext: CoroutineContext, private val internetDialogManager: InternetDialogManager, + private val wifiStateWorker: WifiStateWorker, private val accessPointController: AccessPointController, private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler, ) : QSTileUserActionInteractor<InternetTileModel> { @@ -53,6 +55,11 @@ constructor( ) } } + is QSTileUserAction.ToggleClick -> { + // TODO(b/358352265): Figure out the correct action for the secondary click + // Toggle Wifi + wifiStateWorker.isWifiEnabled = !wifiStateWorker.isWifiEnabled + } is QSTileUserAction.LongClick -> { qsTileIntentUserActionHandler.handle( action.expandable, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt index d64327333cb6..aa8387732160 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt @@ -49,6 +49,7 @@ constructor( Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt index 77404aa82606..cca947ff7e77 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt @@ -68,6 +68,7 @@ constructor( Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt index 083bf05d213b..eb8b23c2505a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileUserActionInteractor.kt @@ -41,7 +41,8 @@ constructor( override suspend fun handleInput(input: QSTileInput<ModesTileModel>) { with(input) { when (action) { - is QSTileUserAction.Click -> { + is QSTileUserAction.Click, + is QSTileUserAction.ToggleClick -> { handleClick(action.expandable) } is QSTileUserAction.LongClick -> { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/domain/interactor/NightDisplayTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/domain/interactor/NightDisplayTileUserActionInteractor.kt index 5cee8c49527d..7076a8f757fe 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/domain/interactor/NightDisplayTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/domain/interactor/NightDisplayTileUserActionInteractor.kt @@ -55,6 +55,7 @@ constructor( Intent(Settings.ACTION_NIGHT_DISPLAY_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt index 5cb0e181378b..0a0f0a668079 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/domain/OneHandedModeTileUserActionInteractor.kt @@ -49,6 +49,7 @@ constructor( Intent(Settings.ACTION_ONE_HANDED_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt index 7c0c41eca4bc..bb5df022dd1b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileUserActionInteractor.kt @@ -45,6 +45,7 @@ constructor( } } is QSTileUserAction.LongClick -> {} // no-op + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt index ed5e4fe74962..de49e70587ca 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt @@ -71,6 +71,7 @@ constructor( Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractor.kt index 34385ea815eb..65712c75516f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileUserActionInteractor.kt @@ -46,6 +46,7 @@ constructor( Intent(Settings.ACTION_AUTO_ROTATE_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt index a5dc66c901f1..252e3f84df6c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt @@ -94,8 +94,7 @@ constructor( ) ?.let { controller -> dialogTransitionAnimator.show(dialog, controller) - } - ?: dialog.show() + } ?: dialog.show() } } is QSTileUserAction.LongClick -> { @@ -104,6 +103,7 @@ constructor( Intent(Settings.ACTION_DATA_SAVER_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt index 5637115cd6da..48b39ed25750 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt @@ -75,6 +75,7 @@ constructor( } } is QSTileUserAction.LongClick -> {} // no-op + is QSTileUserAction.ToggleClick -> {} } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/domain/SensorPrivacyToggleTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/domain/SensorPrivacyToggleTileUserActionInteractor.kt index f22a4269b3f5..d7f64d11a4fd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/domain/SensorPrivacyToggleTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/sensorprivacy/domain/SensorPrivacyToggleTileUserActionInteractor.kt @@ -82,6 +82,7 @@ constructor( } qsTileIntentUserActionHandler.handle(action.expandable, longClickIntent) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileUserActionInteractor.kt index f8dd1730cc10..889782831b70 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileUserActionInteractor.kt @@ -54,6 +54,7 @@ constructor( Intent(Settings.ACTION_DARK_THEME_SETTINGS) ) } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractor.kt index 031e4d978739..45ae09eaef92 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/domain/interactor/WorkModeTileUserActionInteractor.kt @@ -49,6 +49,7 @@ constructor( ) } } + is QSTileUserAction.ToggleClick -> {} } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt index 30247c41200f..549f0a73908d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt @@ -105,6 +105,7 @@ data class QSTileState( enum class UserAction { CLICK, + TOGGLE_CLICK, LONG_CLICK, } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt index acb29362681b..bf3bc73cf72e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt @@ -23,5 +23,8 @@ sealed interface QSTileUserAction { val expandable: Expandable? class Click(override val expandable: Expandable?) : QSTileUserAction + + class ToggleClick(override val expandable: Expandable?) : QSTileUserAction + class LongClick(override val expandable: Expandable?) : QSTileUserAction } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt index 9bcf9272c5d6..8077c67bbba6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt @@ -131,8 +131,8 @@ constructor( } override fun secondaryClick(expandable: Expandable?) { - if (isActionSupported(QSTileState.UserAction.CLICK)) { - qsTileViewModel.onActionPerformed(QSTileUserAction.Click(expandable)) + if (isActionSupported(QSTileState.UserAction.TOGGLE_CLICK)) { + qsTileViewModel.onActionPerformed(QSTileUserAction.ToggleClick(expandable)) } } @@ -184,8 +184,7 @@ constructor( } } - override fun isListening(): Boolean = - listeningClients.isNotEmpty() + override fun isListening(): Boolean = listeningClients.isNotEmpty() override fun setDetailListening(show: Boolean) { // do nothing like QSTileImpl @@ -238,6 +237,8 @@ constructor( secondaryLabel = viewModelState.secondaryLabel handlesLongClick = viewModelState.supportedActions.contains(QSTileState.UserAction.LONG_CLICK) + handlesSecondaryClick = + viewModelState.supportedActions.contains(QSTileState.UserAction.TOGGLE_CLICK) icon = when (val stateIcon = viewModelState.icon()) { diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt b/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt index d3e529c9035b..323bb3ddd63a 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/data/model/SceneStack.kt @@ -55,6 +55,9 @@ fun SceneStack.asIterable(): Iterable<SceneKey> = Iterable { } } +/** Does this stack contain the given [sceneKey]? O(N) */ +fun SceneStack.contains(sceneKey: SceneKey): Boolean = asIterable().any { it == sceneKey } + /** * Returns a new [SceneStack] containing the given [scenes], ordered such that the first argument is * the head returned from [peek], then the second, and so forth. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 0957e5a5df35..3422c67d50bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -54,6 +54,9 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.model.KeyguardState; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.res.R; +import com.android.systemui.scene.data.model.SceneStack; +import com.android.systemui.scene.data.model.SceneStackKt; +import com.android.systemui.scene.domain.interactor.SceneBackInteractor; import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.shared.flag.SceneContainerFlag; @@ -118,6 +121,7 @@ public class StatusBarStateControllerImpl implements private final Lazy<SceneInteractor> mSceneInteractorLazy; private final Lazy<SceneContainerOcclusionInteractor> mSceneContainerOcclusionInteractorLazy; private final Lazy<KeyguardClockInteractor> mKeyguardClockInteractorLazy; + private final Lazy<SceneBackInteractor> mSceneBackInteractorLazy; private int mState; private int mLastState; private int mUpcomingState; @@ -186,7 +190,8 @@ public class StatusBarStateControllerImpl implements Lazy<DeviceUnlockedInteractor> deviceUnlockedInteractorLazy, Lazy<SceneInteractor> sceneInteractorLazy, Lazy<SceneContainerOcclusionInteractor> sceneContainerOcclusionInteractor, - Lazy<KeyguardClockInteractor> keyguardClockInteractorLazy) { + Lazy<KeyguardClockInteractor> keyguardClockInteractorLazy, + Lazy<SceneBackInteractor> sceneBackInteractorLazy) { mUiEventLogger = uiEventLogger; mInteractionJankMonitorLazy = interactionJankMonitorLazy; mJavaAdapter = javaAdapter; @@ -196,6 +201,7 @@ public class StatusBarStateControllerImpl implements mSceneInteractorLazy = sceneInteractorLazy; mSceneContainerOcclusionInteractorLazy = sceneContainerOcclusionInteractor; mKeyguardClockInteractorLazy = keyguardClockInteractorLazy; + mSceneBackInteractorLazy = sceneBackInteractorLazy; for (int i = 0; i < HISTORY_SIZE; i++) { mHistoricalRecords[i] = new HistoricalState(); } @@ -221,6 +227,7 @@ public class StatusBarStateControllerImpl implements combineFlows( mDeviceUnlockedInteractorLazy.get().getDeviceUnlockStatus(), mSceneInteractorLazy.get().getCurrentScene(), + mSceneBackInteractorLazy.get().getBackStack(), mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(), this::calculateStateFromSceneFramework), this::onStatusBarStateChanged); @@ -677,10 +684,15 @@ public class StatusBarStateControllerImpl implements private int calculateStateFromSceneFramework( DeviceUnlockStatus deviceUnlockStatus, SceneKey currentScene, + SceneStack backStack, boolean isOccluded) { SceneContainerFlag.isUnexpectedlyInLegacyMode(); - - if (deviceUnlockStatus.isUnlocked() || isOccluded) { + if (currentScene.equals(Scenes.Lockscreen)) { + return StatusBarState.KEYGUARD; + } else if (currentScene.equals(Scenes.Shade) + && SceneStackKt.contains(backStack, Scenes.Lockscreen)) { + return StatusBarState.SHADE_LOCKED; + } else if (deviceUnlockStatus.isUnlocked() || isOccluded) { return StatusBarState.SHADE; } else { return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene)); 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 0e4be8ecc920..8f187f0274f0 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 @@ -1487,7 +1487,14 @@ public class NotificationStackScrollLayout private float updateStackEndHeight() { if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return 0f; - float height = Math.max(0f, mAmbientState.getStackCutoff() - mAmbientState.getStackTop()); + final float height; + if (mMaxDisplayedNotifications != -1) { + // The stack intrinsic height already contains the correct value when there is a limit + // in the max number of notifications (e.g. as in keyguard). + height = mIntrinsicContentHeight; + } else { + height = Math.max(0f, mAmbientState.getStackCutoff() - mAmbientState.getStackTop()); + } mAmbientState.setStackEndHeight(height); return height; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt new file mode 100644 index 000000000000..f2e43fcb8e2c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/UserInputDeviceRepositoryTest.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.inputdevice.data.repository + +import android.content.pm.UserInfo +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectValues +import com.android.systemui.inputdevice.data.model.UserDeviceConnectionStatus +import com.android.systemui.keyboard.data.repository.keyboardRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.touchpad.data.repository.touchpadRepository +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.user.data.repository.userRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) +class UserInputDeviceRepositoryTest : SysuiTestCase() { + + private lateinit var underTest: UserInputDeviceRepository + private val kosmos = Kosmos() + private val testScope = kosmos.testScope + private val keyboardRepository = kosmos.keyboardRepository + private val touchpadRepository = kosmos.touchpadRepository + private val userRepository = kosmos.fakeUserRepository + + @Before + fun setup() { + underTest = + UserInputDeviceRepository( + kosmos.testDispatcher, + keyboardRepository, + touchpadRepository, + kosmos.userRepository + ) + userRepository.setUserInfos(USER_INFOS) + } + + @Test + fun emitsNewKeyboardConnectedValueOnUserChanged() = + testScope.runTest { + val isAnyKeyboardConnected by collectValues(underTest.isAnyKeyboardConnectedForUser) + userRepository.setSelectedUserInfo(USER_INFOS[0]) + keyboardRepository.setIsAnyKeyboardConnected(true) + runCurrent() + + userRepository.setSelectedUserInfo(USER_INFOS[1]) + + assertThat(isAnyKeyboardConnected) + .containsExactly( + UserDeviceConnectionStatus(isConnected = true, USER_INFOS[0].id), + UserDeviceConnectionStatus(isConnected = true, USER_INFOS[1].id) + ) + .inOrder() + } + + @Test + fun emitsNewTouchpadConnectedValueOnUserChanged() = + testScope.runTest { + val isAnyTouchpadConnected by collectValues(underTest.isAnyTouchpadConnectedForUser) + userRepository.setSelectedUserInfo(USER_INFOS[0]) + touchpadRepository.setIsAnyTouchpadConnected(true) + runCurrent() + + userRepository.setSelectedUserInfo(USER_INFOS[1]) + + assertThat(isAnyTouchpadConnected) + .containsExactly( + UserDeviceConnectionStatus(isConnected = true, USER_INFOS[0].id), + UserDeviceConnectionStatus(isConnected = true, USER_INFOS[1].id) + ) + .inOrder() + } + + companion object { + private val USER_INFOS = + listOf( + UserInfo(100, "First User", 0), + UserInfo(101, "Second User", 0), + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt index 79cb51ab3e10..828c7b2dbc69 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt @@ -23,7 +23,6 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.plugins.ActivityStarter @@ -32,6 +31,8 @@ import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tiles.dialog.InternetDialogManager +import com.android.systemui.qs.tiles.dialog.WifiStateWorker +import com.android.systemui.res.R import com.android.systemui.statusbar.connectivity.AccessPointController import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor @@ -46,7 +47,6 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiIntera import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher @@ -58,6 +58,10 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations +import org.mockito.kotlin.eq +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -87,6 +91,7 @@ class InternetTileNewImplTest : SysuiTestCase() { @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var logger: QSLogger @Mock private lateinit var dialogManager: InternetDialogManager + @Mock private lateinit var wifiStateWorker: WifiStateWorker @Mock private lateinit var accessPointController: AccessPointController @Before @@ -122,6 +127,7 @@ class InternetTileNewImplTest : SysuiTestCase() { logger, viewModel, dialogManager, + wifiStateWorker, accessPointController ) @@ -231,6 +237,24 @@ class InternetTileNewImplTest : SysuiTestCase() { assertThat(underTest.state.secondaryLabel).isEqualTo(WIFI_SSID) } + @Test + fun secondaryClick_turnsWifiOff() { + whenever(wifiStateWorker.isWifiEnabled).thenReturn(true) + + underTest.secondaryClick(null) + + verify(wifiStateWorker, times(1)).isWifiEnabled = eq(false) + } + + @Test + fun secondaryClick_turnsWifiOn() { + whenever(wifiStateWorker.isWifiEnabled).thenReturn(false) + + underTest.secondaryClick(null) + + verify(wifiStateWorker, times(1)).isWifiEnabled = eq(true) + } + companion object { const val WIFI_SSID = "test ssid" val ACTIVE_WIFI = diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java index 8ea79d7cc230..0cf96047fcc0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileTest.java @@ -18,7 +18,10 @@ package com.android.systemui.qs.tiles; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.os.Handler; @@ -38,6 +41,7 @@ import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.qs.tiles.dialog.InternetDialogManager; +import com.android.systemui.qs.tiles.dialog.WifiStateWorker; import com.android.systemui.res.R; import com.android.systemui.statusbar.connectivity.AccessPointController; import com.android.systemui.statusbar.connectivity.IconState; @@ -65,6 +69,8 @@ public class InternetTileTest extends SysuiTestCase { @Mock private InternetDialogManager mInternetDialogManager; @Mock + private WifiStateWorker mWifiStateWorker; + @Mock private QsEventLogger mUiEventLogger; private TestableLooper mTestableLooper; @@ -89,7 +95,8 @@ public class InternetTileTest extends SysuiTestCase { mock(QSLogger.class), mNetworkController, mAccessPointController, - mInternetDialogManager + mInternetDialogManager, + mWifiStateWorker ); mTile.initialize(); @@ -167,4 +174,22 @@ public class InternetTileTest extends SysuiTestCase { assertThat(mTile.getState().icon).isEqualTo( QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable)); } + + @Test + public void secondaryClick_turnsWifiOff() { + when(mWifiStateWorker.isWifiEnabled()).thenReturn(true); + + mTile.secondaryClick(null); + + verify(mWifiStateWorker, times(1)).setWifiEnabled(eq(false)); + } + + @Test + public void secondaryClick_turnsWifiOn() { + when(mWifiStateWorker.isWifiEnabled()).thenReturn(false); + + mTile.secondaryClick(null); + + verify(mWifiStateWorker, times(1)).setWifiEnabled(eq(true)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 8125ef55f4af..523d15c7548f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -468,7 +468,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { () -> mKosmos.getDeviceUnlockedInteractor(), () -> mKosmos.getSceneInteractor(), () -> mKosmos.getSceneContainerOcclusionInteractor(), - () -> mKosmos.getKeyguardClockInteractor()); + () -> mKosmos.getKeyguardClockInteractor(), + () -> mKosmos.getSceneBackInteractor()); KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext); keyguardStatusView.setId(R.id.keyguard_status_view); @@ -625,7 +626,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { () -> mKosmos.getDeviceUnlockedInteractor(), () -> mKosmos.getSceneInteractor(), () -> mKosmos.getSceneContainerOcclusionInteractor(), - () -> mKosmos.getKeyguardClockInteractor()), + () -> mKosmos.getKeyguardClockInteractor(), + () -> mKosmos.getSceneBackInteractor()), mKeyguardBypassController, mDozeParameters, mScreenOffAnimationController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 22b98874c7ef..1717f4c069f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -354,6 +354,20 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { } @Test + @EnableSceneContainer + public void updateStackEndHeightAndStackHeight_maxNotificationsSet_withSceneContainer() { + float stackHeight = 300f; + when(mStackSizeCalculator.computeHeight(eq(mStackScroller), anyInt(), anyFloat())) + .thenReturn(stackHeight); + mStackScroller.setMaxDisplayedNotifications(3); // any non-zero amount + + clearInvocations(mAmbientState); + mStackScroller.updateStackEndHeightAndStackHeight(1f); + + verify(mAmbientState).setStackHeight(eq(300f)); + } + + @Test public void updateStackEndHeightAndStackHeight_onlyUpdatesStackHeightDuringSwipeUp() { final float expansionFraction = 0.5f; mAmbientState.setStatusBarState(StatusBarState.KEYGUARD); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index e6bd24b6b99a..9fe66eb77feb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -50,6 +50,7 @@ import com.android.systemui.model.sceneContainerPlugin import com.android.systemui.plugins.statusbar.statusBarStateController import com.android.systemui.power.data.repository.fakePowerRepository import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.startable.scrimStartable @@ -115,6 +116,7 @@ class KosmosJavaAdapter() { val interactionJankMonitor by lazy { kosmos.interactionJankMonitor } val fakeSceneContainerConfig by lazy { kosmos.sceneContainerConfig } val sceneInteractor by lazy { kosmos.sceneInteractor } + val sceneBackInteractor by lazy { kosmos.sceneBackInteractor } val falsingCollector by lazy { kosmos.falsingCollector } val powerInteractor by lazy { kosmos.powerInteractor } val deviceEntryInteractor by lazy { kosmos.deviceEntryInteractor } 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 index f9f8d232611e..2deeb253e925 100644 --- 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 @@ -22,6 +22,7 @@ import com.android.systemui.jank.interactionJankMonitor import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor @@ -41,5 +42,6 @@ var Kosmos.statusBarStateController: SysuiStatusBarStateController by { sceneInteractor }, { sceneContainerOcclusionInteractor }, { keyguardClockInteractor }, + { sceneBackInteractor }, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt index 9cb76bb412f9..3943d1d7ec01 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/QSTileInputTestKtx.kt @@ -28,6 +28,12 @@ object QSTileInputTestKtx { expandable: Expandable? = null, ): QSTileInput<T> = QSTileInput(user, QSTileUserAction.Click(expandable), data) + fun <T> toggleClick( + data: T, + user: UserHandle = UserHandle.CURRENT, + expandable: Expandable? = null, + ): QSTileInput<T> = QSTileInput(user, QSTileUserAction.ToggleClick(expandable), data) + fun <T> longClick( data: T, user: UserHandle = UserHandle.CURRENT, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/data/repository/TouchpadRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/data/repository/TouchpadRepositoryKosmos.kt new file mode 100644 index 000000000000..91e239602b23 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/touchpad/data/repository/TouchpadRepositoryKosmos.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.touchpad.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.touchpadRepository by Kosmos.Fixture { FakeTouchpadRepository() } diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt index 231179b53ce8..5cffdeccbacf 100644 --- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt @@ -222,8 +222,16 @@ android.content.res.ApkAssets android.content.res.AssetFileDescriptor android.content.res.AssetManager android.content.res.AssetManager$Builder +android.content.res.ConfigurationBoundResourceCache +android.content.res.Configuration +android.content.res.CompatibilityInfo +android.content.res.ConstantState android.content.res.DrawableCache android.content.res.Element +android.content.res.FontResourcesParser +android.content.res.FontScaleConverter +android.content.res.FontScaleConverterImpl +android.content.res.FontScaleConverterFactory android.content.res.Resources android.content.res.Resources$Theme android.content.res.ResourceId @@ -231,6 +239,7 @@ android.content.res.ResourcesImpl android.content.res.ResourcesKey android.content.res.StringBlock android.content.res.TagCounter +android.content.res.ThemedResourceCache android.content.res.TypedArray android.content.res.Validator android.content.res.XmlBlock @@ -275,6 +284,7 @@ android.content.ContentProvider android.app.ActivityManager android.app.ActivityOptions +android.app.ApplicationPackageManager android.app.BroadcastOptions android.app.ComponentOptions android.app.Instrumentation @@ -288,6 +298,7 @@ android.metrics.LogMaker android.view.Display android.view.Display$HdrCapabilities android.view.Display$Mode +android.view.DisplayAdjustments android.view.DisplayInfo android.view.inputmethod.InputBinding diff --git a/ravenwood/texts/ravenwood-framework-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt index 3062863052d2..2d49128ae292 100644 --- a/ravenwood/texts/ravenwood-framework-policies.txt +++ b/ravenwood/texts/ravenwood-framework-policies.txt @@ -69,20 +69,3 @@ class android.text.ClipboardManager keep # Just enough to allow ResourcesManager to run class android.hardware.display.DisplayManagerGlobal keep method getInstance ()Landroid/hardware/display/DisplayManagerGlobal; ignore - -# These classes will be properly enabled in follow-up CLs - -class android.content.res.FontResourcesParser keepclass -class android.content.res.FontResourcesParser.FamilyResourceEntry keepclass -class android.content.res.FontResourcesParser.ProviderResourceEntry keepclass -class android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry keepclass -class android.content.res.FontResourcesParser.FontFileResourceEntry keepclass -class android.content.res.FontScaleConverter keepclass -class android.content.res.FontScaleConverterImpl keepclass -class android.content.res.FontScaleConverterFactory keepclass -class android.content.res.ThemedResourceCache keepclass -class android.content.res.ConfigurationBoundResourceCache keepclass -class android.content.res.Configuration keepclass -class android.content.res.CompatibilityInfo keepclass -class android.content.res.ConstantState keepclass -class android.view.DisplayAdjustments keepclass diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java index 191ec69b25c8..6b8e8c74a4e4 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java @@ -23,10 +23,6 @@ import android.app.appfunctions.IAppFunctionManager; import android.app.appfunctions.IAppFunctionService; import android.app.appfunctions.IExecuteAppFunctionCallback; import android.app.appfunctions.SafeOneTimeExecuteAppFunctionCallback; -import android.app.appfunctions.ServiceCallHelper; -import android.app.appfunctions.ServiceCallHelper.RunServiceCallCallback; -import android.app.appfunctions.ServiceCallHelper.ServiceUsageCompleteListener; -import android.app.appfunctions.ServiceCallHelperImpl; import android.content.Context; import android.content.Intent; import android.os.UserHandle; @@ -34,6 +30,8 @@ import android.text.TextUtils; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback; +import com.android.server.appfunctions.RemoteServiceCaller.ServiceUsageCompleteListener; import java.util.Objects; import java.util.concurrent.LinkedBlockingQueue; @@ -45,12 +43,12 @@ import java.util.concurrent.TimeUnit; */ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { private static final String TAG = AppFunctionManagerServiceImpl.class.getSimpleName(); - private final ServiceCallHelper<IAppFunctionService> mExternalServiceCallHelper; + private final RemoteServiceCaller<IAppFunctionService> mRemoteServiceCaller; private final CallerValidator mCallerValidator; private final ServiceHelper mInternalServiceHelper; public AppFunctionManagerServiceImpl(@NonNull Context context) { - this(new ServiceCallHelperImpl<>( + this(new RemoteServiceCallerImpl<>( context, IAppFunctionService.Stub::asInterface, new ThreadPoolExecutor( /*corePoolSize=*/ Runtime.getRuntime().availableProcessors(), @@ -63,11 +61,11 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { } @VisibleForTesting - AppFunctionManagerServiceImpl(ServiceCallHelper<IAppFunctionService> serviceCallHelper, - CallerValidator apiValidator, + AppFunctionManagerServiceImpl(RemoteServiceCaller<IAppFunctionService> remoteServiceCaller, + CallerValidator callerValidator, ServiceHelper appFunctionInternalServiceHelper) { - mExternalServiceCallHelper = Objects.requireNonNull(serviceCallHelper); - mCallerValidator = Objects.requireNonNull(apiValidator); + mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller); + mCallerValidator = Objects.requireNonNull(callerValidator); mInternalServiceHelper = Objects.requireNonNull(appFunctionInternalServiceHelper); } @@ -134,7 +132,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { return; } - // TODO(b/357551503): Offload call to async executor. bindAppFunctionServiceUnchecked(requestInternal, serviceIntent, targetUser, safeExecuteAppFunctionCallback, /*bindFlags=*/ Context.BIND_AUTO_CREATE, @@ -148,12 +145,12 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { @NonNull SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback, int bindFlags, long timeoutInMillis) { - boolean bindServiceResult = mExternalServiceCallHelper.runServiceCall( + boolean bindServiceResult = mRemoteServiceCaller.runServiceCall( serviceIntent, bindFlags, timeoutInMillis, targetUser, - /*timeOutCallback=*/ new RunServiceCallCallback<IAppFunctionService>() { + new RunServiceCallCallback<IAppFunctionService>() { @Override public void onServiceConnected(@NonNull IAppFunctionService service, @NonNull ServiceUsageCompleteListener diff --git a/core/java/android/app/appfunctions/ServiceCallHelper.java b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java index cc882bd4ba4a..98903ae57a39 100644 --- a/core/java/android/app/appfunctions/ServiceCallHelper.java +++ b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.app.appfunctions; +package com.android.server.appfunctions; import android.annotation.NonNull; import android.content.Intent; @@ -27,7 +27,7 @@ import android.os.UserHandle; * @param <T> Class of wrapped service. * @hide */ -public interface ServiceCallHelper<T> { +public interface RemoteServiceCaller<T> { /** * Initiates service binding and executes a provided method when the service connects. Unbinds diff --git a/core/java/android/app/appfunctions/ServiceCallHelperImpl.java b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java index 2e585467f437..c19a02792aec 100644 --- a/core/java/android/app/appfunctions/ServiceCallHelperImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.app.appfunctions; +package com.android.server.appfunctions; import android.annotation.NonNull; import android.content.ComponentName; @@ -30,27 +30,29 @@ import java.util.concurrent.Executor; import java.util.function.Function; /** - * An implementation of {@link android.app.appfunctions.ServiceCallHelper} that that is based on + * An implementation of {@link RemoteServiceCaller} that that is based on * {@link Context#bindService}. * * @param <T> Class of wrapped service. * @hide */ -public class ServiceCallHelperImpl<T> implements ServiceCallHelper<T> { +public class RemoteServiceCallerImpl<T> implements RemoteServiceCaller<T> { private static final String TAG = "AppFunctionsServiceCall"; - @NonNull private final Context mContext; - @NonNull private final Function<IBinder, T> mInterfaceConverter; + @NonNull + private final Context mContext; + @NonNull + private final Function<IBinder, T> mInterfaceConverter; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Executor mExecutor; /** * @param interfaceConverter A function responsible for converting an IBinder object into the - * desired service interface. - * @param executor An Executor instance to dispatch callback. - * @param context The system context. + * desired service interface. + * @param executor An Executor instance to dispatch callback. + * @param context The system context. */ - public ServiceCallHelperImpl( + public RemoteServiceCallerImpl( @NonNull Context context, @NonNull Function<IBinder, T> interfaceConverter, @NonNull Executor executor) { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index f332ed9504c2..4eb50a952c04 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -41,6 +41,7 @@ import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.companion.AssociationInfo; +import android.companion.virtual.ActivityPolicyExemption; import android.companion.virtual.IVirtualDevice; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.IVirtualDeviceIntentInterceptor; @@ -522,44 +523,37 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override // Binder call @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void addActivityPolicyExemption(@NonNull ComponentName componentName) { + public void addActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) { super.addActivityPolicyExemption_enforcePermission(); - synchronized (mVirtualDeviceLock) { - if (mActivityPolicyExemptions.add(componentName)) { - for (int i = 0; i < mVirtualDisplays.size(); i++) { - mVirtualDisplays.valueAt(i).getWindowPolicyController() - .addActivityPolicyExemption(componentName); - } + final int displayId = exemption.getDisplayId(); + if (exemption.getComponentName() == null || displayId != Display.INVALID_DISPLAY) { + if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { + return; } } - } - - @Override // Binder call - @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void removeActivityPolicyExemption(@NonNull ComponentName componentName) { - super.removeActivityPolicyExemption_enforcePermission(); synchronized (mVirtualDeviceLock) { - if (mActivityPolicyExemptions.remove(componentName)) { - for (int i = 0; i < mVirtualDisplays.size(); i++) { - mVirtualDisplays.valueAt(i).getWindowPolicyController() - .removeActivityPolicyExemption(componentName); + if (displayId != Display.INVALID_DISPLAY) { + checkDisplayOwnedByVirtualDeviceLocked(displayId); + if (exemption.getComponentName() != null) { + mVirtualDisplays.get(displayId).getWindowPolicyController() + .addActivityPolicyExemption(exemption.getComponentName()); + } else if (exemption.getPackageName() != null) { + mVirtualDisplays.get(displayId).getWindowPolicyController() + .addActivityPolicyExemption(exemption.getPackageName()); } - } - } - } - - @Override // Binder call - @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void addActivityPolicyPackageExemption(@NonNull String packageName) { - super.addActivityPolicyPackageExemption_enforcePermission(); - if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { - return; - } - synchronized (mVirtualDeviceLock) { - if (mActivityPolicyPackageExemptions.add(packageName)) { - for (int i = 0; i < mVirtualDisplays.size(); i++) { - mVirtualDisplays.valueAt(i).getWindowPolicyController() - .addActivityPolicyExemption(packageName); + } else { + if (exemption.getComponentName() != null + && mActivityPolicyExemptions.add(exemption.getComponentName())) { + for (int i = 0; i < mVirtualDisplays.size(); i++) { + mVirtualDisplays.valueAt(i).getWindowPolicyController() + .addActivityPolicyExemption(exemption.getComponentName()); + } + } else if (exemption.getPackageName() != null + && mActivityPolicyPackageExemptions.add(exemption.getPackageName())) { + for (int i = 0; i < mVirtualDisplays.size(); i++) { + mVirtualDisplays.valueAt(i).getWindowPolicyController() + .addActivityPolicyExemption(exemption.getPackageName()); + } } } } @@ -567,81 +561,42 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override // Binder call @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void removeActivityPolicyPackageExemption(@NonNull String packageName) { - super.removeActivityPolicyPackageExemption_enforcePermission(); - if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { - return; + public void removeActivityPolicyExemption(@NonNull ActivityPolicyExemption exemption) { + super.removeActivityPolicyExemption_enforcePermission(); + final int displayId = exemption.getDisplayId(); + if (exemption.getComponentName() == null || displayId != Display.INVALID_DISPLAY) { + if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { + return; + } } synchronized (mVirtualDeviceLock) { - if (mActivityPolicyPackageExemptions.remove(packageName)) { - for (int i = 0; i < mVirtualDisplays.size(); i++) { - mVirtualDisplays.valueAt(i).getWindowPolicyController() - .removeActivityPolicyExemption(packageName); + if (displayId != Display.INVALID_DISPLAY) { + checkDisplayOwnedByVirtualDeviceLocked(displayId); + if (exemption.getComponentName() != null) { + mVirtualDisplays.get(displayId).getWindowPolicyController() + .removeActivityPolicyExemption(exemption.getComponentName()); + } else if (exemption.getPackageName() != null) { + mVirtualDisplays.get(displayId).getWindowPolicyController() + .removeActivityPolicyExemption(exemption.getPackageName()); + } + } else { + if (exemption.getComponentName() != null + && mActivityPolicyExemptions.remove(exemption.getComponentName())) { + for (int i = 0; i < mVirtualDisplays.size(); i++) { + mVirtualDisplays.valueAt(i).getWindowPolicyController() + .removeActivityPolicyExemption(exemption.getComponentName()); + } + } else if (exemption.getPackageName() != null + && mActivityPolicyPackageExemptions.remove(exemption.getPackageName())) { + for (int i = 0; i < mVirtualDisplays.size(); i++) { + mVirtualDisplays.valueAt(i).getWindowPolicyController() + .removeActivityPolicyExemption(exemption.getPackageName()); + } } } } } - @Override // Binder call - @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void addActivityPolicyExemptionForDisplay( - int displayId, @NonNull ComponentName componentName) { - super.addActivityPolicyExemptionForDisplay_enforcePermission(); - if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { - return; - } - synchronized (mVirtualDeviceLock) { - checkDisplayOwnedByVirtualDeviceLocked(displayId); - mVirtualDisplays.get(displayId).getWindowPolicyController() - .addActivityPolicyExemption(componentName); - } - } - - @Override // Binder call - @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void removeActivityPolicyExemptionForDisplay( - int displayId, @NonNull ComponentName componentName) { - super.removeActivityPolicyExemptionForDisplay_enforcePermission(); - if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { - return; - } - synchronized (mVirtualDeviceLock) { - checkDisplayOwnedByVirtualDeviceLocked(displayId); - mVirtualDisplays.get(displayId).getWindowPolicyController() - .removeActivityPolicyExemption(componentName); - } - } - - @Override // Binder call - @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void addActivityPolicyPackageExemptionForDisplay( - int displayId, @NonNull String packageName) { - super.addActivityPolicyPackageExemptionForDisplay_enforcePermission(); - if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { - return; - } - synchronized (mVirtualDeviceLock) { - checkDisplayOwnedByVirtualDeviceLocked(displayId); - mVirtualDisplays.get(displayId).getWindowPolicyController() - .addActivityPolicyExemption(packageName); - } - } - - @Override // Binder call - @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) - public void removeActivityPolicyPackageExemptionForDisplay( - int displayId, @NonNull String packageName) { - super.removeActivityPolicyPackageExemptionForDisplay_enforcePermission(); - if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) { - return; - } - synchronized (mVirtualDeviceLock) { - checkDisplayOwnedByVirtualDeviceLocked(displayId); - mVirtualDisplays.get(displayId).getWindowPolicyController() - .removeActivityPolicyExemption(packageName); - } - } - private void sendPendingIntent(int displayId, PendingIntent pendingIntent) throws PendingIntent.CanceledException { final ActivityOptions options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 27024a7e7997..a27360df798a 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -125,9 +125,9 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.LatencyTracker; import com.android.internal.util.Preconditions; +import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.EventLogTags; import com.android.server.LockGuard; -import com.android.server.RescueParty; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.UiThread; @@ -4031,7 +4031,7 @@ public final class PowerManagerService extends SystemService } } if (mHandler == null || !mSystemReady) { - if (RescueParty.isRecoveryTriggeredReboot()) { + if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) { // If we're stuck in a really low-level reboot loop, and a // rescue party is trying to prompt the user for a factory data // reset, we must GET TO DA CHOPPA! diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 4b4e442b7b84..d209ea90f3ca 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -59,8 +59,8 @@ import android.view.SurfaceControl; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.LocalServices; -import com.android.server.RescueParty; import com.android.server.statusbar.StatusBarManagerInternal; import java.io.File; @@ -339,7 +339,7 @@ public final class ShutdownThread extends Thread { com.android.internal.R.string.reboot_to_update_reboot)); } } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) { - if (RescueParty.isRecoveryTriggeredReboot()) { + if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) { // We're not actually doing a factory reset yet; we're rebooting // to ask the user if they'd like to reset, so give them a less // scary dialog message. diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index b768bb155563..e76e94d58800 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1804,7 +1804,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // If on a rotation leash, the wallpaper token surface needs to be shown explicitly // because shell only gets the leash and the wallpaper token surface is not allowed // to be changed by non-transition logic until the transition is finished. - if (Flags.ensureWallpaperInTransitions() && wp.isVisibleRequested() + if (wp.mWmService.mFlags.mEnsureWallpaperInTransitions && wp.isVisibleRequested() && wp.getFixedRotationLeash() != null) { transaction.show(wp.mSurfaceControl); } @@ -2216,7 +2216,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (wallpaper != null) { if (!wallpaper.isVisible() && wallpaper.isVisibleRequested()) { wallpaper.commitVisibility(showWallpaper); - } else if (Flags.ensureWallpaperInTransitions() && wallpaper.isVisible() + } else if (wallpaper.mWmService.mFlags.mEnsureWallpaperInTransitions + && wallpaper.isVisible() && !showWallpaper && !wallpaper.getDisplayContent().isKeyguardLocked() && !wallpaperIsOwnTarget(wallpaper)) { wallpaper.setVisibleRequested(false); @@ -2934,7 +2935,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Use parent rotation because shell doesn't know the surface is rotated. endRotation = parent.getWindowConfiguration().getRotation(); } - } else if (isWallpaper(target) && Flags.ensureWallpaperInTransitions() + } else if (isWallpaper(target) && target.mWmService.mFlags.mEnsureWallpaperInTransitions && target.getRelativeDisplayRotation() != 0 && !target.mTransitionController.useShellTransitionsRotation()) { // If the wallpaper is "fixed-rotated", shell is unaware of this, so use the diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index db95d961f9fd..4536f244215c 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -59,7 +59,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.server.wallpaper.WallpaperCropper.WallpaperCropUtils; -import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.ArrayList; @@ -759,7 +758,7 @@ class WallpaperController { void collectTopWallpapers(Transition transition) { if (mFindResults.hasTopShowWhenLockedWallpaper()) { - if (Flags.ensureWallpaperInTransitions()) { + if (mService.mFlags.mEnsureWallpaperInTransitions) { transition.collect(mFindResults.mTopWallpaper.mTopShowWhenLockedWallpaper.mToken); } else { transition.collect(mFindResults.mTopWallpaper.mTopShowWhenLockedWallpaper); @@ -767,7 +766,7 @@ class WallpaperController { } if (mFindResults.hasTopHideWhenLockedWallpaper()) { - if (Flags.ensureWallpaperInTransitions()) { + if (mService.mFlags.mEnsureWallpaperInTransitions) { transition.collect(mFindResults.mTopWallpaper.mTopHideWhenLockedWallpaper.mToken); } else { transition.collect(mFindResults.mTopWallpaper.mTopHideWhenLockedWallpaper); diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 31156de5debf..384d111eb058 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -32,7 +32,6 @@ import android.os.RemoteException; import android.util.SparseArray; import com.android.internal.protolog.ProtoLog; -import com.android.window.flags.Flags; import java.util.function.Consumer; @@ -85,7 +84,7 @@ class WallpaperWindowToken extends WindowToken { public void prepareSurfaces() { super.prepareSurfaces(); - if (Flags.ensureWallpaperInTransitions()) { + if (mWmService.mFlags.mEnsureWallpaperInTransitions) { // Similar to Task.prepareSurfaces, outside of transitions we need to apply visibility // changes directly. In transitions the transition player will take care of applying the // visibility change. diff --git a/services/core/java/com/android/server/wm/WindowManagerFlags.java b/services/core/java/com/android/server/wm/WindowManagerFlags.java index f3e6a184ce45..7ef8d8d0c16a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerFlags.java +++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java @@ -16,6 +16,9 @@ package com.android.server.wm; +import android.app.AppGlobals; +import android.content.pm.PackageManager; + import com.android.window.flags.Flags; /** @@ -53,5 +56,26 @@ class WindowManagerFlags { final boolean mRespectNonTopVisibleFixedOrientation = Flags.respectNonTopVisibleFixedOrientation(); + final boolean mEnsureWallpaperInTransitions; + /* End Available Flags */ + + WindowManagerFlags() { + boolean isWatch; + try { + isWatch = AppGlobals.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WATCH, 0 /* version */); + } catch (Throwable e) { + isWatch = false; + } + /* + * Wallpaper enablement is separated on Wear vs Phone as the latter appears to still exhibit + * regressions when enabled (for example b/353870983). These don't exist on Wear likely + * due to differences in SysUI/transition implementations. Wear enablement is required for + * 25Q2 while phone doesn't have as pressing a constraint and will wait to resolve any + * outstanding issues prior to roll-out. + */ + mEnsureWallpaperInTransitions = (isWatch && Flags.ensureWallpaperInWearTransitions()) + || Flags.ensureWallpaperInTransitions(); + } } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 24a2a626fe50..b40cf56c2501 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -67,9 +67,8 @@ import android.view.WindowManager.LayoutParams; import android.view.animation.Animation; import android.view.animation.AnimationUtils; -import com.android.internal.protolog.common.LogLevel; import com.android.internal.protolog.ProtoLog; -import com.android.window.flags.Flags; +import com.android.internal.protolog.common.LogLevel; import com.android.server.policy.WindowManagerPolicy; import java.io.PrintWriter; @@ -413,7 +412,7 @@ class WindowStateAnimator { ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY: %s. %s", mWin, new RuntimeException().fillInStackTrace()); destroySurface(t); - if (Flags.ensureWallpaperInTransitions()) { + if (mService.mFlags.mEnsureWallpaperInTransitions) { if (mWallpaperControllerLocked.isWallpaperTarget(mWin)) { mWin.requestUpdateWallpaperIfNeeded(); } @@ -464,7 +463,7 @@ class WindowStateAnimator { if (!w.isOnScreen()) { hide(t, "prepareSurfaceLocked"); - if (!w.mIsWallpaper || !Flags.ensureWallpaperInTransitions()) { + if (!w.mIsWallpaper || !mService.mFlags.mEnsureWallpaperInTransitions) { mWallpaperControllerLocked.hideWallpapers(w); } |