diff options
162 files changed, 3244 insertions, 870 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 1d03370e698d..a79df58c7916 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1298,7 +1298,7 @@ package android { field public static final int shortcutLongLabel = 16844074; // 0x101052a field public static final int shortcutShortLabel = 16844073; // 0x1010529 field public static final int shouldDisableView = 16843246; // 0x10101ee - field public static final int shouldUseDefaultDisplayStateChangeTransition; + field public static final int shouldUseDefaultUnfoldTransition; field public static final int showAsAction = 16843481; // 0x10102d9 field public static final int showDefault = 16843258; // 0x10101fa field public static final int showDividers = 16843561; // 0x1010329 @@ -6927,7 +6927,7 @@ package android.app { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager); - method public boolean shouldUseDefaultDisplayStateChangeTransition(); + method public boolean shouldUseDefaultUnfoldTransition(); method public boolean supportsMultipleDisplays(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR; @@ -17949,6 +17949,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DeviceStateOrientationMap> INFO_DEVICE_STATE_ORIENTATION_MAP; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.String> INFO_VERSION; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES; @@ -18643,6 +18644,12 @@ package android.hardware.camera2.params { method public android.util.Rational getElement(int, int); } + public final class DeviceStateOrientationMap { + method public int getSensorOrientation(long); + field public static final long FOLDED = 4L; // 0x4L + field public static final long NORMAL = 0L; // 0x0L + } + public final class ExtensionSessionConfiguration { ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback); method @NonNull public java.util.concurrent.Executor getExecutor(); diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index a969b10c15a3..99d406446dae 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -81,7 +81,7 @@ public final class WallpaperInfo implements Parcelable { final int mContextDescriptionResource; final boolean mShowMetadataInPreview; final boolean mSupportsAmbientMode; - final boolean mShouldUseDefaultDisplayStateChangeTransition; + final boolean mShouldUseDefaultUnfoldTransition; final String mSettingsSliceUri; final boolean mSupportMultipleDisplays; @@ -146,9 +146,9 @@ public final class WallpaperInfo implements Parcelable { mSupportsAmbientMode = sa.getBoolean( com.android.internal.R.styleable.Wallpaper_supportsAmbientMode, false); - mShouldUseDefaultDisplayStateChangeTransition = sa.getBoolean( + mShouldUseDefaultUnfoldTransition = sa.getBoolean( com.android.internal.R.styleable - .Wallpaper_shouldUseDefaultDisplayStateChangeTransition, true); + .Wallpaper_shouldUseDefaultUnfoldTransition, true); mSettingsSliceUri = sa.getString( com.android.internal.R.styleable.Wallpaper_settingsSliceUri); mSupportMultipleDisplays = sa.getBoolean( @@ -175,7 +175,7 @@ public final class WallpaperInfo implements Parcelable { mSupportsAmbientMode = source.readInt() != 0; mSettingsSliceUri = source.readString(); mSupportMultipleDisplays = source.readInt() != 0; - mShouldUseDefaultDisplayStateChangeTransition = source.readInt() != 0; + mShouldUseDefaultUnfoldTransition = source.readInt() != 0; mService = ResolveInfo.CREATOR.createFromParcel(source); } @@ -400,24 +400,24 @@ public final class WallpaperInfo implements Parcelable { /** * Returns whether this wallpaper should receive default zooming updates when the device - * changes its display state (e.g. when folding or unfolding a foldable device). + * changes its state (e.g. when folding or unfolding a foldable device). * If set to false the wallpaper will not receive zoom events when changing the device state, * so it can implement its own transition instead. * <p> * This corresponds to the value {@link - * android.R.styleable#Wallpaper_shouldUseDefaultDisplayStateChangeTransition} in the + * android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition} in the * XML description of the wallpaper. * <p> * The default value is {@code true}. * - * @see android.R.styleable#Wallpaper_shouldUseDefaultDisplayStateChangeTransition + * @see android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition * @return {@code true} if wallpaper should receive default device state change * transition updates * - * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultDisplayStateChangeTransition + * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition */ - public boolean shouldUseDefaultDisplayStateChangeTransition() { - return mShouldUseDefaultDisplayStateChangeTransition; + public boolean shouldUseDefaultUnfoldTransition() { + return mShouldUseDefaultUnfoldTransition; } public void dump(Printer pw, String prefix) { @@ -450,7 +450,7 @@ public final class WallpaperInfo implements Parcelable { dest.writeInt(mSupportsAmbientMode ? 1 : 0); dest.writeString(mSettingsSliceUri); dest.writeInt(mSupportMultipleDisplays ? 1 : 0); - dest.writeInt(mShouldUseDefaultDisplayStateChangeTransition ? 1 : 0); + dest.writeInt(mShouldUseDefaultUnfoldTransition ? 1 : 0); mService.writeToParcel(dest, flags); } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index e0138c5db178..ddac22cd42a3 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -22,15 +22,18 @@ import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; +import android.hardware.camera2.params.DeviceStateOrientationMap; import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.utils.TypeReference; import android.os.Build; +import android.util.Log; import android.util.Rational; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -202,8 +205,25 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri private List<CaptureResult.Key<?>> mAvailableResultKeys; private ArrayList<RecommendedStreamConfigurationMap> mRecommendedConfigurations; + private final Object mLock = new Object(); + @GuardedBy("mLock") + private boolean mFoldedDeviceState; + + private final CameraManager.DeviceStateListener mFoldStateListener = + new CameraManager.DeviceStateListener() { + @Override + public final void onDeviceStateChanged(boolean folded) { + synchronized (mLock) { + mFoldedDeviceState = folded; + } + }}; + + private static final String TAG = "CameraCharacteristics"; + /** * Takes ownership of the passed-in properties object + * + * @param properties Camera properties. * @hide */ public CameraCharacteristics(CameraMetadataNative properties) { @@ -220,6 +240,41 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri } /** + * Return the device state listener for this Camera characteristics instance + */ + CameraManager.DeviceStateListener getDeviceStateListener() { return mFoldStateListener; } + + /** + * Overrides the property value + * + * <p>Check whether a given property value needs to be overridden in some specific + * case.</p> + * + * @param key The characteristics field to override. + * @return The value of overridden property, or {@code null} if the property doesn't need an + * override. + */ + @Nullable + private <T> T overrideProperty(Key<T> key) { + if (CameraCharacteristics.SENSOR_ORIENTATION.equals(key) && (mFoldStateListener != null) && + (mProperties.get(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATIONS) != null)) { + DeviceStateOrientationMap deviceStateOrientationMap = + mProperties.get(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATION_MAP); + synchronized (mLock) { + Integer ret = deviceStateOrientationMap.getSensorOrientation(mFoldedDeviceState ? + DeviceStateOrientationMap.FOLDED : DeviceStateOrientationMap.NORMAL); + if (ret >= 0) { + return (T) ret; + } else { + Log.w(TAG, "No valid device state to orientation mapping! Using default!"); + } + } + } + + return null; + } + + /** * Get a camera characteristics field value. * * <p>The field definitions can be @@ -235,7 +290,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri */ @Nullable public <T> T get(Key<T> key) { - return mProperties.get(key); + T propertyOverride = overrideProperty(key); + return (propertyOverride != null) ? propertyOverride : mProperties.get(key); } /** @@ -3993,11 +4049,26 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * upright on the device screen in its native orientation.</p> * <p>Also defines the direction of rolling shutter readout, which is from top to bottom in * the sensor's coordinate system.</p> + * <p>Starting with Android API level 32, camera clients that query the orientation via + * {@link android.hardware.camera2.CameraCharacteristics#get } on foldable devices which + * include logical cameras can receive a value that can dynamically change depending on the + * device/fold state. + * Clients are advised to not cache or store the orientation value of such logical sensors. + * In case repeated queries to CameraCharacteristics are not preferred, then clients can + * also access the entire mapping from device state to sensor orientation in + * {@link android.hardware.camera2.params.DeviceStateOrientationMap }. + * Do note that a dynamically changing sensor orientation value in camera characteristics + * will not be the best way to establish the orientation per frame. Clients that want to + * know the sensor orientation of a particular captured frame should query the + * {@link CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID android.logicalMultiCamera.activePhysicalId} from the corresponding capture result and + * check the respective physical camera orientation.</p> * <p><b>Units</b>: Degrees of clockwise rotation; always a multiple of * 90</p> * <p><b>Range of valid values:</b><br> * 0, 90, 180, 270</p> * <p>This key is available on all devices.</p> + * + * @see CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID */ @PublicKey @NonNull @@ -4307,6 +4378,46 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<String>("android.info.version", String.class); /** + * <p>This lists the mapping between a device folding state and + * specific camera sensor orientation for logical cameras on a foldable device.</p> + * <p>Logical cameras on foldable devices can support sensors with different orientation + * values. The orientation value may need to change depending on the specific folding + * state. Information about the mapping between the device folding state and the + * sensor orientation can be obtained in + * {@link android.hardware.camera2.params.DeviceStateOrientationMap }. + * Device state orientation maps are optional and maybe present on devices that support + * {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop}.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * <p><b>Limited capability</b> - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + @PublicKey + @NonNull + @SyntheticKey + public static final Key<android.hardware.camera2.params.DeviceStateOrientationMap> INFO_DEVICE_STATE_ORIENTATION_MAP = + new Key<android.hardware.camera2.params.DeviceStateOrientationMap>("android.info.deviceStateOrientationMap", android.hardware.camera2.params.DeviceStateOrientationMap.class); + + /** + * <p>HAL must populate the array with + * (hardware::camera::provider::V2_5::DeviceState, sensorOrientation) pairs for each + * supported device state bitwise combination.</p> + * <p><b>Units</b>: (device fold state, sensor orientation) x n</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * <p><b>Limited capability</b> - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + public static final Key<long[]> INFO_DEVICE_STATE_ORIENTATIONS = + new Key<long[]>("android.info.deviceStateOrientations", long[].class); + + /** * <p>The maximum number of frames that can occur after a request * (different than the previous) has been submitted, and before the * result's state becomes synchronized.</p> diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 5833b3dbef86..9bb901f8c5f7 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -30,15 +30,19 @@ import android.hardware.ICameraServiceListener; import android.hardware.camera2.impl.CameraDeviceImpl; import android.hardware.camera2.impl.CameraInjectionSessionImpl; import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.params.DeviceStateOrientationMap; import android.hardware.camera2.params.ExtensionSessionConfiguration; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.utils.CameraIdAndSessionConfiguration; import android.hardware.camera2.utils.ConcurrentCameraIdCombination; +import android.hardware.devicestate.DeviceStateManager; import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.DeadObjectException; import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -50,6 +54,10 @@ import android.util.Log; import android.util.Size; import android.view.Display; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ArrayUtils; + +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -97,6 +105,80 @@ public final class CameraManager { synchronized(mLock) { mContext = context; } + + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mFoldStateListener = new FoldStateListener(context); + context.getSystemService(DeviceStateManager.class) + .registerCallback(new HandlerExecutor(mHandler), mFoldStateListener); + } + + private HandlerThread mHandlerThread; + private Handler mHandler; + private FoldStateListener mFoldStateListener; + @GuardedBy("mLock") + private ArrayList<WeakReference<DeviceStateListener>> mDeviceStateListeners = new ArrayList<>(); + private boolean mFoldedDeviceState; + + /** + * @hide + */ + public interface DeviceStateListener { + void onDeviceStateChanged(boolean folded); + } + + private final class FoldStateListener implements DeviceStateManager.DeviceStateCallback { + private final int[] mFoldedDeviceStates; + + public FoldStateListener(Context context) { + mFoldedDeviceStates = context.getResources().getIntArray( + com.android.internal.R.array.config_foldedDeviceStates); + } + + private void handleStateChange(int state) { + boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state); + synchronized (mLock) { + mFoldedDeviceState = folded; + ArrayList<WeakReference<DeviceStateListener>> invalidListeners = new ArrayList<>(); + for (WeakReference<DeviceStateListener> listener : mDeviceStateListeners) { + DeviceStateListener callback = listener.get(); + if (callback != null) { + callback.onDeviceStateChanged(folded); + } else { + invalidListeners.add(listener); + } + } + if (!invalidListeners.isEmpty()) { + mDeviceStateListeners.removeAll(invalidListeners); + } + } + } + + @Override + public final void onBaseStateChanged(int state) { + handleStateChange(state); + } + + @Override + public final void onStateChanged(int state) { + handleStateChange(state); + } + } + + /** + * Register a {@link CameraCharacteristics} device state listener + * + * @param chars Camera characteristics that need to receive device state updates + * + * @hide + */ + public void registerDeviceStateListener(@NonNull CameraCharacteristics chars) { + synchronized (mLock) { + DeviceStateListener listener = chars.getDeviceStateListener(); + listener.onDeviceStateChanged(mFoldedDeviceState); + mDeviceStateListeners.add(new WeakReference<>(listener)); + } } /** @@ -504,6 +586,7 @@ public final class CameraManager { "Camera service is currently unavailable", e); } } + registerDeviceStateListener(characteristics); return characteristics; } @@ -1327,8 +1410,7 @@ public final class CameraManager { private ICameraService mCameraService; // Singleton, don't allow construction - private CameraManagerGlobal() { - } + private CameraManagerGlobal() { } public static final boolean sCameraServiceDisabled = SystemProperties.getBoolean("config.disable_cameraservice", false); diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 196134b397cb..37450222aca9 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -50,6 +50,7 @@ import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration; import android.hardware.camera2.marshal.impl.MarshalQueryableString; import android.hardware.camera2.params.Capability; +import android.hardware.camera2.params.DeviceStateOrientationMap; import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; @@ -754,7 +755,7 @@ public class CameraMetadataNative implements Parcelable { }); sGetCommandMap.put( CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(), - new GetCommand() { + new GetCommand() { @Override @SuppressWarnings("unchecked") public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { @@ -762,6 +763,15 @@ public class CameraMetadataNative implements Parcelable { } }); sGetCommandMap.put( + CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATION_MAP.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { + return (T) metadata.getDeviceStateOrientationMap(); + } + }); + sGetCommandMap.put( CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(), new GetCommand() { @Override @@ -994,6 +1004,18 @@ public class CameraMetadataNative implements Parcelable { return map; } + private DeviceStateOrientationMap getDeviceStateOrientationMap() { + long[] mapArray = getBase(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATIONS); + + // Do not warn if map is null while s is not. This is valid. + if (mapArray == null) { + return null; + } + + DeviceStateOrientationMap map = new DeviceStateOrientationMap(mapArray); + return map; + } + private Location getGpsLocation() { String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD); double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES); diff --git a/core/java/android/hardware/camera2/params/DeviceStateOrientationMap.java b/core/java/android/hardware/camera2/params/DeviceStateOrientationMap.java new file mode 100644 index 000000000000..3907f040759c --- /dev/null +++ b/core/java/android/hardware/camera2/params/DeviceStateOrientationMap.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2.params; + +import android.annotation.LongDef; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.utils.HashCodeHelpers; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Objects; + +/** + * Immutable class that maps the device fold state to sensor orientation. + * + * <p>Some {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA logical} + * cameras on foldables can include physical sensors with different sensor orientation + * values. As a result, the values of the logical camera device can potentially change depending + * on the device fold state.</p> + * + * <p>The device fold state to sensor orientation map will contain information about the + * respective logical camera sensor orientation given a device state. Clients + * can query the mapping for all possible supported folded states. + * + * @see CameraCharacteristics#SENSOR_ORIENTATION + */ +public final class DeviceStateOrientationMap { + /** + * Needs to be kept in sync with the HIDL/AIDL DeviceState + */ + + /** + * The device is in its normal physical configuration. This is the default if the + * device does not support multiple different states. + */ + public static final long NORMAL = 0; + + /** + * The device is folded. If not set, the device is unfolded or does not + * support folding. + * + * The exact point when this status change happens during the folding + * operation is device-specific. + */ + public static final long FOLDED = 1 << 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @LongDef(prefix = {"DEVICE_STATE"}, value = + {NORMAL, + FOLDED }) + public @interface DeviceState {}; + + private final HashMap<Long, Integer> mDeviceStateOrientationMap = new HashMap<>(); + + /** + * Create a new immutable DeviceStateOrientationMap instance. + * + * <p>This constructor takes over the array; do not write to the array afterwards.</p> + * + * @param elements + * An array of elements describing the map + * + * @throws IllegalArgumentException + * if the {@code elements} array length is invalid, not divisible by 2 or contains + * invalid element values + * @throws NullPointerException + * if {@code elements} is {@code null} + * + * @hide + */ + public DeviceStateOrientationMap(final long[] elements) { + mElements = Objects.requireNonNull(elements, "elements must not be null"); + if ((elements.length % 2) != 0) { + throw new IllegalArgumentException("Device state orientation map length " + + elements.length + " is not even!"); + } + + for (int i = 0; i < elements.length; i += 2) { + if ((elements[i+1] % 90) != 0) { + throw new IllegalArgumentException("Sensor orientation not divisible by 90: " + + elements[i+1]); + } + + mDeviceStateOrientationMap.put(elements[i], Math.toIntExact(elements[i + 1])); + } + } + + /** + * Return the logical camera sensor orientation given a specific device fold state. + * + * @param deviceState Device fold state + * + * @return Valid {@link android.hardware.camera2.CameraCharacteristics#SENSOR_ORIENTATION} for + * any supported device fold state + * + * @throws IllegalArgumentException if the given device state is invalid + */ + public int getSensorOrientation(@DeviceState long deviceState) { + if (!mDeviceStateOrientationMap.containsKey(deviceState)) { + throw new IllegalArgumentException("Invalid device state: " + deviceState); + } + + return mDeviceStateOrientationMap.get(deviceState); + } + + /** + * Check if this DeviceStateOrientationMap is equal to another DeviceStateOrientationMap. + * + * <p>Two device state orientation maps are equal if and only if all of their elements are + * {@link Object#equals equal}.</p> + * + * @return {@code true} if the objects were equal, {@code false} otherwise + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (obj instanceof DeviceStateOrientationMap) { + final DeviceStateOrientationMap other = (DeviceStateOrientationMap) obj; + return Arrays.equals(mElements, other.mElements); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return HashCodeHelpers.hashCodeGeneric(mElements); + } + + private final long[] mElements; +} diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 5b8dc4055509..c786f0f3cc68 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -23,6 +23,7 @@ import static android.graphics.Matrix.MSKEW_Y; import static android.graphics.Matrix.MTRANS_X; import static android.graphics.Matrix.MTRANS_Y; import static android.view.SurfaceControlProto.HASH_CODE; +import static android.view.SurfaceControlProto.LAYER_ID; import static android.view.SurfaceControlProto.NAME; import android.annotation.FloatRange; @@ -242,6 +243,7 @@ public final class SurfaceControl implements Parcelable { private static native int nativeGetGPUContextPriority(); private static native void nativeSetTransformHint(long nativeObject, int transformHint); private static native int nativeGetTransformHint(long nativeObject); + private static native int nativeGetLayerId(long nativeObject); @Nullable @GuardedBy("mLock") @@ -357,8 +359,6 @@ public final class SurfaceControl implements Parcelable { @GuardedBy("mLock") private int mHeight; - private int mTransformHint; - private WeakReference<View> mLocalOwnerView; static GlobalTransactionWrapper sGlobalTransaction; @@ -1541,6 +1541,7 @@ public final class SurfaceControl implements Parcelable { final long token = proto.start(fieldId); proto.write(HASH_CODE, System.identityHashCode(this)); proto.write(NAME, mName); + proto.write(LAYER_ID, getLayerId()); proto.end(token); } @@ -3675,4 +3676,15 @@ public final class SurfaceControl implements Parcelable { public void setTransformHint(@Surface.Rotation int transformHint) { nativeSetTransformHint(mNativeObject, transformHint); } + + /** + * @hide + */ + public int getLayerId() { + if (mNativeObject != 0) { + return nativeGetLayerId(mNativeObject); + } + + return -1; + } } diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java index 0307268a28b5..93baa193570d 100644 --- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java @@ -16,6 +16,8 @@ package com.android.internal.os; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT; + import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.BatteryUsageStats; @@ -32,8 +34,9 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { private final UsageBasedPowerEstimator mPowerEstimator; public AmbientDisplayPowerCalculator(PowerProfile powerProfile) { + // TODO(b/200239964): update to support multidisplay. mPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)); + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0)); } /** diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index add2304afe9d..4d19b35b1e16 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -17,10 +17,12 @@ package com.android.internal.os; +import android.annotation.StringDef; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; @@ -30,6 +32,8 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashMap; @@ -40,6 +44,8 @@ import java.util.HashMap; */ public class PowerProfile { + public static final String TAG = "PowerProfile"; + /* * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should @@ -145,12 +151,18 @@ public class PowerProfile { /** * Power consumption when screen is in doze/ambient/always-on mode, including backlight power. + * + * @deprecated Use {@link #POWER_GROUP_DISPLAY_AMBIENT} instead. */ + @Deprecated public static final String POWER_AMBIENT_DISPLAY = "ambient.on"; /** * Power consumption when screen is on, not including the backlight power. + * + * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_ON} instead. */ + @Deprecated @UnsupportedAppUsage public static final String POWER_SCREEN_ON = "screen.on"; @@ -175,7 +187,10 @@ public class PowerProfile { /** * Power consumption at full backlight brightness. If the backlight is at * 50% brightness, then this should be multiplied by 0.5 + * + * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_FULL} instead. */ + @Deprecated @UnsupportedAppUsage public static final String POWER_SCREEN_FULL = "screen.full"; @@ -221,6 +236,29 @@ public class PowerProfile { public static final String POWER_BATTERY_CAPACITY = "battery.capacity"; /** + * Power consumption when a screen is in doze/ambient/always-on mode, including backlight power. + */ + public static final String POWER_GROUP_DISPLAY_AMBIENT = "ambient.on.display"; + + /** + * Power consumption when a screen is on, not including the backlight power. + */ + public static final String POWER_GROUP_DISPLAY_SCREEN_ON = "screen.on.display"; + + /** + * Power consumption of a screen at full backlight brightness. + */ + public static final String POWER_GROUP_DISPLAY_SCREEN_FULL = "screen.full.display"; + + @StringDef(prefix = { "POWER_GROUP_" }, value = { + POWER_GROUP_DISPLAY_AMBIENT, + POWER_GROUP_DISPLAY_SCREEN_ON, + POWER_GROUP_DISPLAY_SCREEN_FULL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PowerGroup {} + + /** * A map from Power Use Item to its power consumption. */ static final HashMap<String, Double> sPowerItemMap = new HashMap<>(); @@ -255,6 +293,7 @@ public class PowerProfile { readPowerValuesFromXml(context, forTest); } initCpuClusters(); + initDisplays(); } } @@ -424,6 +463,58 @@ public class PowerProfile { return 0; } + private int mNumDisplays; + + private void initDisplays() { + // Figure out how many displays are listed in the power profile. + mNumDisplays = 0; + while (!Double.isNaN( + getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, mNumDisplays, Double.NaN)) + || !Double.isNaN( + getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, mNumDisplays, Double.NaN)) + || !Double.isNaN( + getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, mNumDisplays, + Double.NaN))) { + mNumDisplays++; + } + + // Handle legacy display power constants. + final Double deprecatedAmbientDisplay = sPowerItemMap.get(POWER_AMBIENT_DISPLAY); + boolean legacy = false; + if (deprecatedAmbientDisplay != null && mNumDisplays == 0) { + final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_AMBIENT, 0); + Slog.w(TAG, POWER_AMBIENT_DISPLAY + " is deprecated! Use " + key + " instead."); + sPowerItemMap.put(key, deprecatedAmbientDisplay); + legacy = true; + } + + final Double deprecatedScreenOn = sPowerItemMap.get(POWER_SCREEN_ON); + if (deprecatedScreenOn != null && mNumDisplays == 0) { + final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_ON, 0); + Slog.w(TAG, POWER_SCREEN_ON + " is deprecated! Use " + key + " instead."); + sPowerItemMap.put(key, deprecatedScreenOn); + legacy = true; + } + + final Double deprecatedScreenFull = sPowerItemMap.get(POWER_SCREEN_FULL); + if (deprecatedScreenFull != null && mNumDisplays == 0) { + final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_FULL, 0); + Slog.w(TAG, POWER_SCREEN_FULL + " is deprecated! Use " + key + " instead."); + sPowerItemMap.put(key, deprecatedScreenFull); + legacy = true; + } + if (legacy) { + mNumDisplays = 1; + } + } + + /** + * Returns the number built in displays on the device as defined in the power_profile.xml. + */ + public int getNumDisplays() { + return mNumDisplays; + } + /** * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a * default value if the subsystem has no recorded value. @@ -496,6 +587,32 @@ public class PowerProfile { } /** + * Returns the average current in mA consumed by an ordinaled subsystem, or the given + * default value if the subsystem has no recorded value. + * + * @param group the subsystem {@link PowerGroup}. + * @param ordinal which entity in the {@link PowerGroup}. + * @param defaultValue the value to return if the subsystem has no recorded value. + * @return the average current in milliAmps. + */ + public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal, + double defaultValue) { + final String type = getOrdinalPowerType(group, ordinal); + return getAveragePowerOrDefault(type, defaultValue); + } + + /** + * Returns the average current in mA consumed by an ordinaled subsystem. + * + * @param group the subsystem {@link PowerGroup}. + * @param ordinal which entity in the {@link PowerGroup}. + * @return the average current in milliAmps. + */ + public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal) { + return getAveragePowerForOrdinal(group, ordinal, 0); + } + + /** * Returns the battery capacity, if available, in milli Amp Hours. If not available, * it returns zero. * @@ -682,4 +799,9 @@ public class PowerProfile { } } } + + // Creates the key for an ordinaled power constant from the group and ordinal. + private static String getOrdinalPowerType(@PowerGroup String group, int ordinal) { + return group + ordinal; + } } diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java index 1b3bc234fc0f..72ad4e72707a 100644 --- a/core/java/com/android/internal/os/ScreenPowerCalculator.java +++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java @@ -16,6 +16,9 @@ package com.android.internal.os; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON; + import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.BatteryUsageStats; @@ -50,10 +53,11 @@ public class ScreenPowerCalculator extends PowerCalculator { } public ScreenPowerCalculator(PowerProfile powerProfile) { + // TODO(b/200239964): update to support multidisplay. mScreenOnPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON)); + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0)); mScreenFullPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL)); + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0)); } @Override diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 5ce43df53819..65ff7c7f5a0f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -1827,6 +1827,12 @@ static jint nativeGetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfac return toRotationInt(ui::Transform::toRotation((transformHintRotationFlags))); } +static jint nativeGetLayerId(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl) { + sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl*>(nativeSurfaceControl)); + + return surface->getLayerId(); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { @@ -2026,6 +2032,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetTrustedOverlay }, {"nativeSetDropInputMode", "(JJI)V", (void*)nativeSetDropInputMode }, + {"nativeGetLayerId", "(J)I", + (void*)nativeGetLayerId }, // clang-format on }; diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 0121bff3e7ef..4af9d75682bb 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -480,6 +480,7 @@ message WindowContainerProto { optional SurfaceAnimatorProto surface_animator = 4; repeated WindowContainerChildProto children = 5; optional IdentifierProto identifier = 6; + optional .android.view.SurfaceControlProto surface_control = 7; } /* represents a generic child of a WindowContainer */ diff --git a/core/proto/android/view/surfacecontrol.proto b/core/proto/android/view/surfacecontrol.proto index cbb243ba7872..5a5f035412b2 100644 --- a/core/proto/android/view/surfacecontrol.proto +++ b/core/proto/android/view/surfacecontrol.proto @@ -29,4 +29,5 @@ message SurfaceControlProto { optional int32 hash_code = 1; optional string name = 2 [ (android.privacy).dest = DEST_EXPLICIT ]; + optional int32 layerId = 3; } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 77820d1dfa38..ab39152fc10f 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8372,7 +8372,7 @@ <attr name="supportsAmbientMode" format="boolean" /> <!-- Indicates that this wallpaper service should receive zoom transition updates when - changing the display state of the device (e.g. when folding or unfolding + changing the structural state of the device (e.g. when folding or unfolding a foldable device). When this value is set to true {@link android.service.wallpaper.WallpaperService.Engine} could receive zoom updates before or after changing the device state. Wallpapers receive zoom updates using @@ -8381,8 +8381,8 @@ {@link android.service.wallpaper.WallpaperService.Engine} is created and not destroyed. Default value is true. Corresponds to - {@link android.app.WallpaperInfo#shouldUseDefaultDisplayStateChangeTransition()} --> - <attr name="shouldUseDefaultDisplayStateChangeTransition" format="boolean" /> + {@link android.app.WallpaperInfo#shouldUseDefaultUnfoldTransition()} --> + <attr name="shouldUseDefaultUnfoldTransition" format="boolean" /> <!-- Uri that specifies a settings Slice for this wallpaper. --> <attr name="settingsSliceUri" format="string"/> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 462b1883e29d..7d489049d112 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3221,7 +3221,7 @@ <eat-comment /> <staging-public-group type="attr" first-id="0x01ff0000"> - <public name="shouldUseDefaultDisplayStateChangeTransition" /> + <public name="shouldUseDefaultUnfoldTransition" /> </staging-public-group> <staging-public-group type="id" first-id="0x01fe0000"> diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml index 166edca3d046..d310736ae121 100644 --- a/core/res/res/xml/power_profile.xml +++ b/core/res/res/xml/power_profile.xml @@ -27,9 +27,33 @@ are totally dependent on the platform and can vary significantly, so should be measured on the shipping platform with a power meter. --> - <item name="ambient.on">0.1</item> <!-- ~100mA --> - <item name="screen.on">0.1</item> <!-- ~100mA --> - <item name="screen.full">0.1</item> <!-- ~100mA --> + + <!-- Display related values. --> + <!-- Average battery current draw of display0 while in ambient mode, including backlight. + There must be one of these for each display, labeled: + ambient.on.display0, ambient.on.display1, etc... + + Each display suffix number should match it's ordinal in its display device config. + --> + <item name="ambient.on.display0">0.1</item> <!-- ~100mA --> + <!-- Average battery current draw of display0 while on without backlight. + There must be one of these for each display, labeled: + screen.on.display0, screen.on.display1, etc... + + Each display suffix number should match it's ordinal in its display device config. + --> + <item name="screen.on.display0">0.1</item> <!-- ~100mA --> + <!-- Average battery current draw of the backlight at full brightness. + The full current draw of display N at full brightness should be the sum of screen.on.displayN + and screen.full.displayN + + There must be one of these for each display, labeled: + screen.full.display0, screen.full.display1, etc... + + Each display suffix number should match it's ordinal in its display device config. + --> + <item name="screen.full.display0">0.1</item> <!-- ~100mA --> + <item name="bluetooth.active">0.1</item> <!-- Bluetooth data transfer, ~10mA --> <item name="bluetooth.on">0.1</item> <!-- Bluetooth on & connectable, but not connected, ~0.1mA --> <item name="wifi.on">0.1</item> <!-- ~3mA --> diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java index 79f7a5c9df18..d76037eb1cab 100644 --- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java @@ -16,6 +16,8 @@ package com.android.internal.os; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT; + import static com.google.common.truth.Truth.assertThat; import android.os.BatteryConsumer; @@ -36,7 +38,7 @@ public class AmbientDisplayPowerCalculatorTest { @Rule public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() - .setAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY, 10.0); + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0, 10.0); @Test public void testMeasuredEnergyBasedModel() { diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java index 083090c54619..ab38f017936d 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -110,6 +110,14 @@ public class BatteryUsageStatsRule implements TestRule { return this; } + public BatteryUsageStatsRule setAveragePowerForOrdinal(String group, int ordinal, + double value) { + when(mPowerProfile.getAveragePowerForOrdinal(group, ordinal)).thenReturn(value); + when(mPowerProfile.getAveragePowerForOrdinal(eq(group), eq(ordinal), + anyDouble())).thenReturn(value); + return this; + } + /** Call only after setting the power profile information. */ public BatteryUsageStatsRule initMeasuredEnergyStatsLocked() { return initMeasuredEnergyStatsLocked(new String[0]); diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java index 5862368f44d2..88ee405483db 100644 --- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java +++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java @@ -17,6 +17,10 @@ package com.android.internal.os; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON; + import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -53,7 +57,12 @@ public class PowerProfileTest extends TestCase { assertEquals(4, mProfile.getNumSpeedStepsInCpuCluster(1)); assertEquals(60.0, mProfile.getAveragePowerForCpuCore(1, 3)); assertEquals(3000.0, mProfile.getBatteryCapacity()); - assertEquals(0.5, mProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)); + assertEquals(0.5, + mProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0)); + assertEquals(100.0, + mProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0)); + assertEquals(800.0, + mProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0)); assertEquals(100.0, mProfile.getAveragePower(PowerProfile.POWER_AUDIO)); assertEquals(150.0, mProfile.getAveragePower(PowerProfile.POWER_VIDEO)); } diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java index c695fc9eb87d..50e0a1512819 100644 --- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java @@ -16,6 +16,9 @@ package com.android.internal.os; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON; + import static com.google.common.truth.Truth.assertThat; import android.app.ActivityManager; @@ -42,8 +45,8 @@ public class ScreenPowerCalculatorTest { @Rule public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() - .setAveragePower(PowerProfile.POWER_SCREEN_ON, 36.0) - .setAveragePower(PowerProfile.POWER_SCREEN_FULL, 48.0); + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0, 36.0) + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0, 48.0); @Test public void testMeasuredEnergyBasedModel() { diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml index 33f885a45a3a..53d02a4a309e 100644 --- a/data/etc/car/com.android.car.carlauncher.xml +++ b/data/etc/car/com.android.car.carlauncher.xml @@ -24,5 +24,6 @@ <permission name="android.permission.MEDIA_CONTENT_CONTROL"/> <permission name="android.permission.PACKAGE_USAGE_STATS"/> <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/> + <permission name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/> </privapp-permissions> </permissions> diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml index 8705067e3d9b..ab162dd590a1 100644 --- a/data/etc/car/com.google.android.car.kitchensink.xml +++ b/data/etc/car/com.google.android.car.kitchensink.xml @@ -74,6 +74,8 @@ <permission name="android.car.permission.CAR_TEST_SERVICE"/> <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION"/> <permission name="android.car.permission.CAR_VENDOR_EXTENSION"/> + <!-- use for AndroidCarApiTest --> + <permission name="android.car.permission.CONTROL_CAR_APP_LAUNCH"/> <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/> <permission name="android.car.permission.CONTROL_CAR_DOORS"/> <permission name="android.car.permission.CONTROL_CAR_EXTERIOR_LIGHTS"/> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index b48bda3a6e48..bef26bfffef3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -558,6 +558,8 @@ public class BubbleData { } Bubble bubbleToRemove = mBubbles.get(indexToRemove); bubbleToRemove.stopInflation(); + overflowBubble(reason, bubbleToRemove); + if (mBubbles.size() == 1) { if (hasOverflowBubbles() && (mPositioner.showingInTaskbar() || isExpanded())) { // No more active bubbles but we have stuff in the overflow -- select that view @@ -581,8 +583,6 @@ public class BubbleData { mStateChange.orderChanged |= repackAll(); } - overflowBubble(reason, bubbleToRemove); - // Note: If mBubbles.isEmpty(), then mSelectedBubble is now null. if (Objects.equals(mSelectedBubble, bubbleToRemove)) { // Move selection to the new bubble at the same position. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java index 08ab85cab97b..fc1b704e95ad 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java @@ -16,9 +16,6 @@ package com.android.wm.shell.fullscreen; -import static android.graphics.Color.blue; -import static android.graphics.Color.green; -import static android.graphics.Color.red; import static android.util.MathUtils.lerp; import static android.view.Display.DEFAULT_DISPLAY; @@ -36,12 +33,11 @@ import android.view.InsetsState; import android.view.SurfaceControl; import com.android.internal.policy.ScreenDecorationsUtils; -import com.android.wm.shell.R; -import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener; +import com.android.wm.shell.unfold.UnfoldBackgroundController; import java.util.concurrent.Executor; @@ -59,21 +55,17 @@ public final class FullscreenUnfoldController implements UnfoldListener, private static final float VERTICAL_START_MARGIN = 0.03f; private static final float END_SCALE = 1f; private static final float START_SCALE = END_SCALE - VERTICAL_START_MARGIN * 2; - private static final int BACKGROUND_LAYER_Z_INDEX = -1; - private final Context mContext; private final Executor mExecutor; private final ShellUnfoldProgressProvider mProgressProvider; - private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private final DisplayInsetsController mDisplayInsetsController; private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>(); + private final UnfoldBackgroundController mBackgroundController; - private SurfaceControl mBackgroundLayer; private InsetsSource mTaskbarInsetsSource; private final float mWindowCornerRadiusPx; - private final float[] mBackgroundColor; private final float mExpandedTaskBarHeight; private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); @@ -81,19 +73,17 @@ public final class FullscreenUnfoldController implements UnfoldListener, public FullscreenUnfoldController( @NonNull Context context, @NonNull Executor executor, + @NonNull UnfoldBackgroundController backgroundController, @NonNull ShellUnfoldProgressProvider progressProvider, - @NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, @NonNull DisplayInsetsController displayInsetsController ) { - mContext = context; mExecutor = executor; - mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mProgressProvider = progressProvider; mDisplayInsetsController = displayInsetsController; mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context); mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.taskbar_frame_height); - mBackgroundColor = getBackgroundColor(); + mBackgroundController = backgroundController; } /** @@ -108,7 +98,7 @@ public final class FullscreenUnfoldController implements UnfoldListener, public void onStateChangeProgress(float progress) { if (mAnimationContextByTaskId.size() == 0) return; - ensureBackground(); + mBackgroundController.ensureBackground(mTransaction); for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) { final AnimationContext context = mAnimationContextByTaskId.valueAt(i); @@ -135,7 +125,7 @@ public final class FullscreenUnfoldController implements UnfoldListener, resetSurface(context); } - removeBackground(); + mBackgroundController.removeBackground(mTransaction); mTransaction.apply(); } @@ -178,7 +168,7 @@ public final class FullscreenUnfoldController implements UnfoldListener, } if (mAnimationContextByTaskId.size() == 0) { - removeBackground(); + mBackgroundController.removeBackground(mTransaction); } mTransaction.apply(); @@ -194,39 +184,6 @@ public final class FullscreenUnfoldController implements UnfoldListener, (float) context.mTaskInfo.positionInParent.y); } - private void ensureBackground() { - if (mBackgroundLayer != null) return; - - SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder() - .setName("app-unfold-background") - .setCallsite("AppUnfoldTransitionController") - .setColorLayer(); - mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder); - mBackgroundLayer = colorLayerBuilder.build(); - - mTransaction - .setColor(mBackgroundLayer, mBackgroundColor) - .show(mBackgroundLayer) - .setLayer(mBackgroundLayer, BACKGROUND_LAYER_Z_INDEX); - } - - private void removeBackground() { - if (mBackgroundLayer == null) return; - if (mBackgroundLayer.isValid()) { - mTransaction.remove(mBackgroundLayer); - } - mBackgroundLayer = null; - } - - private float[] getBackgroundColor() { - int colorInt = mContext.getResources().getColor(R.color.unfold_transition_background); - return new float[]{ - (float) red(colorInt) / 255.0F, - (float) green(colorInt) / 255.0F, - (float) blue(colorInt) / 255.0F - }; - } - private class AnimationContext { final SurfaceControl mLeash; final Rect mStartCropRect = new Rect(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java index d0998eb57633..7f82ebde77af 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java @@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import android.annotation.Nullable; import android.graphics.Rect; import android.view.SurfaceSession; import android.window.WindowContainerToken; @@ -38,8 +39,10 @@ class MainStage extends StageTaskListener { MainStage(ShellTaskOrganizer taskOrganizer, int displayId, StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue, - SurfaceSession surfaceSession) { - super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession); + SurfaceSession surfaceSession, + @Nullable StageTaskUnfoldController stageTaskUnfoldController) { + super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession, + stageTaskUnfoldController); } boolean isActive() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java index 0e7ccd3515c4..dc8fb9fbd7a3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java @@ -46,8 +46,10 @@ class SideStage extends StageTaskListener implements SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId, StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue, - SurfaceSession surfaceSession) { - super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession); + SurfaceSession surfaceSession, + @Nullable StageTaskUnfoldController stageTaskUnfoldController) { + super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession, + stageTaskUnfoldController); mContext = context; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index ac68b3b8a6a9..0d5271924375 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -68,8 +68,11 @@ import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Optional; import java.util.concurrent.Executor; +import javax.inject.Provider; + /** * Class manages split-screen multitasking mode and implements the main interface * {@link SplitScreen}. @@ -91,6 +94,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private final Transitions mTransitions; private final TransactionPool mTransactionPool; private final SplitscreenEventLogger mLogger; + private final Provider<Optional<StageTaskUnfoldController>> mUnfoldControllerProvider; private StageCoordinator mStageCoordinator; @@ -99,7 +103,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellExecutor mainExecutor, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, - Transitions transitions, TransactionPool transactionPool) { + Transitions transitions, TransactionPool transactionPool, + Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mTaskOrganizer = shellTaskOrganizer; mSyncQueue = syncQueue; mContext = context; @@ -109,6 +114,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mDisplayInsetsController = displayInsetsController; mTransitions = transitions; mTransactionPool = transactionPool; + mUnfoldControllerProvider = unfoldControllerProvider; mLogger = new SplitscreenEventLogger(); } @@ -131,7 +137,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, // TODO: Multi-display mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, - mDisplayInsetsController, mTransitions, mTransactionPool, mLogger); + mDisplayInsetsController, mTransitions, mTransactionPool, mLogger, + mUnfoldControllerProvider); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index d7a6cfff6c6f..414b4e48efdd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -95,6 +95,9 @@ import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Optional; + +import javax.inject.Provider; /** * Coordinates the staging (visibility, sizing, ...) of the split-screen {@link MainStage} and @@ -121,8 +124,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private final MainStage mMainStage; private final StageListenerImpl mMainStageListener = new StageListenerImpl(); + private final StageTaskUnfoldController mMainUnfoldController; private final SideStage mSideStage; private final StageListenerImpl mSideStageListener = new StageListenerImpl(); + private final StageTaskUnfoldController mSideUnfoldController; @SplitPosition private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT; @@ -179,26 +184,32 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, - TransactionPool transactionPool, SplitscreenEventLogger logger) { + TransactionPool transactionPool, SplitscreenEventLogger logger, + Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mContext = context; mDisplayId = displayId; mSyncQueue = syncQueue; mRootTDAOrganizer = rootTDAOrganizer; mTaskOrganizer = taskOrganizer; mLogger = logger; + mMainUnfoldController = unfoldControllerProvider.get().orElse(null); + mSideUnfoldController = unfoldControllerProvider.get().orElse(null); + mMainStage = new MainStage( mTaskOrganizer, mDisplayId, mMainStageListener, mSyncQueue, - mSurfaceSession); + mSurfaceSession, + mMainUnfoldController); mSideStage = new SideStage( mContext, mTaskOrganizer, mDisplayId, mSideStageListener, mSyncQueue, - mSurfaceSession); + mSurfaceSession, + mSideUnfoldController); mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSideStage); @@ -218,7 +229,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, - SplitscreenEventLogger logger) { + SplitscreenEventLogger logger, + Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) { mContext = context; mDisplayId = displayId; mSyncQueue = syncQueue; @@ -232,6 +244,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout = splitLayout; mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions, mOnTransitionAnimationComplete); + mMainUnfoldController = unfoldControllerProvider.get().orElse(null); + mSideUnfoldController = unfoldControllerProvider.get().orElse(null); mLogger = logger; transitions.addHandler(this); } @@ -460,6 +474,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, onLayoutChanged(mSplitLayout); } else { updateWindowBounds(mSplitLayout, wct); + updateUnfoldBounds(); } } } @@ -515,6 +530,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSideStage.removeAllTasks(wct, childrenToTop == mSideStage); mMainStage.deactivate(wct, childrenToTop == mMainStage); mTaskOrganizer.applyTransaction(wct); + mSyncQueue.runInSync(t -> t + .setWindowCrop(mMainStage.mRootLeash, null) + .setWindowCrop(mSideStage.mRootLeash, null)); // Hide divider and reset its position. setDividerVisibility(false); mSplitLayout.resetDividerPosition(); @@ -603,6 +621,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, final SplitScreen.SplitScreenListener l = mListeners.get(i); l.onSplitVisibilityChanged(mDividerVisible); } + + if (mMainUnfoldController != null && mSideUnfoldController != null) { + mMainUnfoldController.onSplitVisibilityChanged(mDividerVisible); + mSideUnfoldController.onSplitVisibilityChanged(mDividerVisible); + } } private void onStageRootTaskAppeared(StageListenerImpl stageListener) { @@ -641,6 +664,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDividerVisible = visible; if (visible) { mSplitLayout.init(); + updateUnfoldBounds(); } else { mSplitLayout.release(); } @@ -784,12 +808,20 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, public void onLayoutChanged(SplitLayout layout) { final WindowContainerTransaction wct = new WindowContainerTransaction(); updateWindowBounds(layout, wct); + updateUnfoldBounds(); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); mSideStage.setOutlineVisibility(true); mLogger.logResize(mSplitLayout.getDividerPositionAsFraction()); } + private void updateUnfoldBounds() { + if (mMainUnfoldController != null && mSideUnfoldController != null) { + mMainUnfoldController.onLayoutChanged(getMainStageBounds()); + mSideUnfoldController.onLayoutChanged(getSideStageBounds()); + } + } + /** * Populates `wct` with operations that match the split windows to the current layout. * To match relevant surfaces, make sure to call updateSurfaceBounds after `wct` is applied @@ -846,6 +878,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDisplayAreaInfo.configuration, this, mParentContainerCallbacks, mDisplayImeController, mTaskOrganizer); mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout); + + if (mMainUnfoldController != null && mSideUnfoldController != null) { + mMainUnfoldController.init(); + mSideUnfoldController.init(); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 4140332f50a3..84d570f4be44 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; import android.annotation.CallSuper; +import android.annotation.Nullable; import android.app.ActivityManager; import android.graphics.Point; import android.graphics.Rect; @@ -80,12 +81,16 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { protected SparseArray<ActivityManager.RunningTaskInfo> mChildrenTaskInfo = new SparseArray<>(); private final SparseArray<SurfaceControl> mChildrenLeashes = new SparseArray<>(); + private final StageTaskUnfoldController mStageTaskUnfoldController; + StageTaskListener(ShellTaskOrganizer taskOrganizer, int displayId, StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue, - SurfaceSession surfaceSession) { + SurfaceSession surfaceSession, + @Nullable StageTaskUnfoldController stageTaskUnfoldController) { mCallbacks = callbacks; mSyncQueue = syncQueue; mSurfaceSession = surfaceSession; + mStageTaskUnfoldController = stageTaskUnfoldController; taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this); } @@ -158,6 +163,10 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo + "\n mRootTaskInfo: " + mRootTaskInfo); } + + if (mStageTaskUnfoldController != null) { + mStageTaskUnfoldController.onTaskAppeared(taskInfo, leash); + } } @Override @@ -210,6 +219,10 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo + "\n mRootTaskInfo: " + mRootTaskInfo); } + + if (mStageTaskUnfoldController != null) { + mStageTaskUnfoldController.onTaskVanished(taskInfo); + } } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java new file mode 100644 index 000000000000..e904f6a9e22c --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.splitscreen; + +import static android.view.Display.DEFAULT_DISPLAY; + +import android.animation.RectEvaluator; +import android.animation.TypeEvaluator; +import android.annotation.NonNull; +import android.app.ActivityManager; +import android.content.Context; +import android.graphics.Rect; +import android.util.SparseArray; +import android.view.InsetsSource; +import android.view.InsetsState; +import android.view.SurfaceControl; + +import com.android.internal.policy.ScreenDecorationsUtils; +import com.android.wm.shell.common.DisplayInsetsController; +import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener; +import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; +import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener; +import com.android.wm.shell.unfold.UnfoldBackgroundController; + +import java.util.concurrent.Executor; + +/** + * Controls transformations of the split screen task surfaces in response + * to the unfolding/folding action on foldable devices + */ +public class StageTaskUnfoldController implements UnfoldListener, OnInsetsChangedListener { + + private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect()); + private static final float CROPPING_START_MARGIN_FRACTION = 0.05f; + + private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>(); + private final ShellUnfoldProgressProvider mUnfoldProgressProvider; + private final DisplayInsetsController mDisplayInsetsController; + private final UnfoldBackgroundController mBackgroundController; + private final Executor mExecutor; + private final int mExpandedTaskBarHeight; + private final float mWindowCornerRadiusPx; + private final Rect mStageBounds = new Rect(); + private final TransactionPool mTransactionPool; + + private InsetsSource mTaskbarInsetsSource; + private boolean mBothStagesVisible; + + public StageTaskUnfoldController(@NonNull Context context, + @NonNull TransactionPool transactionPool, + @NonNull ShellUnfoldProgressProvider unfoldProgressProvider, + @NonNull DisplayInsetsController displayInsetsController, + @NonNull UnfoldBackgroundController backgroundController, + @NonNull Executor executor) { + mUnfoldProgressProvider = unfoldProgressProvider; + mTransactionPool = transactionPool; + mExecutor = executor; + mBackgroundController = backgroundController; + mDisplayInsetsController = displayInsetsController; + mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context); + mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.taskbar_frame_height); + } + + /** + * Initializes the controller, starts listening for the external events + */ + public void init() { + mUnfoldProgressProvider.addListener(mExecutor, this); + mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this); + } + + @Override + public void insetsChanged(InsetsState insetsState) { + mTaskbarInsetsSource = insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR); + for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) { + AnimationContext context = mAnimationContextByTaskId.valueAt(i); + context.update(); + } + } + + /** + * Called when split screen task appeared + * @param taskInfo info for the appeared task + * @param leash surface leash for the appeared task + */ + public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { + AnimationContext context = new AnimationContext(leash); + mAnimationContextByTaskId.put(taskInfo.taskId, context); + } + + /** + * Called when a split screen task vanished + * @param taskInfo info for the vanished task + */ + public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { + AnimationContext context = mAnimationContextByTaskId.get(taskInfo.taskId); + if (context != null) { + final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); + resetSurface(transaction, context); + transaction.apply(); + mTransactionPool.release(transaction); + } + mAnimationContextByTaskId.remove(taskInfo.taskId); + } + + @Override + public void onStateChangeProgress(float progress) { + if (mAnimationContextByTaskId.size() == 0 || !mBothStagesVisible) return; + + final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); + mBackgroundController.ensureBackground(transaction); + + for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) { + AnimationContext context = mAnimationContextByTaskId.valueAt(i); + + context.mCurrentCropRect.set(RECT_EVALUATOR + .evaluate(progress, context.mStartCropRect, context.mEndCropRect)); + + transaction.setWindowCrop(context.mLeash, context.mCurrentCropRect) + .setCornerRadius(context.mLeash, mWindowCornerRadiusPx); + } + + transaction.apply(); + + mTransactionPool.release(transaction); + } + + @Override + public void onStateChangeFinished() { + resetTransformations(); + } + + /** + * Called when split screen visibility changes + * @param bothStagesVisible true if both stages of the split screen are visible + */ + public void onSplitVisibilityChanged(boolean bothStagesVisible) { + mBothStagesVisible = bothStagesVisible; + if (!bothStagesVisible) { + resetTransformations(); + } + } + + /** + * Called when split screen stage bounds changed + * @param bounds new bounds for this stage + */ + public void onLayoutChanged(Rect bounds) { + mStageBounds.set(bounds); + + for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) { + final AnimationContext context = mAnimationContextByTaskId.valueAt(i); + context.update(); + } + } + + private void resetTransformations() { + final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); + + for (int i = mAnimationContextByTaskId.size() - 1; i >= 0; i--) { + final AnimationContext context = mAnimationContextByTaskId.valueAt(i); + resetSurface(transaction, context); + } + mBackgroundController.removeBackground(transaction); + transaction.apply(); + + mTransactionPool.release(transaction); + } + + private void resetSurface(SurfaceControl.Transaction transaction, AnimationContext context) { + transaction + .setWindowCrop(context.mLeash, null) + .setCornerRadius(context.mLeash, 0.0F); + } + + private class AnimationContext { + final SurfaceControl mLeash; + final Rect mStartCropRect = new Rect(); + final Rect mEndCropRect = new Rect(); + final Rect mCurrentCropRect = new Rect(); + + private AnimationContext(SurfaceControl leash) { + this.mLeash = leash; + update(); + } + + private void update() { + mStartCropRect.set(mStageBounds); + + if (mTaskbarInsetsSource != null) { + // Only insets the cropping window with taskbar when taskbar is expanded + if (mTaskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) { + mStartCropRect.inset(mTaskbarInsetsSource + .calculateVisibleInsets(mStartCropRect)); + } + } + + // Offset to surface coordinates as layout bounds are in screen coordinates + mStartCropRect.offsetTo(0, 0); + + mEndCropRect.set(mStartCropRect); + + int maxSize = Math.max(mEndCropRect.width(), mEndCropRect.height()); + int margin = (int) (maxSize * CROPPING_START_MARGIN_FRACTION); + mStartCropRect.inset(margin, margin, margin, margin); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java new file mode 100644 index 000000000000..9faf454261d3 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.unfold; + +import static android.graphics.Color.blue; +import static android.graphics.Color.green; +import static android.graphics.Color.red; +import static android.view.Display.DEFAULT_DISPLAY; + +import android.annotation.NonNull; +import android.content.Context; +import android.view.SurfaceControl; + +import com.android.wm.shell.R; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; + +/** + * Controls background color layer for the unfold animations + */ +public class UnfoldBackgroundController { + + private static final int BACKGROUND_LAYER_Z_INDEX = -1; + + private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; + private final float[] mBackgroundColor; + private SurfaceControl mBackgroundLayer; + + public UnfoldBackgroundController( + @NonNull Context context, + @NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { + mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; + mBackgroundColor = getBackgroundColor(context); + } + + /** + * Ensures that unfold animation background color layer is present, + * @param transaction where we should add the background if it is not added + */ + public void ensureBackground(@NonNull SurfaceControl.Transaction transaction) { + if (mBackgroundLayer != null) return; + + SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder() + .setName("app-unfold-background") + .setCallsite("AppUnfoldTransitionController") + .setColorLayer(); + mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder); + mBackgroundLayer = colorLayerBuilder.build(); + + transaction + .setColor(mBackgroundLayer, mBackgroundColor) + .show(mBackgroundLayer) + .setLayer(mBackgroundLayer, BACKGROUND_LAYER_Z_INDEX); + } + + /** + * Ensures that the background is not visible + * @param transaction as part of which the removal will happen if needed + */ + public void removeBackground(@NonNull SurfaceControl.Transaction transaction) { + if (mBackgroundLayer == null) return; + if (mBackgroundLayer.isValid()) { + transaction.remove(mBackgroundLayer); + } + mBackgroundLayer = null; + } + + private float[] getBackgroundColor(Context context) { + int colorInt = context.getResources().getColor(R.color.unfold_transition_background); + return new float[]{ + (float) red(colorInt) / 255.0F, + (float) green(colorInt) / 255.0F, + (float) blue(colorInt) / 255.0F + }; + } +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt index b36468b7e9a5..c07f0eb11510 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt @@ -14,13 +14,14 @@ * limitations under the License. */ +@file:JvmName("CommonAssertions") package com.android.wm.shell.flicker -import android.content.ComponentName import android.graphics.Region import android.view.Surface import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.traces.common.FlickerComponentName fun FlickerTestParameter.appPairsDividerIsVisibleAtEnd() { assertLayersEnd { @@ -72,7 +73,7 @@ fun FlickerTestParameter.dockedStackDividerNotExistsAtEnd() { fun FlickerTestParameter.appPairsPrimaryBoundsIsVisibleAtEnd( rotation: Int, - primaryComponent: ComponentName + primaryComponent: FlickerComponentName ) { assertLayersEnd { val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region @@ -83,7 +84,7 @@ fun FlickerTestParameter.appPairsPrimaryBoundsIsVisibleAtEnd( fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisibleAtEnd( rotation: Int, - primaryComponent: ComponentName + primaryComponent: FlickerComponentName ) { assertLayersEnd { val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region @@ -94,7 +95,7 @@ fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisibleAtEnd( fun FlickerTestParameter.appPairsSecondaryBoundsIsVisibleAtEnd( rotation: Int, - secondaryComponent: ComponentName + secondaryComponent: FlickerComponentName ) { assertLayersEnd { val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region @@ -105,7 +106,7 @@ fun FlickerTestParameter.appPairsSecondaryBoundsIsVisibleAtEnd( fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisibleAtEnd( rotation: Int, - secondaryComponent: ComponentName + secondaryComponent: FlickerComponentName ) { assertLayersEnd { val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt index ff1a6e6d9d90..40891f36a5da 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt @@ -17,8 +17,8 @@ @file:JvmName("CommonConstants") package com.android.wm.shell.flicker -import android.content.ComponentName +import com.android.server.wm.traces.common.FlickerComponentName const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" -val APP_PAIR_SPLIT_DIVIDER_COMPONENT = ComponentName("", "AppPairSplitDivider#") -val DOCKED_STACK_DIVIDER_COMPONENT = ComponentName("", "DockedStackDivider#")
\ No newline at end of file +val APP_PAIR_SPLIT_DIVIDER_COMPONENT = FlickerComponentName("", "AppPairSplitDivider#") +val DOCKED_STACK_DIVIDER_COMPONENT = FlickerComponentName("", "DockedStackDivider#")
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt index a6d67355f271..b63d9fffdb61 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:JvmName("WaitUtils") package com.android.wm.shell.flicker import android.os.SystemClock diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt index 19374ed04be5..038be9c190c2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt @@ -100,8 +100,8 @@ class AppPairsTestCannotPairNonResizeableApps( "Non resizeable app not initialized" } testSpec.assertWmEnd { - isVisible(nonResizeableApp.component) - isInvisible(primaryApp.component) + isAppWindowVisible(nonResizeableApp.component) + isAppWindowInvisible(primaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt index 46ee89295a4e..bbc6b2dbece8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt @@ -77,8 +77,8 @@ class AppPairsTestPairPrimaryAndSecondaryApps( @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(primaryApp.component) - isVisible(secondaryApp.component) + isAppWindowVisible(primaryApp.component) + isAppWindowVisible(secondaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt index f7ced71afe8a..bb784a809b7e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt @@ -100,8 +100,8 @@ class AppPairsTestSupportPairNonResizeableApps( "Non resizeable app not initialized" } testSpec.assertWmEnd { - isVisible(nonResizeableApp.component) - isVisible(primaryApp.component) + isAppWindowVisible(nonResizeableApp.component) + isAppWindowVisible(primaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt index 3debdd3276e4..a1a4db112dfd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt @@ -81,8 +81,8 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps( @Test fun bothAppWindowsInvisible() { testSpec.assertWmEnd { - isInvisible(primaryApp.component) - isInvisible(secondaryApp.component) + isAppWindowInvisible(primaryApp.component) + isAppWindowInvisible(secondaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt index cdf89a57fde8..c1ec324e9ab1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt @@ -38,6 +38,7 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.helpers.AppPairsHelper import com.android.wm.shell.flicker.helpers.BaseAppHelper import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow @@ -55,7 +56,7 @@ abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) protected val activityHelper = ActivityHelper.getInstance() protected val appPairsHelper = AppPairsHelper(instrumentation, Components.SplitScreenActivity.LABEL, - Components.SplitScreenActivity.COMPONENT) + Components.SplitScreenActivity.COMPONENT.toFlickerComponent()) protected val primaryApp = SplitScreenHelper.getPrimary(instrumentation) protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt index 3e782e608c86..56a2531a3fe1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt @@ -73,8 +73,8 @@ class RotateTwoLaunchedAppsInAppPairsMode( @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(primaryApp.component) - .isVisible(secondaryApp.component) + isAppWindowVisible(primaryApp.component) + isAppWindowVisible(secondaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt index ee28c7aa6beb..0699a4fd0512 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt @@ -85,8 +85,8 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode( @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(primaryApp.component) - isVisible(secondaryApp.component) + isAppWindowVisible(primaryApp.component) + isAppWindowVisible(secondaryApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt index 5a438af0b1f1..623055f659b9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt @@ -17,15 +17,15 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.graphics.Region import com.android.server.wm.flicker.Flicker import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.traces.common.FlickerComponentName class AppPairsHelper( instrumentation: Instrumentation, activityLabel: String, - component: ComponentName + component: FlickerComponentName ) : BaseAppHelper(instrumentation, activityLabel, component) { fun getPrimaryBounds(dividerBounds: Region): android.graphics.Region { val primaryAppBounds = Region(0, 0, dividerBounds.bounds.right, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt index f15044ef37af..57bc0d580d72 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt @@ -17,7 +17,6 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.content.pm.PackageManager.FEATURE_LEANBACK import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY import android.os.SystemProperties @@ -28,13 +27,13 @@ import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until import com.android.compatibility.common.util.SystemUtil import com.android.server.wm.flicker.helpers.StandardAppHelper -import com.android.server.wm.traces.parser.toWindowName +import com.android.server.wm.traces.common.FlickerComponentName import java.io.IOException abstract class BaseAppHelper( instrumentation: Instrumentation, launcherName: String, - component: ComponentName + component: FlickerComponentName ) : StandardAppHelper( instrumentation, launcherName, diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt index b4ae18749b34..471e010cf560 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FixedAppHelper.kt @@ -17,10 +17,11 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.testapp.Components class FixedAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.FixedActivity.LABEL, - Components.FixedActivity.COMPONENT + Components.FixedActivity.COMPONENT.toFlickerComponent() )
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt index 086e8b792e0e..0f00edea136f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt @@ -21,13 +21,14 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.FIND_TIMEOUT +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.testapp.Components open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.ImeActivity.LABEL, - Components.ImeActivity.COMPONENT + Components.ImeActivity.COMPONENT.toFlickerComponent() ) { /** * Opens the IME and wait for it to be displayed diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt index 7f99e62b36b0..12ccbafce651 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/MultiWindowHelper.kt @@ -17,14 +17,14 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.content.Context import android.provider.Settings +import com.android.server.wm.traces.common.FlickerComponentName class MultiWindowHelper( instrumentation: Instrumentation, activityLabel: String, - componentsInfo: ComponentName + componentsInfo: FlickerComponentName ) : BaseAppHelper(instrumentation, activityLabel, componentsInfo) { companion object { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt index 1529f5bcd7e1..2357b0debb33 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt @@ -26,6 +26,7 @@ import androidx.test.uiautomator.BySelector import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.FIND_TIMEOUT import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow import com.android.wm.shell.flicker.pip.tv.isFocusedOrHasFocusedChild @@ -34,7 +35,7 @@ import com.android.wm.shell.flicker.testapp.Components class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.PipActivity.LABEL, - Components.PipActivity.COMPONENT + Components.PipActivity.COMPONENT.toFlickerComponent() ) { private val mediaSessionManager: MediaSessionManager get() = context.getSystemService(MediaSessionManager::class.java) @@ -129,7 +130,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( } /** - * Expands the pip window and dismisses it by clicking on the X button. + * Taps the pip window and dismisses it by clicking on the X button. */ fun closePipWindow(wmHelper: WindowManagerStateHelper) { if (isTelevision) { @@ -137,9 +138,12 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( } else { val windowRect = getWindowRect(wmHelper) uiDevice.click(windowRect.centerX(), windowRect.centerY()) - val exitPipObject = uiDevice.findObject(By.res(SYSTEMUI_PACKAGE, "dismiss")) + // search and interact with the dismiss button + val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss") + uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT) + val dismissPipObject = uiDevice.findObject(dismissSelector) ?: error("PIP window dismiss button not found") - val dismissButtonBounds = exitPipObject.visibleBounds + val dismissButtonBounds = dismissPipObject.visibleBounds uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY()) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt index ba13e38ae9e3..4d0fbc4a0e38 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SimpleAppHelper.kt @@ -17,10 +17,11 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.testapp.Components class SimpleAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, Components.SimpleActivity.LABEL, - Components.SimpleActivity.COMPONENT + Components.SimpleActivity.COMPONENT.toFlickerComponent() )
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt index 2d996ca1d6f7..0ec9b2d869a8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt @@ -17,14 +17,15 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.content.res.Resources +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.testapp.Components class SplitScreenHelper( instrumentation: Instrumentation, activityLabel: String, - componentsInfo: ComponentName + componentsInfo: FlickerComponentName ) : BaseAppHelper(instrumentation, activityLabel, componentsInfo) { companion object { @@ -39,16 +40,16 @@ class SplitScreenHelper( fun getPrimary(instrumentation: Instrumentation): SplitScreenHelper = SplitScreenHelper(instrumentation, Components.SplitScreenActivity.LABEL, - Components.SplitScreenActivity.COMPONENT) + Components.SplitScreenActivity.COMPONENT.toFlickerComponent()) fun getSecondary(instrumentation: Instrumentation): SplitScreenHelper = SplitScreenHelper(instrumentation, Components.SplitScreenSecondaryActivity.LABEL, - Components.SplitScreenSecondaryActivity.COMPONENT) + Components.SplitScreenSecondaryActivity.COMPONENT.toFlickerComponent()) fun getNonResizeable(instrumentation: Instrumentation): SplitScreenHelper = SplitScreenHelper(instrumentation, Components.NonResizeableActivity.LABEL, - Components.NonResizeableActivity.COMPONENT) + Components.NonResizeableActivity.COMPONENT.toFlickerComponent()) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt index 508e93988aa6..bd44d082a1aa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import android.view.WindowManagerPolicyConstants @@ -25,13 +24,13 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper @@ -50,7 +49,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class EnterSplitScreenDockActivity( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -62,10 +61,10 @@ class EnterSplitScreenDockActivity( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(LAUNCHER_COMPONENT, LIVE_WALLPAPER_COMPONENT, - splitScreenApp.component, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT, LAUNCHER_COMPONENT) + splitScreenApp.component, FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, LAUNCHER_COMPONENT) @Presubmit @Test @@ -89,7 +88,7 @@ class EnterSplitScreenDockActivity( @Test fun appWindowIsVisible() { testSpec.assertWmEnd { - isVisible(splitScreenApp.component) + isAppWindowVisible(splitScreenApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt index 12f3909b6c34..625d48b8ab5a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt @@ -16,16 +16,16 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder @@ -43,6 +43,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@Group4 class EnterSplitScreenFromDetachedRecentTask( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -62,10 +63,10 @@ class EnterSplitScreenFromDetachedRecentTask( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(LAUNCHER_COMPONENT, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, splitScreenApp.component) @Presubmit @@ -76,7 +77,7 @@ class EnterSplitScreenFromDetachedRecentTask( @Test fun appWindowIsVisible() { testSpec.assertWmEnd { - isVisible(splitScreenApp.component) + isAppWindowVisible(splitScreenApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt index ac85c4857c76..2ed2806af528 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt @@ -16,21 +16,20 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd @@ -49,7 +48,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class EnterSplitScreenLaunchToSide( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -62,10 +61,10 @@ class EnterSplitScreenLaunchToSide( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component, - secondaryApp.component, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + secondaryApp.component, FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Presubmit @Test @@ -92,7 +91,7 @@ class EnterSplitScreenLaunchToSide( // Because we log WM once per frame, sometimes the activity and the window // become visible in the same entry, sometimes not, thus it is not possible to // assert the visibility of the activity here - this.isAppWindowInvisible(secondaryApp.component, ignoreActivity = true) + this.isAppWindowInvisible(secondaryApp.component) .then() // during re-parenting, the window may disappear and reappear from the // trace, this occurs because we log only 1x per frame diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt index 964af2341439..ee6cf341c9ff 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt @@ -16,17 +16,16 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.canSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow @@ -51,7 +50,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) -@Group1 +@Group4 class EnterSplitScreenNotSupportNonResizable( testSpec: FlickerTestParameter ) : LegacySplitScreenTransition(testSpec) { @@ -71,10 +70,10 @@ class EnterSplitScreenNotSupportNonResizable( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(LAUNCHER_COMPONENT, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, nonResizeableApp.component, splitScreenApp.component) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt index 1b8afa668802..163b6ffda6e2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice @@ -26,7 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow @@ -68,12 +67,12 @@ class EnterSplitScreenSupportNonResizable( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(LAUNCHER_COMPONENT, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT, - nonResizeableApp.component, - splitScreenApp.component) + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, + nonResizeableApp.component, + splitScreenApp.component) @Before override fun setup() { @@ -95,7 +94,7 @@ class EnterSplitScreenSupportNonResizable( @Test fun appWindowIsVisible() { testSpec.assertWmEnd { - isVisible(nonResizeableApp.component) + isAppWindowVisible(nonResizeableApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt index 247965f8071d..2b629b0a7eb5 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Postsubmit import android.view.Surface import androidx.test.filters.FlakyTest @@ -30,7 +29,7 @@ import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder @@ -70,10 +69,10 @@ class ExitLegacySplitScreenFromBottom( } } - override val ignoredWindows: List<ComponentName> - get() = listOf(LAUNCHER_COMPONENT, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, splitScreenApp.component, secondaryApp.component, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + FlickerComponentName.SNAPSHOT) @Postsubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt index ff34364261f2..95fe3bef4852 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest @@ -30,7 +29,7 @@ import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder @@ -70,10 +69,10 @@ class ExitPrimarySplitScreenShowSecondaryFullscreen( } } - override val ignoredWindows: List<ComponentName> - get() = listOf(LAUNCHER_COMPONENT, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, splitScreenApp.component, secondaryApp.component, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + FlickerComponentName.SNAPSHOT) @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt index 95e4085db4eb..f7d628d48769 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice @@ -26,7 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig @@ -69,11 +68,11 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, - nonResizeableApp.component, splitScreenApp.component, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + nonResizeableApp.component, splitScreenApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -120,12 +119,12 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( // when the activity gets PAUSED the window may still be marked as visible // it will be updated in the next log entry. This occurs because we record 1x // per frame, thus ignore activity check here - this.isAppWindowVisible(splitScreenApp.component, ignoreActivity = true) + this.isAppWindowVisible(splitScreenApp.component) .then() // immediately after the window (after onResume and before perform relayout) // the activity is invisible. This may or not be logged, since we record 1x // per frame, thus ignore activity check here - .isAppWindowInvisible(splitScreenApp.component, ignoreActivity = true) + .isAppWindowInvisible(splitScreenApp.component) } } @@ -142,13 +141,12 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( .then() // we log once per frame, upon logging, window may be visible or not depending // on what was processed until that moment. Both behaviors are correct - .isAppWindowInvisible(nonResizeableApp.component, - ignoreActivity = true, isOptional = true) + .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) .then() // immediately after the window (after onResume and before perform relayout) // the activity is invisible. This may or not be logged, since we record 1x // per frame, thus ignore activity check here - .isAppWindowVisible(nonResizeableApp.component, ignoreActivity = true) + .isAppWindowVisible(nonResizeableApp.component) } } @@ -159,7 +157,7 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( @Test fun nonResizableAppWindowBecomesVisibleAtEnd() { testSpec.assertWmEnd { - this.isVisible(nonResizeableApp.component) + isAppWindowVisible(nonResizeableApp.component) } } @@ -171,8 +169,8 @@ class LegacySplitScreenFromIntentNotSupportNonResizable( @Test fun onlyNonResizableAppWindowIsVisibleAtEnd() { testSpec.assertWmEnd { - isInvisible(splitScreenApp.component) - isVisible(nonResizeableApp.component) + isAppWindowInvisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt index 65346aa8ea5d..a5c6571f68de 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice @@ -26,7 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig @@ -69,11 +68,11 @@ class LegacySplitScreenFromIntentSupportNonResizable( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, nonResizeableApp.component, splitScreenApp.component, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -110,13 +109,12 @@ class LegacySplitScreenFromIntentSupportNonResizable( .then() // we log once per frame, upon logging, window may be visible or not depending // on what was processed until that moment. Both behaviors are correct - .isAppWindowInvisible(nonResizeableApp.component, - ignoreActivity = true, isOptional = true) + .isAppWindowInvisible(nonResizeableApp.component, isOptional = true) .then() // immediately after the window (after onResume and before perform relayout) // the activity is invisible. This may or not be logged, since we record 1x // per frame, thus ignore activity check here - .isAppWindowVisible(nonResizeableApp.component, ignoreActivity = true) + .isAppWindowVisible(nonResizeableApp.component) } } @@ -128,8 +126,8 @@ class LegacySplitScreenFromIntentSupportNonResizable( @Test fun bothAppsWindowsAreVisibleAtEnd() { testSpec.assertWmEnd { - isVisible(splitScreenApp.component) - isVisible(nonResizeableApp.component) + isAppWindowVisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt index 547341a14cdd..6f486b0ddfea 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.view.Surface @@ -28,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig @@ -71,11 +70,11 @@ class LegacySplitScreenFromRecentNotSupportNonResizable( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, - TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -116,12 +115,12 @@ class LegacySplitScreenFromRecentNotSupportNonResizable( // when the activity gets PAUSED the window may still be marked as visible // it will be updated in the next log entry. This occurs because we record 1x // per frame, thus ignore activity check here - this.isAppWindowVisible(splitScreenApp.component, ignoreActivity = true) + this.isAppWindowVisible(splitScreenApp.component) .then() // immediately after the window (after onResume and before perform relayout) // the activity is invisible. This may or not be logged, since we record 1x // per frame, thus ignore activity check here - .isAppWindowInvisible(splitScreenApp.component, ignoreActivity = true) + .isAppWindowInvisible(splitScreenApp.component) } } @@ -143,8 +142,8 @@ class LegacySplitScreenFromRecentNotSupportNonResizable( @Test fun onlyNonResizableAppWindowIsVisibleAtEnd() { testSpec.assertWmEnd { - isInvisible(splitScreenApp.component) - isVisible(nonResizeableApp.component) + isAppWindowInvisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt index 3f86658297fe..f03c927b8d58 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.RequiresDevice @@ -27,7 +26,7 @@ import com.android.server.wm.flicker.annotation.Group2 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.reopenAppFromOverview -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig @@ -70,11 +69,11 @@ class LegacySplitScreenFromRecentSupportNonResizable( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT, - TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Before override fun setup() { @@ -107,7 +106,7 @@ class LegacySplitScreenFromRecentSupportNonResizable( // Because we log WM once per frame, sometimes the activity and the window // become visible in the same entry, sometimes not, thus it is not possible to // assert the visibility of the activity here - this.isAppWindowInvisible(nonResizeableApp.component, ignoreActivity = true) + this.isAppWindowInvisible(nonResizeableApp.component) .then() // during re-parenting, the window may disappear and reappear from the // trace, this occurs because we log only 1x per frame @@ -129,8 +128,8 @@ class LegacySplitScreenFromRecentSupportNonResizable( @Test fun bothAppsWindowsAreVisibleAtEnd() { testSpec.assertWmEnd { - isVisible(splitScreenApp.component) - isVisible(nonResizeableApp.component) + isAppWindowVisible(splitScreenApp.component) + isAppWindowVisible(nonResizeableApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt index 5fb6f1fa1076..b6680d96e2a2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.view.Surface @@ -39,7 +38,7 @@ import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible import com.android.wm.shell.flicker.helpers.SimpleAppHelper import org.junit.FixMethodOrder @@ -86,9 +85,9 @@ class LegacySplitScreenToLauncher( } } - override val ignoredWindows: List<ComponentName> - get() = listOf(LAUNCHER_COMPONENT, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + override val ignoredWindows: List<FlickerComponentName> + get() = listOf(LAUNCHER_COMPONENT, FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt index 311769313a7a..661c8b69068e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt @@ -17,7 +17,6 @@ package com.android.wm.shell.flicker.legacysplitscreen import android.app.Instrumentation -import android.content.ComponentName import android.content.Context import android.support.test.launcherhelper.LauncherStrategyFactory import android.view.Surface @@ -32,7 +31,7 @@ import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setDevEnableNonResizableMultiWindow @@ -50,7 +49,7 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation) protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation) protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation) - protected val LAUNCHER_COMPONENT = ComponentName("", + protected val LAUNCHER_COMPONENT = FlickerComponentName("", LauncherStrategyFactory.getInstance(instrumentation) .launcherStrategy.supportedLauncherPackage) private var prevDevEnableNonResizableMultiWindow = 0 @@ -79,9 +78,9 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa * * b/182720234 */ - open val ignoredWindows: List<ComponentName> = listOf( - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + open val ignoredWindows: List<FlickerComponentName> = listOf( + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = { configuration -> @@ -148,9 +147,9 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa } companion object { - internal val LIVE_WALLPAPER_COMPONENT = ComponentName("", + internal val LIVE_WALLPAPER_COMPONENT = FlickerComponentName("", "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2") - internal val LETTERBOX_COMPONENT = ComponentName("", "Letterbox") - internal val TOAST_COMPONENT = ComponentName("", "Toast") + internal val LETTERBOX_COMPONENT = FlickerComponentName("", "Letterbox") + internal val TOAST_COMPONENT = FlickerComponentName("", "Toast") } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt index a7ac6a77d425..34eff80a04bc 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.legacysplitscreen -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import androidx.test.filters.FlakyTest @@ -29,7 +28,7 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.statusBarLayerIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.appPairsDividerBecomesVisible import com.android.wm.shell.flicker.helpers.SplitScreenHelper import org.junit.FixMethodOrder @@ -59,10 +58,10 @@ class OpenAppToLegacySplitScreen( } } - override val ignoredWindows: List<ComponentName> + override val ignoredWindows: List<FlickerComponentName> get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT) + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT) @FlakyTest @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt index cd150518f21f..14b006ee046e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt @@ -42,6 +42,7 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT import com.android.wm.shell.flicker.helpers.SimpleAppHelper import com.android.wm.shell.flicker.testapp.Components @@ -110,7 +111,7 @@ class ResizeLegacySplitScreen( @Test fun topAppWindowIsAlwaysVisible() { testSpec.assertWm { - this.isAppWindowVisible(Components.SimpleActivity.COMPONENT) + this.isAppWindowVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent()) } } @@ -118,7 +119,7 @@ class ResizeLegacySplitScreen( @Test fun bottomAppWindowIsAlwaysVisible() { testSpec.assertWm { - this.isAppWindowVisible(Components.ImeActivity.COMPONENT) + this.isAppWindowVisible(Components.ImeActivity.COMPONENT.toFlickerComponent()) } } @@ -142,14 +143,14 @@ class ResizeLegacySplitScreen( @Test fun topAppLayerIsAlwaysVisible() { testSpec.assertLayers { - this.isVisible(Components.SimpleActivity.COMPONENT) + this.isVisible(Components.SimpleActivity.COMPONENT.toFlickerComponent()) } } @Test fun bottomAppLayerIsAlwaysVisible() { testSpec.assertLayers { - this.isVisible(Components.ImeActivity.COMPONENT) + this.isVisible(Components.ImeActivity.COMPONENT.toFlickerComponent()) } } @@ -174,8 +175,10 @@ class ResizeLegacySplitScreen( dividerBounds.bottom - WindowUtils.dockedStackDividerInset, displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarHeight) - visibleRegion(Components.SimpleActivity.COMPONENT).coversExactly(topAppBounds) - visibleRegion(Components.ImeActivity.COMPONENT).coversExactly(bottomAppBounds) + visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent()) + .coversExactly(topAppBounds) + visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent()) + .coversExactly(bottomAppBounds) } } @@ -194,8 +197,10 @@ class ResizeLegacySplitScreen( displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarHeight) - visibleRegion(Components.SimpleActivity.COMPONENT).coversExactly(topAppBounds) - visibleRegion(Components.ImeActivity.COMPONENT).coversExactly(bottomAppBounds) + visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent()) + .coversExactly(topAppBounds) + visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent()) + .coversExactly(bottomAppBounds) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt index 2be693631b26..56933c371aa8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt @@ -101,7 +101,7 @@ class RotateTwoLaunchedAppAndEnterSplitScreen( // Because we log WM once per frame, sometimes the activity and the window // become visible in the same entry, sometimes not, thus it is not possible to // assert the visibility of the activity here - this.isAppWindowInvisible(secondaryApp.component, ignoreActivity = true) + this.isAppWindowInvisible(secondaryApp.component) .then() // during re-parenting, the window may disappear and reappear from the // trace, this occurs because we log only 1x per frame diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt index 443204c245db..f9b08000290f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:JvmName("CommonAssertions") package com.android.wm.shell.flicker.pip internal const val PIP_WINDOW_COMPONENT = "PipMenuActivity" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index 046972d246e6..52a744f3897d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -26,7 +26,6 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.LAUNCHER_COMPONENT import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.parser.toLayerName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt index 097ccb8cd734..2aa1ed868ff2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt @@ -29,7 +29,7 @@ import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.helpers.FixedAppHelper import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT @@ -106,7 +106,7 @@ class EnterPipToOtherOrientationTest( } /** - * Checks that the [WindowManagerStateHelper.NAV_BAR_COMPONENT] has the correct position at + * Checks that the [FlickerComponentName.NAV_BAR] has the correct position at * the start and end of the transition */ @FlakyTest @@ -115,7 +115,7 @@ class EnterPipToOtherOrientationTest( testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_90, Surface.ROTATION_0) /** - * Checks that the [WindowManagerStateHelper.STATUS_BAR_COMPONENT] has the correct position at + * Checks that the [FlickerComponentName.STATUS_BAR] has the correct position at * the start and end of the transition */ @Presubmit @@ -150,7 +150,7 @@ class EnterPipToOtherOrientationTest( @Test fun testAppWindowInvisibleOnStart() { testSpec.assertWmStart { - isInvisible(testApp.component) + isAppWindowInvisible(testApp.component) } } @@ -161,7 +161,7 @@ class EnterPipToOtherOrientationTest( @Test fun testAppWindowVisibleOnEnd() { testSpec.assertWmEnd { - isVisible(testApp.component) + isAppWindowVisible(testApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt index faaaecb8da46..64b7eb53bd6f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt @@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.traces.parser.toLayerName import com.android.wm.shell.flicker.helpers.FixedAppHelper import org.junit.Test @@ -63,7 +62,7 @@ abstract class ExitPipToAppTransition(testSpec: FlickerTestParameter) : PipTrans // when the activity is STOPPING, sometimes it becomes invisible in an entry before // the window, sometimes in the same entry. This occurs because we log 1x per frame // thus we ignore activity here - isAppWindowVisible(testApp.component, ignoreActivity = true) + isAppWindowVisible(testApp.component) .isAppWindowOnTop(pipApp.component) .then() .isAppWindowInvisible(testApp.component) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt index 3414031d3532..5207fed59208 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt @@ -54,9 +54,9 @@ abstract class ExitPipTransition(testSpec: FlickerTestParameter) : PipTransition open fun pipWindowBecomesInvisible() { testSpec.assertWm { this.invoke("hasPipWindow") { - it.isPinned(pipApp.component).isVisible(pipApp.component) + it.isPinned(pipApp.component).isAppWindowVisible(pipApp.component) }.then().invoke("!hasPipWindow") { - it.isNotPinned(pipApp.component).isInvisible(pipApp.component) + it.isNotPinned(pipApp.component).isAppWindowInvisible(pipApp.component) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt index fa100b5b25ab..b53342d6f2f7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt @@ -23,7 +23,6 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.parser.toWindowName import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt index 617ef221ee9a..1fec3cf85214 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt @@ -23,7 +23,6 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.parser.toWindowName import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index 89b2c400e80a..ce840efcab88 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -27,7 +27,6 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.LAUNCHER_COMPONENT import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.parser.toLayerName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt index ed04fc947435..6e0324c17272 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt @@ -20,8 +20,6 @@ import android.platform.test.annotations.Presubmit import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.traces.RegionSubject -import com.android.server.wm.traces.parser.toLayerName -import com.android.server.wm.traces.parser.toWindowName import com.android.wm.shell.flicker.helpers.FixedAppHelper import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt index 5719413aff25..aba8aced298f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt @@ -22,12 +22,12 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.startRotation -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.android.wm.shell.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder import org.junit.Test @@ -43,7 +43,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 +@Group4 class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val imeApp = ImeAppHelper(instrumentation) @@ -90,7 +90,7 @@ class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) @Test fun pipIsAboveAppWindow() { testSpec.assertWmTag(TAG_IME_VISIBLE) { - isAboveWindow(WindowManagerStateHelper.IME_COMPONENT, pipApp.component) + isAboveWindow(FlickerComponentName.IME, pipApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt index 086165289d2d..9bea5c03dadb 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt @@ -23,7 +23,7 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.launchSplitScreen import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen @@ -51,7 +51,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 +@Group4 class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val imeApp = ImeAppHelper(instrumentation) private val testApp = FixedAppHelper(instrumentation) @@ -104,9 +104,9 @@ class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(t @Test fun bothAppWindowsVisible() { testSpec.assertWmEnd { - isVisible(testApp.component) - isVisible(imeApp.component) - noWindowsOverlap(testApp.component, imeApp.component) + isAppWindowVisible(testApp.component) + isAppWindowVisible(imeApp.component) + doNotOverlap(testApp.component, imeApp.component) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt index b1054600d702..08d52095e499 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt @@ -23,7 +23,7 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.entireScreenCovered @@ -62,7 +62,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 +@Group4 class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) { private val fixedApp = FixedAppHelper(instrumentation) private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.config.startRotation) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt index 02a3eb1e070a..d6dbc366aec0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt @@ -22,7 +22,7 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group3 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE @@ -43,7 +43,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group3 +@Group4 class SetRequestedOrientationWhilePinnedTest( testSpec: FlickerTestParameter ) : PipTransition(testSpec) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java index b0312e6d6f3c..091022a139f3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java @@ -793,7 +793,7 @@ public class BubbleDataTest extends ShellTestCase { } @Test - public void test_expanded_removeLastBubble_collapsesStack() { + public void test_expanded_removeLastBubble_showsOverflowIfNotEmpty() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); changeExpandedStateAtTime(true, 2000); @@ -802,6 +802,21 @@ public class BubbleDataTest extends ShellTestCase { // Test mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_USER_GESTURE); verifyUpdateReceived(); + assertThat(mBubbleData.getOverflowBubbles().size()).isGreaterThan(0); + assertSelectionChangedTo(mBubbleData.getOverflow()); + } + + @Test + public void test_expanded_removeLastBubble_collapsesIfOverflowEmpty() { + // Setup + sendUpdatedEntryAtTime(mEntryA1, 1000); + changeExpandedStateAtTime(true, 2000); + mBubbleData.setListener(mListener); + + // Test + mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NO_BUBBLE_UP); + verifyUpdateReceived(); + assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); assertExpandedChangedTo(false); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java index 1bb5fd1e49e7..12b547a765be 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java @@ -56,7 +56,7 @@ public class MainStageTests { MockitoAnnotations.initMocks(this); mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, mSyncQueue, - mSurfaceSession); + mSurfaceSession, null); mMainStage.onTaskAppeared(mRootTaskInfo, mRootLeash); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java index 3a2516ec9366..838aa811bb87 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java @@ -64,7 +64,7 @@ public class SideStageTests extends ShellTestCase { MockitoAnnotations.initMocks(this); mRootTask = new TestRunningTaskInfoBuilder().build(); mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, - mSyncQueue, mSurfaceSession); + mSyncQueue, mSurfaceSession, null); mSideStage.onTaskAppeared(mRootTask, mRootLeash); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java index 736566e5b4d3..f90af239db01 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java @@ -18,7 +18,6 @@ package com.android.wm.shell.splitscreen; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; - import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -39,6 +38,10 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.transition.Transitions; +import java.util.Optional; + +import javax.inject.Provider; + public class SplitTestUtils { static SplitLayout createMockSplitLayout() { @@ -68,10 +71,11 @@ public class SplitTestUtils { MainStage mainStage, SideStage sideStage, DisplayImeController imeController, DisplayInsetsController insetsController, SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, - SplitscreenEventLogger logger) { + SplitscreenEventLogger logger, + Provider<Optional<StageTaskUnfoldController>> unfoldController) { super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage, sideStage, imeController, insetsController, splitLayout, transitions, - transactionPool, logger); + transactionPool, logger, unfoldController); // Prepare default TaskDisplayArea for testing. mDisplayAreaInfo = new DisplayAreaInfo( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index 8dce454eb078..be103863a0f2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -74,6 +74,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; +import java.util.Optional; + /** Tests for {@link StageCoordinator} */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -106,16 +108,16 @@ public class SplitTransitionTests extends ShellTestCase { doReturn(mock(SurfaceControl.Transaction.class)).when(mTransactionPool).acquire(); mSplitLayout = SplitTestUtils.createMockSplitLayout(); mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mock( - StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession); + StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession, null); mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface()); mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock( - StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession); + StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession, null); mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface()); mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage, mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, - mLogger); + mLogger, Optional::empty); mSplitScreenTransitions = mStageCoordinator.getSplitTransitions(); doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class)) .when(mTransitions).startTransition(anyInt(), any(), any()); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index d930d4ca5dd4..a39d331ca884 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -18,18 +18,20 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.Display.DEFAULT_DISPLAY; - import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT; - +import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.graphics.Rect; +import android.window.DisplayAreaInfo; import android.window.WindowContainerTransaction; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -43,6 +45,7 @@ import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.transition.Transitions; import org.junit.Before; @@ -51,29 +54,55 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -/** Tests for {@link StageCoordinator} */ +import java.util.Optional; + +import javax.inject.Provider; + +/** + * Tests for {@link StageCoordinator} + */ @SmallTest @RunWith(AndroidJUnit4.class) public class StageCoordinatorTests extends ShellTestCase { - @Mock private ShellTaskOrganizer mTaskOrganizer; - @Mock private SyncTransactionQueue mSyncQueue; - @Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer; - @Mock private MainStage mMainStage; - @Mock private SideStage mSideStage; - @Mock private DisplayImeController mDisplayImeController; - @Mock private DisplayInsetsController mDisplayInsetsController; - @Mock private Transitions mTransitions; - @Mock private TransactionPool mTransactionPool; - @Mock private SplitscreenEventLogger mLogger; + @Mock + private ShellTaskOrganizer mTaskOrganizer; + @Mock + private SyncTransactionQueue mSyncQueue; + @Mock + private RootTaskDisplayAreaOrganizer mRootTDAOrganizer; + @Mock + private MainStage mMainStage; + @Mock + private SideStage mSideStage; + @Mock + private StageTaskUnfoldController mMainUnfoldController; + @Mock + private StageTaskUnfoldController mSideUnfoldController; + @Mock + private SplitLayout mSplitLayout; + @Mock + private DisplayImeController mDisplayImeController; + @Mock + private DisplayInsetsController mDisplayInsetsController; + @Mock + private Transitions mTransitions; + @Mock + private TransactionPool mTransactionPool; + @Mock + private SplitscreenEventLogger mLogger; + + private final Rect mBounds1 = new Rect(10, 20, 30, 40); + private final Rect mBounds2 = new Rect(5, 10, 15, 20); + private StageCoordinator mStageCoordinator; @Before public void setup() { MockitoAnnotations.initMocks(this); - mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY, - mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage, - mDisplayImeController, mDisplayInsetsController, null /* splitLayout */, - mTransitions, mTransactionPool, mLogger); + mStageCoordinator = createStageCoordinator(/* splitLayout */ null); + + when(mSplitLayout.getBounds1()).thenReturn(mBounds1); + when(mSplitLayout.getBounds2()).thenReturn(mBounds2); } @Test @@ -88,6 +117,38 @@ public class StageCoordinatorTests extends ShellTestCase { } @Test + public void testDisplayAreaAppeared_initializesUnfoldControllers() { + mStageCoordinator.onDisplayAreaAppeared(mock(DisplayAreaInfo.class)); + + verify(mMainUnfoldController).init(); + verify(mSideUnfoldController).init(); + } + + @Test + public void testLayoutChanged_topLeftSplitPosition_updatesUnfoldStageBounds() { + mStageCoordinator = createStageCoordinator(mSplitLayout); + mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null); + clearInvocations(mMainUnfoldController, mSideUnfoldController); + + mStageCoordinator.onLayoutChanged(mSplitLayout); + + verify(mMainUnfoldController).onLayoutChanged(mBounds2); + verify(mSideUnfoldController).onLayoutChanged(mBounds1); + } + + @Test + public void testLayoutChanged_bottomRightSplitPosition_updatesUnfoldStageBounds() { + mStageCoordinator = createStageCoordinator(mSplitLayout); + mStageCoordinator.setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null); + clearInvocations(mMainUnfoldController, mSideUnfoldController); + + mStageCoordinator.onLayoutChanged(mSplitLayout); + + verify(mMainUnfoldController).onLayoutChanged(mBounds1); + verify(mSideUnfoldController).onLayoutChanged(mBounds2); + } + + @Test public void testRemoveFromSideStage() { final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); @@ -131,4 +192,27 @@ public class StageCoordinatorTests extends ShellTestCase { verify(mSideStage).removeAllTasks(any(WindowContainerTransaction.class), eq(true)); verify(mMainStage).deactivate(any(WindowContainerTransaction.class), eq(false)); } + + private StageCoordinator createStageCoordinator(SplitLayout splitLayout) { + return new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY, + mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage, + mDisplayImeController, mDisplayInsetsController, splitLayout, + mTransitions, mTransactionPool, mLogger, new UnfoldControllerProvider()); + } + + private class UnfoldControllerProvider implements + Provider<Optional<StageTaskUnfoldController>> { + + private boolean isMain = true; + + @Override + public Optional<StageTaskUnfoldController> get() { + if (isMain) { + isMain = false; + return Optional.of(mMainUnfoldController); + } else { + return Optional.of(mSideUnfoldController); + } + } + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index 0916dd1f71bd..a5746a49da2b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -60,6 +61,7 @@ public final class StageTaskListenerTests { @Mock private ShellTaskOrganizer mTaskOrganizer; @Mock private StageTaskListener.StageListenerCallbacks mCallbacks; @Mock private SyncTransactionQueue mSyncQueue; + @Mock private StageTaskUnfoldController mStageTaskUnfoldController; @Captor private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor; private SurfaceSession mSurfaceSession = new SurfaceSession(); private SurfaceControl mSurfaceControl; @@ -74,7 +76,8 @@ public final class StageTaskListenerTests { DEFAULT_DISPLAY, mCallbacks, mSyncQueue, - mSurfaceSession); + mSurfaceSession, + mStageTaskUnfoldController); mRootTask = new TestRunningTaskInfoBuilder().build(); mRootTask.parentTaskId = INVALID_TASK_ID; mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession).setName("test").build(); @@ -111,6 +114,28 @@ public final class StageTaskListenerTests { verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true)); } + @Test + public void testTaskAppeared_notifiesUnfoldListener() { + final ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); + + mStageTaskListener.onTaskAppeared(task, mSurfaceControl); + + verify(mStageTaskUnfoldController).onTaskAppeared(eq(task), eq(mSurfaceControl)); + } + + @Test + public void testTaskVanished_notifiesUnfoldListener() { + final ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); + mStageTaskListener.onTaskAppeared(task, mSurfaceControl); + clearInvocations(mStageTaskUnfoldController); + + mStageTaskListener.onTaskVanished(task); + + verify(mStageTaskUnfoldController).onTaskVanished(eq(task)); + } + @Test(expected = IllegalArgumentException.class) public void testUnknownTaskVanished() { final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 23d9532e11a0..aa72d965f793 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -1613,7 +1613,9 @@ public class AudioTrack extends PlayerBase AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_LEFT | AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_CENTER | AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_RIGHT | - AudioFormat.CHANNEL_OUT_LOW_FREQUENCY_2; + AudioFormat.CHANNEL_OUT_LOW_FREQUENCY_2 | + AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT | + AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT; // Returns a boolean whether the attributes, format, bufferSizeInBytes, mode allow // power saving to be automatically enabled for an AudioTrack. Returns false if @@ -1787,6 +1789,8 @@ public class AudioTrack extends PlayerBase | AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT); put("bottom front", AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_LEFT | AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_RIGHT); + put("front wide", AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT + | AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT); }}; /** diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java index 6c5c4ef94921..9829918a0302 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java @@ -109,9 +109,8 @@ public interface StatusBarStateController { * Callback to be notified when the fullscreen or immersive state changes. * * @param isFullscreen if any of the system bar is hidden by the focused window. - * @param isImmersive if the navigation bar can stay hidden when the display gets tapped. */ - default void onFullscreenStateChanged(boolean isFullscreen, boolean isImmersive) {} + default void onFullscreenStateChanged(boolean isFullscreen) {} /** * Callback to be notified when the pulsing state changes diff --git a/packages/SystemUI/res/color/prv_color_surface.xml b/packages/SystemUI/res/color/prv_color_surface.xml new file mode 100644 index 000000000000..b9d016c46ba0 --- /dev/null +++ b/packages/SystemUI/res/color/prv_color_surface.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="?androidprv:attr/colorSurface" /> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/prv_text_color_on_accent.xml b/packages/SystemUI/res/color/prv_text_color_on_accent.xml new file mode 100644 index 000000000000..9f44acadb420 --- /dev/null +++ b/packages/SystemUI/res/color/prv_text_color_on_accent.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="?androidprv:attr/textColorOnAccent" /> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml new file mode 100644 index 000000000000..1a128dfe8b10 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:insetTop="@dimen/qs_dialog_button_vertical_inset" + android:insetBottom="@dimen/qs_dialog_button_vertical_inset"> + <ripple android:color="?android:attr/colorControlHighlight"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/white"/> + <corners android:radius="?android:attr/buttonCornerRadius"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <corners android:radius="?android:attr/buttonCornerRadius"/> + <solid android:color="?androidprv:attr/colorAccentPrimary"/> + <padding android:left="@dimen/qs_dialog_button_horizontal_padding" + android:top="@dimen/qs_dialog_button_vertical_padding" + android:right="@dimen/qs_dialog_button_horizontal_padding" + android:bottom="@dimen/qs_dialog_button_vertical_padding"/> + </shape> + </item> + </ripple> +</inset> diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml new file mode 100644 index 000000000000..467c20f3ffcd --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:insetTop="@dimen/qs_dialog_button_vertical_inset" + android:insetBottom="@dimen/qs_dialog_button_vertical_inset"> + <ripple android:color="?android:attr/colorControlHighlight"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/white"/> + <corners android:radius="?android:attr/buttonCornerRadius"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <corners android:radius="?android:attr/buttonCornerRadius"/> + <solid android:color="@android:color/transparent"/> + <stroke android:color="?androidprv:attr/colorAccentPrimary" + android:width="1dp" + /> + <padding android:left="@dimen/qs_dialog_button_horizontal_padding" + android:top="@dimen/qs_dialog_button_vertical_padding" + android:right="@dimen/qs_dialog_button_horizontal_padding" + android:bottom="@dimen/qs_dialog_button_vertical_padding"/> + </shape> + </item> + </ripple> +</inset> diff --git a/packages/SystemUI/res/layout/qs_user_dialog_content.xml b/packages/SystemUI/res/layout/qs_user_dialog_content.xml new file mode 100644 index 000000000000..321fe68e2f13 --- /dev/null +++ b/packages/SystemUI/res/layout/qs_user_dialog_content.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2021 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<androidx.constraintlayout.widget.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sysui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="24dp" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" + android:background="@drawable/qs_dialog_bg" +> + <TextView + android:id="@+id/title" + android:layout_height="wrap_content" + android:layout_width="0dp" + android:textAlignment="center" + android:text="@string/qs_user_switch_dialog_title" + android:textAppearance="@style/TextAppearance.QSDialog.Title" + android:layout_marginBottom="32dp" + sysui:layout_constraintTop_toTopOf="parent" + sysui:layout_constraintStart_toStartOf="parent" + sysui:layout_constraintEnd_toEndOf="parent" + sysui:layout_constraintBottom_toTopOf="@id/grid" + /> + + <com.android.systemui.qs.PseudoGridView + android:id="@+id/grid" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="28dp" + sysui:verticalSpacing="4dp" + sysui:horizontalSpacing="4dp" + sysui:fixedChildWidth="80dp" + sysui:layout_constraintTop_toBottomOf="@id/title" + sysui:layout_constraintStart_toStartOf="parent" + sysui:layout_constraintEnd_toEndOf="parent" + sysui:layout_constraintBottom_toTopOf="@id/barrier" + /> + + <androidx.constraintlayout.widget.Barrier + android:id="@+id/barrier" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + sysui:barrierDirection="top" + sysui:constraint_referenced_ids="settings,done" + /> + + <Button + android:id="@+id/settings" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:text="@string/quick_settings_more_user_settings" + sysui:layout_constraintTop_toBottomOf="@id/barrier" + sysui:layout_constraintBottom_toBottomOf="parent" + sysui:layout_constraintStart_toStartOf="parent" + sysui:layout_constraintEnd_toStartOf="@id/done" + sysui:layout_constraintHorizontal_chainStyle="spread_inside" + style="@style/Widget.QSDialog.Button.BorderButton" + /> + + <Button + android:id="@+id/done" + android:layout_width="wrap_content" + android:layout_height="48dp" + android:text="@string/quick_settings_done" + sysui:layout_constraintTop_toBottomOf="@id/barrier" + sysui:layout_constraintBottom_toBottomOf="parent" + sysui:layout_constraintStart_toEndOf="@id/settings" + sysui:layout_constraintEnd_toEndOf="parent" + style="@style/Widget.QSDialog.Button" + /> +</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 3121ce37490a..db699242a061 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -77,6 +77,7 @@ <attr name="numColumns" format="integer" /> <attr name="verticalSpacing" format="dimension" /> <attr name="horizontalSpacing" format="dimension" /> + <attr name="fixedChildWidth" format="dimension" /> </declare-styleable> <!-- Theme for icons in the status/nav bar (light/dark). background/fillColor is used for dual diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 9f257466ff28..946bbc289a03 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1639,4 +1639,9 @@ <item name="communal_source_height_percentage" format="float" type="dimen">0.80</item> <dimen name="drag_and_drop_icon_size">70dp</dimen> + + <dimen name="qs_dialog_button_horizontal_padding">16dp</dimen> + <dimen name="qs_dialog_button_vertical_padding">8dp</dimen> + <!-- The button will be 48dp tall, but the background needs to be 36dp tall --> + <dimen name="qs_dialog_button_vertical_inset">6dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index 9a438df5b7fc..d6d98b9397ac 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -53,4 +53,6 @@ <bool name="flag_smartspace_deduping">true</bool> <bool name="flag_combined_status_bar_signal_icons">false</bool> + + <bool name="flag_new_user_switcher">true</bool> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index c26de37517d4..ec63df5e0fe2 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3026,4 +3026,7 @@ <string name="see_all_networks">See all</string> <!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] --> <string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string> + + <!-- Title for User Switch dialog. [CHAR LIMIT=20] --> + <string name="qs_user_switch_dialog_title">Select user</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 6594216e4290..6e51ec715da5 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -929,6 +929,39 @@ <item name="actionDividerHeight">32dp</item> </style> + <style name="Theme.SystemUI.Dialog.QSDialog"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowIsFloating">true</item> + <item name="android:backgroundDimEnabled">true</item> + <item name="android:windowCloseOnTouchOutside">true</item> + <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> + <item name="android:dialogCornerRadius">28dp</item> + <item name="android:buttonCornerRadius">28dp</item> + <item name="android:colorBackground">@color/prv_color_surface</item> + </style> + + <style name="TextAppearance.QSDialog.Title" parent="Theme.SystemUI.Dialog.QSDialog"> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:textSize">24sp</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:lineHeight">32sp</item> + </style> + + <style name="Widget.QSDialog.Button" parent = "Theme.SystemUI.Dialog.QSDialog"> + <item name="android:background">@drawable/qs_dialog_btn_filled</item> + <item name="android:textColor">@color/prv_text_color_on_accent</item> + <item name="android:textSize">14sp</item> + <item name="android:lineHeight">20sp</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> + <item name="android:stateListAnimator">@null</item> + </style> + + <style name="Widget.QSDialog.Button.BorderButton"> + <item name="android:background">@drawable/qs_dialog_btn_outline</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> + <style name="Theme.SystemUI.Dialog.Internet"> <item name="android:windowBackground">@drawable/internet_dialog_background</item> </style> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index 60b06378a61a..f11dc9313852 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -824,11 +824,25 @@ public abstract class AuthBiometricView extends LinearLayout { return new AuthDialog.LayoutParams(width, totalHeight); } + private boolean isLargeDisplay() { + return com.android.systemui.util.Utils.shouldUseSplitNotificationShade(getResources()); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = MeasureSpec.getSize(widthMeasureSpec); final int height = MeasureSpec.getSize(heightMeasureSpec); - final int newWidth = Math.min(width, height); + + final boolean isLargeDisplay = isLargeDisplay(); + + final int newWidth; + if (isLargeDisplay) { + // TODO(b/201811580): Unless we can come up with a one-size-fits-all equation, we may + // want to consider moving this to an overlay. + newWidth = 2 * Math.min(width, height) / 3; + } else { + newWidth = Math.min(width, height); + } // Use "newWidth" instead, so the landscape dialog width is the same as the portrait // width. diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java index fa50f895f83e..f1e42e0c5454 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java @@ -117,24 +117,6 @@ public class AuthPanelController extends ViewOutlineProvider { mUseFullScreen = fullScreen; } - public ValueAnimator getTranslationAnimator(float relativeTranslationY) { - final ValueAnimator animator = ValueAnimator.ofFloat( - mPanelView.getY(), mPanelView.getY() - relativeTranslationY); - animator.addUpdateListener(animation -> { - final float translation = (float) animation.getAnimatedValue(); - mPanelView.setTranslationY(translation); - }); - return animator; - } - - public ValueAnimator getAlphaAnimator(float alpha) { - final ValueAnimator animator = ValueAnimator.ofFloat(mPanelView.getAlpha(), alpha); - animator.addUpdateListener(animation -> { - mPanelView.setAlpha((float) animation.getAnimatedValue()); - }); - return animator; - } - public void updateForContentDimensions(int contentWidth, int contentHeight, int animateDurationMs) { if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java index b17041bc83f2..f81811ac0ffb 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java @@ -192,6 +192,13 @@ public class FeatureFlags { return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); } + /** + * Use the new version of the user switcher + */ + public boolean useNewUserSwitcher() { + return mFlagReader.isEnabled(R.bool.flag_new_user_switcher); + } + /** static method for the system setting */ public static boolean isProviderModelSettingEnabled(Context context) { return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java index 87c64c78edc8..2f189beb7780 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java @@ -38,6 +38,7 @@ public class PseudoGridView extends ViewGroup { private int mNumColumns = 3; private int mVerticalSpacing; private int mHorizontalSpacing; + private int mFixedChildWidth = -1; public PseudoGridView(Context context, AttributeSet attrs) { super(context, attrs); @@ -53,6 +54,8 @@ public class PseudoGridView extends ViewGroup { mVerticalSpacing = a.getDimensionPixelSize(attr, 0); } else if (attr == R.styleable.PseudoGridView_horizontalSpacing) { mHorizontalSpacing = a.getDimensionPixelSize(attr, 0); + } else if (attr == R.styleable.PseudoGridView_fixedChildWidth) { + mFixedChildWidth = a.getDimensionPixelSize(attr, -1); } } @@ -65,8 +68,15 @@ public class PseudoGridView extends ViewGroup { throw new UnsupportedOperationException("Needs a maximum width"); } int width = MeasureSpec.getSize(widthMeasureSpec); - - int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns; + int childWidth; + int necessarySpaceForChildWidth = + mFixedChildWidth * mNumColumns + mHorizontalSpacing * (mNumColumns - 1); + if (mFixedChildWidth != -1 && necessarySpaceForChildWidth <= width) { + childWidth = mFixedChildWidth; + width = mFixedChildWidth * mNumColumns + mHorizontalSpacing * (mNumColumns - 1); + } else { + childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns; + } int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); int childHeightSpec = MeasureSpec.UNSPECIFIED; int totalHeight = 0; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index 04437ea14bb3..821bd5117d18 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -39,6 +39,8 @@ import com.android.systemui.qs.PseudoGridView; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.statusbar.policy.UserSwitcherController; +import java.util.function.Consumer; + import javax.inject.Inject; /** @@ -75,6 +77,7 @@ public class UserDetailView extends PseudoGridView { private View mCurrentUserView; private final UiEventLogger mUiEventLogger; private final FalsingManager mFalsingManager; + private Consumer<UserSwitcherController.UserRecord> mClickCallback; @Inject public Adapter(Context context, UserSwitcherController controller, @@ -92,6 +95,10 @@ public class UserDetailView extends PseudoGridView { return createUserDetailItemView(convertView, parent, item); } + public void injectCallback(Consumer<UserSwitcherController.UserRecord> clickCallback) { + mClickCallback = clickCallback; + } + public UserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent, UserSwitcherController.UserRecord item) { UserDetailItemView v = UserDetailItemView.convertOrInflate( @@ -167,6 +174,13 @@ public class UserDetailView extends PseudoGridView { } onUserListItemClicked(tag); } + if (mClickCallback != null) { + mClickCallback.accept(tag); + } + } + + public void linkToViewGroup(ViewGroup viewGroup) { + PseudoGridView.ViewGroupAdapterBridge.link(viewGroup, this); } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt new file mode 100644 index 000000000000..2ad06c1c172c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.user + +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.view.WindowInsets +import android.view.WindowManager +import com.android.systemui.qs.PseudoGridView +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.R + +/** + * Dialog for switching users or creating new ones. + */ +class UserDialog( + context: Context +) : SystemUIDialog(context, R.style.Theme_SystemUI_Dialog_QSDialog) { + + // create() is no-op after creation + private lateinit var _doneButton: View + /** + * Button with text "Done" in dialog. + */ + val doneButton: View + get() { + create() + return _doneButton + } + + private lateinit var _settingsButton: View + /** + * Button with text "User Settings" in dialog. + */ + val settingsButton: View + get() { + create() + return _settingsButton + } + + private lateinit var _grid: PseudoGridView + /** + * Grid to populate with user avatar from adapter + */ + val grid: ViewGroup + get() { + create() + return _grid + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window?.apply { + setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL) + attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars() + attributes.receiveInsetsIgnoringZOrder = true + setLayout( + context.resources.getDimensionPixelSize(R.dimen.qs_panel_width), + ViewGroup.LayoutParams.WRAP_CONTENT + ) + setGravity(Gravity.CENTER) + } + setContentView(R.layout.qs_user_dialog_content) + + _doneButton = requireViewById(R.id.done) + _settingsButton = requireViewById(R.id.settings) + _grid = requireViewById(R.id.grid) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt new file mode 100644 index 000000000000..a5e4ba1b5b4b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.user + +import android.content.Context +import android.content.Intent +import android.provider.Settings +import android.view.View +import androidx.annotation.VisibleForTesting +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.qs.tiles.UserDetailView +import javax.inject.Inject +import javax.inject.Provider + +/** + * Controller for [UserDialog]. + */ +@SysUISingleton +class UserSwitchDialogController @VisibleForTesting constructor( + private val userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>, + private val activityStarter: ActivityStarter, + private val falsingManager: FalsingManager, + private val dialogFactory: (Context) -> UserDialog +) { + + @Inject + constructor( + userDetailViewAdapterProvider: Provider<UserDetailView.Adapter>, + activityStarter: ActivityStarter, + falsingManager: FalsingManager + ) : this( + userDetailViewAdapterProvider, + activityStarter, + falsingManager, + { UserDialog(it) } + ) + + companion object { + private val USER_SETTINGS_INTENT = Intent(Settings.ACTION_USER_SETTINGS) + } + + /** + * Show a [UserDialog]. + * + * Populate the dialog with information from and adapter obtained from + * [userDetailViewAdapterProvider] and show it as launched from [view]. + */ + fun showDialog(view: View) { + with(dialogFactory(view.context)) { + setShowForAllUsers(true) + setCanceledOnTouchOutside(true) + create() // Needs to be called before we can retrieve views + + settingsButton.setOnClickListener { + if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { + activityStarter.postStartActivityDismissingKeyguard(USER_SETTINGS_INTENT, 0) + } + dismiss() + } + doneButton.setOnClickListener { dismiss() } + + val adapter = userDetailViewAdapterProvider.get() + adapter.injectCallback { + dismiss() + } + adapter.linkToViewGroup(grid) + + show() + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 19876ba063bb..cbb3aba5cc64 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -446,7 +446,7 @@ public class StatusBarStateControllerImpl implements mIsFullscreen = isFullscreen; synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.mListener.onFullscreenStateChanged(isFullscreen, true /* isImmersive */); + rl.mListener.onFullscreenStateChanged(isFullscreen); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java index 3fdf1ceaa2d9..dd21c8af37e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java @@ -23,11 +23,13 @@ import android.view.View; import android.view.ViewGroup; import com.android.systemui.R; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.qs.FooterActionsView; import com.android.systemui.qs.QSDetailDisplayer; import com.android.systemui.qs.dagger.QSScope; +import com.android.systemui.qs.user.UserSwitchDialogController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.ViewController; @@ -39,6 +41,8 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> { private final UserSwitcherController mUserSwitcherController; private final QSDetailDisplayer mQsDetailDisplayer; private final FalsingManager mFalsingManager; + private final UserSwitchDialogController mUserSwitchDialogController; + private final FeatureFlags mFeatureFlags; private UserSwitcherController.BaseUserAdapter mUserListener; @@ -49,14 +53,18 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> { return; } - View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView; + if (mFeatureFlags.useNewUserSwitcher()) { + mUserSwitchDialogController.showDialog(v); + } else { + View center = mView.getChildCount() > 0 ? mView.getChildAt(0) : mView; - int[] tmpInt = new int[2]; - center.getLocationInWindow(tmpInt); - tmpInt[0] += center.getWidth() / 2; - tmpInt[1] += center.getHeight() / 2; + int[] tmpInt = new int[2]; + center.getLocationInWindow(tmpInt); + tmpInt[0] += center.getWidth() / 2; + tmpInt[1] += center.getHeight() / 2; - mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]); + mQsDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]); + } } }; @@ -66,31 +74,40 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> { private final UserSwitcherController mUserSwitcherController; private final QSDetailDisplayer mQsDetailDisplayer; private final FalsingManager mFalsingManager; + private final UserSwitchDialogController mUserSwitchDialogController; + private final FeatureFlags mFeatureFlags; @Inject public Factory(UserManager userManager, UserSwitcherController userSwitcherController, - QSDetailDisplayer qsDetailDisplayer, FalsingManager falsingManager) { + QSDetailDisplayer qsDetailDisplayer, FalsingManager falsingManager, + UserSwitchDialogController userSwitchDialogController, + FeatureFlags featureFlags) { mUserManager = userManager; mUserSwitcherController = userSwitcherController; mQsDetailDisplayer = qsDetailDisplayer; mFalsingManager = falsingManager; + mUserSwitchDialogController = userSwitchDialogController; + mFeatureFlags = featureFlags; } public MultiUserSwitchController create(FooterActionsView view) { return new MultiUserSwitchController(view.findViewById(R.id.multi_user_switch), mUserManager, mUserSwitcherController, mQsDetailDisplayer, - mFalsingManager); + mFalsingManager, mUserSwitchDialogController, mFeatureFlags); } } private MultiUserSwitchController(MultiUserSwitch view, UserManager userManager, UserSwitcherController userSwitcherController, QSDetailDisplayer qsDetailDisplayer, - FalsingManager falsingManager) { + FalsingManager falsingManager, UserSwitchDialogController userSwitchDialogController, + FeatureFlags featureFlags) { super(view); mUserManager = userManager; mUserSwitcherController = userSwitcherController; mQsDetailDisplayer = qsDetailDisplayer; mFalsingManager = falsingManager; + mUserSwitchDialogController = userSwitchDialogController; + mFeatureFlags = featureFlags; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 90e554041dbc..27770c7e53b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -2696,8 +2696,9 @@ public class NotificationPanelViewController extends PanelViewController { * @return Whether we should intercept a gesture to open Quick Settings. */ private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) { - if (!isQsExpansionEnabled() || mCollapsedOnDown || (mKeyguardShowing - && mKeyguardBypassController.getBypassEnabled())) { + if (!isQsExpansionEnabled() || mCollapsedOnDown + || (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()) + || (mKeyguardShowing && mShouldUseSplitNotificationShade)) { return false; } View header = mKeyguardShowing || mQs == null ? mKeyguardStatusBar : mQs.getHeader(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 78ab0d7f8a2f..7b3fc849df03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -628,6 +628,7 @@ public class StatusBar extends SystemUI implements private final Executor mUiBgExecutor; protected boolean mDozing; + private boolean mIsFullscreen; private final NotificationMediaManager mMediaManager; private final NotificationLockscreenUserManager mLockscreenUserManager; @@ -909,6 +910,9 @@ public class StatusBar extends SystemUI implements mActivityLaunchAnimator = activityLaunchAnimator; mDialogLaunchAnimator = dialogLaunchAnimator; + // The status bar background may need updating when the ongoing call status changes. + mOngoingCallController.addCallback((animate) -> maybeUpdateBarMode()); + // TODO(b/190746471): Find a better home for this. DateTimeView.setReceiverHandler(timeTickHandler); @@ -2242,7 +2246,7 @@ public class StatusBar extends SystemUI implements if (!mTransientShown) { mTransientShown = true; mNoAnimationOnNextBarModeChange = true; - handleTransientChanged(); + maybeUpdateBarMode(); } } @@ -2250,11 +2254,11 @@ public class StatusBar extends SystemUI implements void clearTransient() { if (mTransientShown) { mTransientShown = false; - handleTransientChanged(); + maybeUpdateBarMode(); } } - private void handleTransientChanged() { + private void maybeUpdateBarMode() { final int barMode = barMode(mTransientShown, mAppearance); if (updateBarMode(barMode)) { mLightBarController.onStatusBarModeChanged(barMode); @@ -2272,9 +2276,11 @@ public class StatusBar extends SystemUI implements return false; } - private static @TransitionMode int barMode(boolean isTransient, int appearance) { + private @TransitionMode int barMode(boolean isTransient, int appearance) { final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_STATUS_BARS; - if (isTransient) { + if (mOngoingCallController.hasOngoingCall() && mIsFullscreen) { + return MODE_SEMI_TRANSPARENT; + } else if (isTransient) { return MODE_SEMI_TRANSPARENT; } else if ((appearance & lightsOutOpaque) == lightsOutOpaque) { return MODE_LIGHTS_OUT; @@ -4476,6 +4482,12 @@ public class StatusBar extends SystemUI implements updateReportRejectedTouchVisibility(); Trace.endSection(); } + + @Override + public void onFullscreenStateChanged(boolean isFullscreen) { + mIsFullscreen = isFullscreen; + maybeUpdateBarMode(); + } }; private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java index d838a05135e7..b4aba380d971 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -35,10 +35,12 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherScope; import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.tiles.UserDetailView; +import com.android.systemui.qs.user.UserSwitchDialogController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; @@ -76,6 +78,8 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout> private final ConfigurationController mConfigurationController; private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; private final KeyguardUserDetailAdapter mUserDetailAdapter; + private final FeatureFlags mFeatureFlags; + private final UserSwitchDialogController mUserSwitchDialogController; private NotificationPanelViewController mNotificationPanelViewController; private UserAvatarView mUserAvatarView; UserSwitcherController.UserRecord mCurrentUser; @@ -124,7 +128,9 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout> SysuiStatusBarStateController statusBarStateController, DozeParameters dozeParameters, Provider<UserDetailView.Adapter> userDetailViewAdapterProvider, - UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) { + UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, + FeatureFlags featureFlags, + UserSwitchDialogController userSwitchDialogController) { super(view); if (DEBUG) Log.d(TAG, "New KeyguardQsUserSwitchController"); mContext = context; @@ -139,6 +145,8 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout> keyguardStateController, dozeParameters, unlockedScreenOffAnimationController, /* animateYPos= */ false); mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider); + mFeatureFlags = featureFlags; + mUserSwitchDialogController = userSwitchDialogController; } @Override @@ -162,7 +170,11 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout> } // Tapping anywhere in the view will open QS user panel - openQsUserPanel(); + if (mFeatureFlags.useNewUserSwitcher()) { + mUserSwitchDialogController.showDialog(mView); + } else { + openQsUserPanel(); + } }); mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() { diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java index 0ba072e9e72f..f97f4d0edc24 100644 --- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java +++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java @@ -31,7 +31,6 @@ import java.util.Arrays; public class NotificationChannels extends SystemUI { public static String ALERTS = "ALR"; - public static String SCREENSHOTS_LEGACY = "SCN"; public static String SCREENSHOTS_HEADSUP = "SCN_HEADSUP"; public static String GENERAL = "GEN"; public static String STORAGE = "DSK"; @@ -84,18 +83,11 @@ public class NotificationChannels extends SystemUI { general, storage, createScreenshotChannel( - context.getString(R.string.notification_channel_screenshot), - nm.getNotificationChannel(SCREENSHOTS_LEGACY)), + context.getString(R.string.notification_channel_screenshot)), batteryChannel, hint )); - // Delete older SS channel if present. - // Screenshots promoted to heads-up in P, this cleans up the lower priority channel from O. - // This line can be deleted in Q. - nm.deleteNotificationChannel(SCREENSHOTS_LEGACY); - - if (isTv(context)) { // TV specific notification channel for TV PIP controls. // Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest @@ -113,7 +105,7 @@ public class NotificationChannels extends SystemUI { * @return */ @VisibleForTesting static NotificationChannel createScreenshotChannel( - String name, NotificationChannel legacySS) { + String name) { NotificationChannel screenshotChannel = new NotificationChannel(SCREENSHOTS_HEADSUP, name, NotificationManager.IMPORTANCE_HIGH); // pop on screen @@ -121,24 +113,6 @@ public class NotificationChannels extends SystemUI { new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build()); screenshotChannel.setBlockable(true); - if (legacySS != null) { - // Respect any user modified fields from the old channel. - int userlock = legacySS.getUserLockedFields(); - if ((userlock & NotificationChannel.USER_LOCKED_IMPORTANCE) != 0) { - screenshotChannel.setImportance(legacySS.getImportance()); - } - if ((userlock & NotificationChannel.USER_LOCKED_SOUND) != 0) { - screenshotChannel.setSound(legacySS.getSound(), legacySS.getAudioAttributes()); - } - if ((userlock & NotificationChannel.USER_LOCKED_VIBRATION) != 0) { - screenshotChannel.setVibrationPattern(legacySS.getVibrationPattern()); - } - if ((userlock & NotificationChannel.USER_LOCKED_LIGHTS) != 0) { - screenshotChannel.setLightColor(legacySS.getLightColor()); - } - // skip show_badge, irrelevant for system channel - } - return screenshotChannel; } diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt index 2c01a7003a16..db2aca873d0c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt +++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt @@ -40,8 +40,8 @@ class WallpaperController @Inject constructor(private val wallpaperManager: Wall this.wallpaperInfo = wallpaperInfo } - private val shouldUseDefaultDisplayStateChangeTransition: Boolean - get() = wallpaperInfo?.shouldUseDefaultDisplayStateChangeTransition() + private val shouldUseDefaultUnfoldTransition: Boolean + get() = wallpaperInfo?.shouldUseDefaultUnfoldTransition() ?: true fun setNotificationShadeZoom(zoomOut: Float) { @@ -50,7 +50,7 @@ class WallpaperController @Inject constructor(private val wallpaperManager: Wall } fun setUnfoldTransitionZoom(zoomOut: Float) { - if (shouldUseDefaultDisplayStateChangeTransition) { + if (shouldUseDefaultUnfoldTransition) { unfoldTransitionZoomOut = zoomOut updateZoom() } diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java index 28cba8e16970..40982bb18023 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java @@ -18,8 +18,7 @@ package com.android.systemui.util.sensors; import android.util.Log; -import androidx.annotation.NonNull; - +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.Execution; @@ -42,9 +41,9 @@ class PostureDependentProximitySensor extends ProximitySensorImpl { PostureDependentProximitySensor( @PrimaryProxSensor ThresholdSensor[] postureToPrimaryProxSensorMap, @SecondaryProxSensor ThresholdSensor[] postureToSecondaryProxSensorMap, - @NonNull DelayableExecutor delayableExecutor, - @NonNull Execution execution, - @NonNull DevicePostureController devicePostureController + @Main DelayableExecutor delayableExecutor, + Execution execution, + DevicePostureController devicePostureController ) { super( postureToPrimaryProxSensorMap[0], diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index ff263109d555..514a9035a9ef 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -73,6 +73,7 @@ import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.sizecompatui.SizeCompatUIController; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.splitscreen.StageTaskUnfoldController; import com.android.wm.shell.startingsurface.StartingSurface; import com.android.wm.shell.startingsurface.StartingWindowController; import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; @@ -81,10 +82,14 @@ import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController; import com.android.wm.shell.transition.ShellTransitions; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; +import com.android.wm.shell.unfold.UnfoldBackgroundController; import java.util.Optional; +import javax.inject.Provider; + import dagger.BindsOptionalOf; +import dagger.Lazy; import dagger.Module; import dagger.Provides; @@ -234,16 +239,48 @@ public abstract class WMShellBaseModule { static Optional<FullscreenUnfoldController> provideFullscreenUnfoldController( Context context, Optional<ShellUnfoldProgressProvider> progressProvider, - RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + Lazy<UnfoldBackgroundController> unfoldBackgroundController, DisplayInsetsController displayInsetsController, @ShellMainThread ShellExecutor mainExecutor ) { return progressProvider.map(shellUnfoldTransitionProgressProvider -> new FullscreenUnfoldController(context, mainExecutor, - shellUnfoldTransitionProgressProvider, rootTaskDisplayAreaOrganizer, + unfoldBackgroundController.get(), shellUnfoldTransitionProgressProvider, displayInsetsController)); } + @Provides + static Optional<StageTaskUnfoldController> provideStageTaskUnfoldController( + Optional<ShellUnfoldProgressProvider> progressProvider, + Context context, + TransactionPool transactionPool, + Lazy<UnfoldBackgroundController> unfoldBackgroundController, + DisplayInsetsController displayInsetsController, + @ShellMainThread ShellExecutor mainExecutor + ) { + return progressProvider.map(shellUnfoldTransitionProgressProvider -> + new StageTaskUnfoldController( + context, + transactionPool, + shellUnfoldTransitionProgressProvider, + displayInsetsController, + unfoldBackgroundController.get(), + mainExecutor + )); + } + + @WMSingleton + @Provides + static UnfoldBackgroundController provideUnfoldBackgroundController( + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + Context context + ) { + return new UnfoldBackgroundController( + context, + rootTaskDisplayAreaOrganizer + ); + } + // // Freeform (optional feature) // @@ -401,12 +438,13 @@ public abstract class WMShellBaseModule { @ShellMainThread ShellExecutor mainExecutor, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, - TransactionPool transactionPool) { + TransactionPool transactionPool, + Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) { if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) { return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context, rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, displayInsetsController, transitions, - transactionPool)); + transactionPool, stageTaskUnfoldControllerProvider)); } else { return Optional.empty(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt new file mode 100644 index 000000000000..d5fe588b2115 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserDialogTest.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.user + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.View +import android.view.ViewGroup +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class UserDialogTest : SysuiTestCase() { + + private lateinit var dialog: UserDialog + + @Before + fun setUp() { + dialog = UserDialog(mContext) + } + + @After + fun tearDown() { + dialog.dismiss() + } + + @Test + fun doneButtonExists() { + assertThat(dialog.doneButton).isInstanceOf(View::class.java) + } + + @Test + fun settingsButtonExists() { + assertThat(dialog.settingsButton).isInstanceOf(View::class.java) + } + + @Test + fun gridExistsAndIsViewGroup() { + assertThat(dialog.grid).isInstanceOf(ViewGroup::class.java) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt new file mode 100644 index 000000000000..a1760a79417f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.user + +import android.content.Intent +import android.provider.Settings +import android.testing.AndroidTestingRunner +import android.view.View +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.qs.PseudoGridView +import com.android.systemui.qs.tiles.UserDetailView +import com.android.systemui.statusbar.policy.UserSwitcherController +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.eq +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatcher +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.argThat +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import java.util.function.Consumer + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class UserSwitchDialogControllerTest : SysuiTestCase() { + + @Mock + private lateinit var dialog: UserDialog + @Mock + private lateinit var falsingManager: FalsingManager + @Mock + private lateinit var settingsView: View + @Mock + private lateinit var doneView: View + @Mock + private lateinit var activityStarter: ActivityStarter + @Mock + private lateinit var userDetailViewAdapter: UserDetailView.Adapter + @Mock + private lateinit var launchView: View + @Mock + private lateinit var gridView: PseudoGridView + @Captor + private lateinit var clickCaptor: ArgumentCaptor<View.OnClickListener> + + private lateinit var controller: UserSwitchDialogController + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + `when`(dialog.settingsButton).thenReturn(settingsView) + `when`(dialog.doneButton).thenReturn(doneView) + `when`(dialog.grid).thenReturn(gridView) + + `when`(launchView.context).thenReturn(mContext) + + controller = UserSwitchDialogController( + { userDetailViewAdapter }, + activityStarter, + falsingManager, + { dialog } + ) + } + + @Test + fun showDialog_callsDialogShow() { + controller.showDialog(launchView) + verify(dialog).show() + } + + @Test + fun createCalledBeforeDoneButton() { + controller.showDialog(launchView) + val inOrder = inOrder(dialog) + inOrder.verify(dialog).create() + inOrder.verify(dialog).doneButton + } + + @Test + fun createCalledBeforeSettingsButton() { + controller.showDialog(launchView) + val inOrder = inOrder(dialog) + inOrder.verify(dialog).create() + inOrder.verify(dialog).settingsButton + } + + @Test + fun createCalledBeforeGrid() { + controller.showDialog(launchView) + val inOrder = inOrder(dialog) + inOrder.verify(dialog).create() + inOrder.verify(dialog).grid + } + + @Test + fun dialog_showForAllUsers() { + controller.showDialog(launchView) + verify(dialog).setShowForAllUsers(true) + } + + @Test + fun dialog_cancelOnTouchOutside() { + controller.showDialog(launchView) + verify(dialog).setCanceledOnTouchOutside(true) + } + + @Test + fun adapterAndGridLinked() { + controller.showDialog(launchView) + verify(userDetailViewAdapter).linkToViewGroup(gridView) + } + + @Test + fun clickDoneButton_dismiss() { + controller.showDialog(launchView) + + verify(doneView).setOnClickListener(capture(clickCaptor)) + + clickCaptor.value.onClick(doneView) + + verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt()) + verify(dialog).dismiss() + } + + @Test + fun clickSettingsButton_noFalsing_opensSettingsAndDismisses() { + `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false) + + controller.showDialog(launchView) + + verify(settingsView).setOnClickListener(capture(clickCaptor)) + + clickCaptor.value.onClick(settingsView) + + verify(activityStarter) + .postStartActivityDismissingKeyguard( + argThat(IntentMatcher(Settings.ACTION_USER_SETTINGS)), + eq(0) + ) + verify(dialog).dismiss() + } + + @Test + fun clickSettingsButton_Falsing_notOpensSettingsAndDismisses() { + `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true) + + controller.showDialog(launchView) + + verify(settingsView).setOnClickListener(capture(clickCaptor)) + + clickCaptor.value.onClick(settingsView) + + verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt()) + verify(dialog).dismiss() + } + + @Test + fun callbackFromDetailView_dismissesDialog() { + val captor = argumentCaptor<Consumer<UserSwitcherController.UserRecord>>() + + controller.showDialog(launchView) + verify(userDetailViewAdapter).injectCallback(capture(captor)) + + captor.value.accept(mock(UserSwitcherController.UserRecord::class.java)) + + verify(dialog).dismiss() + } + + private class IntentMatcher(private val action: String) : ArgumentMatcher<Intent> { + override fun matches(argument: Intent?): Boolean { + return argument?.action == action + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java index f1c9980f12c4..c7bcdefdc4c3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.verify; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; -import android.provider.Settings; import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; @@ -68,51 +67,4 @@ public class ChannelsTest extends SysuiTestCase { list.forEach((chan) -> assertTrue(ALL_CHANNELS.contains(chan.getId()))); } - @Test - public void testChannelSetup_noLegacyScreenshot() { - // Assert old channel cleaned up. - // TODO: remove that code + this test after P. - NotificationChannels.createAll(mContext); - ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); - verify(mMockNotificationManager).deleteNotificationChannel( - NotificationChannels.SCREENSHOTS_LEGACY); - } - - @Test - public void testInheritFromLegacy_keepsUserLockedLegacySettings() { - NotificationChannel legacyChannel = new NotificationChannel("id", "oldName", - NotificationManager.IMPORTANCE_MIN); - legacyChannel.setImportance(NotificationManager.IMPORTANCE_NONE);; - legacyChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, - legacyChannel.getAudioAttributes()); - legacyChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE | - NotificationChannel.USER_LOCKED_SOUND); - NotificationChannel newChannel = - NotificationChannels.createScreenshotChannel("newName", legacyChannel); - // NONE importance user locked, so don't use HIGH for new channel. - assertEquals(NotificationManager.IMPORTANCE_NONE, newChannel.getImportance()); - assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, newChannel.getSound()); - } - - @Test - public void testInheritFromLegacy_dropsUnlockedLegacySettings() { - NotificationChannel legacyChannel = new NotificationChannel("id", "oldName", - NotificationManager.IMPORTANCE_MIN); - NotificationChannel newChannel = - NotificationChannels.createScreenshotChannel("newName", legacyChannel); - assertEquals(null, newChannel.getSound()); - assertEquals("newName", newChannel.getName()); - // MIN importance not user locked, so HIGH wins out. - assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance()); - } - - @Test - public void testInheritFromLegacy_noLegacyExists() { - NotificationChannel newChannel = - NotificationChannels.createScreenshotChannel("newName", null); - assertEquals(null, newChannel.getSound()); - assertEquals("newName", newChannel.getName()); - assertEquals(NotificationManager.IMPORTANCE_HIGH, newChannel.getImportance()); - } - } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt index b54aadb8228f..d8e418a7815c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt @@ -138,7 +138,7 @@ class WallpaperControllerTest : SysuiTestCase() { private fun createWallpaperInfo(useDefaultTransition: Boolean = true): WallpaperInfo { val info = mock(WallpaperInfo::class.java) - whenever(info.shouldUseDefaultDisplayStateChangeTransition()) + whenever(info.shouldUseDefaultUnfoldTransition()) .thenReturn(useDefaultTransition) return info } diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index b0893cc360b7..ed37d7e2e6e6 100644 --- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java +++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java @@ -19,6 +19,7 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Camera; import android.graphics.GraphicBuffer; import android.graphics.Rect; import android.hardware.camera2.CameraAccessException; @@ -135,6 +136,7 @@ public class CameraExtensionsProxyService extends Service { private HashMap<String, CameraCharacteristics> mCharacteristicsHashMap = new HashMap<>(); private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>(); + private CameraManager mCameraManager; private static boolean checkForAdvancedAPI() { if (EXTENSIONS_PRESENT && EXTENSIONS_VERSION.startsWith(ADVANCED_VERSION_PREFIX)) { @@ -460,12 +462,12 @@ public class CameraExtensionsProxyService extends Service { // This will setup the camera vendor tag descriptor in the service process // along with all camera characteristics. try { - CameraManager manager = getSystemService(CameraManager.class); + mCameraManager = getSystemService(CameraManager.class); - String [] cameraIds = manager.getCameraIdListNoLazy(); + String [] cameraIds = mCameraManager.getCameraIdListNoLazy(); if (cameraIds != null) { for (String cameraId : cameraIds) { - CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId); + CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId); mCharacteristicsHashMap.put(cameraId, chars); Object thisClass = CameraCharacteristics.Key.class; Class<CameraCharacteristics.Key<?>> keyClass = @@ -1174,8 +1176,9 @@ public class CameraExtensionsProxyService extends Service { @Override public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) { mCameraId = cameraId; - mPreviewExtender.onInit(cameraId, new CameraCharacteristics(cameraCharacteristics), - CameraExtensionsProxyService.this); + CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics); + mCameraManager.registerDeviceStateListener(chars); + mPreviewExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this); } @Override @@ -1200,13 +1203,16 @@ public class CameraExtensionsProxyService extends Service { @Override public void init(String cameraId, CameraMetadataNative chars) { - mPreviewExtender.init(cameraId, new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + mPreviewExtender.init(cameraId, c); } @Override public boolean isExtensionAvailable(String cameraId, CameraMetadataNative chars) { - return mPreviewExtender.isExtensionAvailable(cameraId, - new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + return mPreviewExtender.isExtensionAvailable(cameraId, c); } @Override @@ -1283,8 +1289,9 @@ public class CameraExtensionsProxyService extends Service { @Override public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) { - mImageExtender.onInit(cameraId, new CameraCharacteristics(cameraCharacteristics), - CameraExtensionsProxyService.this); + CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics); + mCameraManager.registerDeviceStateListener(chars); + mImageExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this); mCameraId = cameraId; } @@ -1310,13 +1317,16 @@ public class CameraExtensionsProxyService extends Service { @Override public void init(String cameraId, CameraMetadataNative chars) { - mImageExtender.init(cameraId, new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + mImageExtender.init(cameraId, c); } @Override public boolean isExtensionAvailable(String cameraId, CameraMetadataNative chars) { - return mImageExtender.isExtensionAvailable(cameraId, - new CameraCharacteristics(chars)); + CameraCharacteristics c = new CameraCharacteristics(chars); + mCameraManager.registerDeviceStateListener(c); + return mImageExtender.isExtensionAvailable(cameraId, c); } @Override diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 7ba032f683b8..e9aa3be8b403 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -659,11 +659,13 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { // Inform mStats about each applicable measured energy (unless addressed elsewhere). if (measuredEnergyDeltas != null) { - final long displayChargeUC = measuredEnergyDeltas.displayChargeUC; - if (displayChargeUC != MeasuredEnergySnapshot.UNAVAILABLE) { + final long[] displayChargeUC = measuredEnergyDeltas.displayChargeUC; + if (displayChargeUC != null && displayChargeUC.length > 0) { + // TODO (b/194107383): pass all display ordinals to mStats. + final long primaryDisplayChargeUC = displayChargeUC[0]; // If updating, pass in what BatteryExternalStatsWorker thinks screenState is. - mStats.updateDisplayMeasuredEnergyStatsLocked(displayChargeUC, screenState, - elapsedRealtime); + mStats.updateDisplayMeasuredEnergyStatsLocked(primaryDisplayChargeUC, + screenState, elapsedRealtime); } final long gnssChargeUC = measuredEnergyDeltas.gnssChargeUC; @@ -948,6 +950,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { switch (consumer.type) { case EnergyConsumerType.OTHER: case EnergyConsumerType.CPU_CLUSTER: + case EnergyConsumerType.DISPLAY: break; default: Slog.w(TAG, "EnergyConsumer '" + consumer.name + "' has unexpected ordinal " diff --git a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java index a9fca4f24026..0359aa531c64 100644 --- a/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java +++ b/services/core/java/com/android/server/am/MeasuredEnergySnapshot.java @@ -49,6 +49,9 @@ public class MeasuredEnergySnapshot { /** Number of ordinals for {@link EnergyConsumerType#CPU_CLUSTER}. */ private final int mNumCpuClusterOrdinals; + /** Number of ordinals for {@link EnergyConsumerType#DISPLAY}. */ + private final int mNumDisplayOrdinals; + /** Number of ordinals for {@link EnergyConsumerType#OTHER}. */ private final int mNumOtherOrdinals; @@ -95,6 +98,7 @@ public class MeasuredEnergySnapshot { mNumCpuClusterOrdinals = calculateNumOrdinals(EnergyConsumerType.CPU_CLUSTER, idToConsumerMap); + mNumDisplayOrdinals = calculateNumOrdinals(EnergyConsumerType.DISPLAY, idToConsumerMap); mNumOtherOrdinals = calculateNumOrdinals(EnergyConsumerType.OTHER, idToConsumerMap); mAttributionSnapshots = new SparseArray<>(mNumOtherOrdinals); } @@ -108,7 +112,7 @@ public class MeasuredEnergySnapshot { public long[] cpuClusterChargeUC = null; /** The chargeUC for {@link EnergyConsumerType#DISPLAY}. */ - public long displayChargeUC = UNAVAILABLE; + public long[] displayChargeUC = null; /** The chargeUC for {@link EnergyConsumerType#GNSS}. */ public long gnssChargeUC = UNAVAILABLE; @@ -212,7 +216,10 @@ public class MeasuredEnergySnapshot { break; case EnergyConsumerType.DISPLAY: - output.displayChargeUC = deltaChargeUC; + if (output.displayChargeUC == null) { + output.displayChargeUC = new long[mNumDisplayOrdinals]; + } + output.displayChargeUC[ordinal] = deltaChargeUC; break; case EnergyConsumerType.GNSS: diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java index fa33338a61e7..03e421bfed67 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java @@ -209,6 +209,12 @@ public class ContextHubClientBroker extends IContextHubClient.Stub */ private AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false); + /** + * True if a permissions query has been issued and is being processed. Used to prevent too many + * queries from being issued by a single client at once. + */ + private AtomicBoolean mIsPermQueryIssued = new AtomicBoolean(false); + /* * True if the application creating the client has the ACCESS_CONTEXT_HUB permission. */ @@ -240,11 +246,11 @@ public class ContextHubClientBroker extends IContextHubClient.Stub private final IContextHubTransactionCallback mQueryPermsCallback = new IContextHubTransactionCallback.Stub() { @Override - public void onTransactionComplete(int result) { - } + public void onTransactionComplete(int result) {} @Override public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) { + mIsPermQueryIssued.set(false); if (result != ContextHubTransaction.RESULT_SUCCESS && nanoAppStateList != null) { Log.e(TAG, "Permissions query failed, but still received nanoapp state"); } else if (nanoAppStateList != null) { @@ -656,9 +662,11 @@ public class ContextHubClientBroker extends IContextHubClient.Stub * communicated with in the past. */ private void checkNanoappPermsAsync() { - ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( - mAttachedContextHubInfo.getId(), mQueryPermsCallback, mPackage); - mTransactionManager.addTransaction(transaction); + if (!mIsPermQueryIssued.getAndSet(true)) { + ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( + mAttachedContextHubInfo.getId(), mQueryPermsCallback, mPackage); + mTransactionManager.addTransaction(transaction); + } } private int updateNanoAppAuthState( diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java index cc51cea05160..22a675ad39ab 100644 --- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java +++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java @@ -105,15 +105,20 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation synchronized (mLock) { mDeviceIdleHelper.addListener(this); - onDeviceIdleChanged(mDeviceIdleHelper.isDeviceIdle()); + mDeviceIdle = mDeviceIdleHelper.isDeviceIdle(); + mDeviceStationaryHelper.addListener(this); + mDeviceStationary = false; + mDeviceStationaryRealtimeMs = Long.MIN_VALUE; + + onThrottlingChangedLocked(false); } } @Override protected void onStop() { synchronized (mLock) { + mDeviceStationaryHelper.removeListener(this); mDeviceIdleHelper.removeListener(this); - onDeviceIdleChanged(false); mIncomingRequest = ProviderRequest.EMPTY_REQUEST; mOutgoingRequest = ProviderRequest.EMPTY_REQUEST; @@ -146,27 +151,13 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation } mDeviceIdle = deviceIdle; - - if (deviceIdle) { - // device stationary helper will deliver an immediate listener update - mDeviceStationaryHelper.addListener(this); - } else { - mDeviceStationaryHelper.removeListener(this); - mDeviceStationary = false; - mDeviceStationaryRealtimeMs = Long.MIN_VALUE; - onThrottlingChangedLocked(false); - } + onThrottlingChangedLocked(false); } } @Override public void onDeviceStationaryChanged(boolean deviceStationary) { synchronized (mLock) { - if (!mDeviceIdle) { - // stationary detection is only registered while idle - ignore late notifications - return; - } - if (mDeviceStationary == deviceStationary) { return; } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f39fa0396d8d..394ff755d252 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -401,10 +401,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1; private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2; - /** - * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k. - */ - @VisibleForTesting static final int Z_BOOST_BASE = 800570000; static final int INVALID_PID = -1; // How long we wait until giving up on the last activity to pause. This @@ -4244,20 +4240,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return callback.test(this) ? this : null; } - @Override - protected void setLayer(Transaction t, int layer) { - if (!mSurfaceAnimator.hasLeash()) { - t.setLayer(mSurfaceControl, layer); - } - } - - @Override - protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { - if (!mSurfaceAnimator.hasLeash()) { - t.setRelativeLayer(mSurfaceControl, relativeTo, layer); - } - } - void logStartActivity(int tag, Task task) { final Uri data = intent.getData(); final String strData = data != null ? data.toSafeString() : null; @@ -6796,12 +6778,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return candidate; } - SurfaceControl getAppAnimationLayer() { - return getAppAnimationLayer(isActivityTypeHome() ? ANIMATION_LAYER_HOME - : needsZBoost() ? ANIMATION_LAYER_BOOSTED - : ANIMATION_LAYER_STANDARD); - } - @Override boolean needsZBoost() { return mNeedsZBoost || super.needsZBoost(); @@ -6862,29 +6838,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A || mDisplayContent.isNextTransitionForward(); } - private int getAnimationLayer() { - // The leash is parented to the animation layer. We need to preserve the z-order by using - // the prefix order index, but we boost if necessary. - int layer; - if (!inPinnedWindowingMode()) { - layer = getPrefixOrderIndex(); - } else { - // Root pinned tasks have animations take place within themselves rather than an - // animation layer so we need to preserve the order relative to the root task (e.g. - // the order of our task/parent). - layer = getParent().getPrefixOrderIndex(); - } - - if (mNeedsZBoost) { - layer += Z_BOOST_BASE; - } - return layer; - } - @Override - public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { - t.setLayer(leash, getAnimationLayer()); - getDisplayContent().assignRootTaskOrdering(); + void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) { + // Noop as Activity may be offset for letterbox } @Override @@ -6913,7 +6869,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Crop to root task bounds. t.setLayer(leash, 0); - t.setLayer(mAnimationBoundsLayer, getAnimationLayer()); + t.setLayer(mAnimationBoundsLayer, getLastLayer()); // Reparent leash to animation bounds layer. t.reparent(leash, mAnimationBoundsLayer); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index d709abb4cf5c..60a514e4d612 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3424,9 +3424,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final List<RemoteAction> actions = r.pictureInPictureArgs.getActions(); mRootWindowContainer.moveActivityToPinnedRootTask( r, "enterPictureInPictureMode"); - final Task rootTask = r.getRootTask(); - rootTask.setPictureInPictureAspectRatio(aspectRatio); - rootTask.setPictureInPictureActions(actions); + final Task task = r.getTask(); + task.setPictureInPictureAspectRatio(aspectRatio); + task.setPictureInPictureActions(actions); + + // Continue the pausing process after entering pip. + if (task.getPausingActivity() == r) { + task.schedulePauseActivity(r, false /* userLeaving */, + false /* pauseImmediately */, "auto-pip"); + } } }; diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index eeb85c585876..5a2cf17ffd18 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -28,6 +28,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.activityTypeToString; import static android.app.WindowConfiguration.windowingModeToString; +import static android.app.WindowConfigurationProto.WINDOWING_MODE; +import static android.content.ConfigurationProto.WINDOW_CONFIGURATION; import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION; import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION; @@ -695,22 +697,40 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { @CallSuper protected void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { - // Critical log level logs only visible elements to mitigate performance overheard - if (logLevel != WindowTraceLogLevel.ALL && !mHasOverrideConfiguration) { - return; + final long token = proto.start(fieldId); + + if (logLevel == WindowTraceLogLevel.ALL || mHasOverrideConfiguration) { + mRequestedOverrideConfiguration.dumpDebug(proto, OVERRIDE_CONFIGURATION, + logLevel == WindowTraceLogLevel.CRITICAL); } - final long token = proto.start(fieldId); - mRequestedOverrideConfiguration.dumpDebug(proto, OVERRIDE_CONFIGURATION, - logLevel == WindowTraceLogLevel.CRITICAL); + // Unless trace level is set to `WindowTraceLogLevel.ALL` don't dump anything that isn't + // required to mitigate performance overhead if (logLevel == WindowTraceLogLevel.ALL) { mFullConfiguration.dumpDebug(proto, FULL_CONFIGURATION, false /* critical */); mMergedOverrideConfiguration.dumpDebug(proto, MERGED_OVERRIDE_CONFIGURATION, false /* critical */); } + + if (logLevel == WindowTraceLogLevel.TRIM) { + // Required for Fass to automatically detect pip transitions in Winscope traces + dumpDebugWindowingMode(proto); + } + proto.end(token); } + private void dumpDebugWindowingMode(ProtoOutputStream proto) { + final long fullConfigToken = proto.start(FULL_CONFIGURATION); + final long windowConfigToken = proto.start(WINDOW_CONFIGURATION); + + int windowingMode = mFullConfiguration.windowConfiguration.getWindowingMode(); + proto.write(WINDOWING_MODE, windowingMode); + + proto.end(windowConfigToken); + proto.end(fullConfigToken); + } + /** * Dumps the names of this container children in the input print writer indenting each * level with the input prefix. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 594b6be489d6..3cb80d6e643e 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2972,11 +2972,6 @@ class Task extends TaskFragment { return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId); } - @Override - void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) { - super.resetSurfacePositionForAnimationLeash(t); - } - boolean shouldAnimate() { /** * Animations are handled by the TaskOrganizer implementation. diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 66f2dbc8ec09..71844ce02b20 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -99,13 +99,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { private int mColorLayerCounter = 0; /** - * A control placed at the appropriate level for transitions to occur. - */ - private SurfaceControl mAppAnimationLayer; - private SurfaceControl mBoostedAppAnimationLayer; - private SurfaceControl mHomeAppAnimationLayer; - - /** * Given that the split-screen divider does not have an AppWindowToken, it * will have to live inside of a "NonAppWindowContainer". However, in visual Z order * it will need to be interleaved with some of our children, appearing on top of @@ -132,7 +125,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { private final ArrayList<WindowContainer> mTmpNormalChildren = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpHomeChildren = new ArrayList<>(); private final IntArray mTmpNeedsZBoostIndexes = new IntArray(); - private int mTmpLayerForAnimationLayer; private ArrayList<Task> mTmpTasks = new ArrayList<>(); @@ -871,33 +863,13 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { int layer = 0; // Place root home tasks to the bottom. - layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer, false /* normalRootTasks */); - // The home animation layer is between the root home tasks and the normal root tasks. - final int layerForHomeAnimationLayer = layer++; - mTmpLayerForAnimationLayer = layer++; - layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer, true /* normalRootTasks */); - - // The boosted animation layer is between the normal root tasks and the always on top - // root tasks. - final int layerForBoostedAnimationLayer = layer++; - // Always on top tasks layer should higher than split divider layer so set it as start. - layer = SPLIT_DIVIDER_LAYER + 1; - adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer, false /* normalRootTasks */); + layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer); + adjustRootTaskLayer(t, mTmpNormalChildren, layer); - t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer); - t.setLayer(mAppAnimationLayer, mTmpLayerForAnimationLayer); + // Always on top tasks layer should higher than split divider layer so set it as start. t.setLayer(mSplitScreenDividerAnchor, SPLIT_DIVIDER_LAYER); - t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer); - } - - private int adjustNormalRootTaskLayer(WindowContainer child, int layer) { - if ((child.asTask() != null && child.asTask().isAnimatingByRecents()) - || child.isAppTransitioning()) { - // The animation layer is located above the highest animating root task and no - // higher. - mTmpLayerForAnimationLayer = layer++; - } - return layer; + layer = SPLIT_DIVIDER_LAYER + 1; + adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer); } /** @@ -906,11 +878,10 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { * normal rootTasks. * * @param startLayer The beginning layer of this group of rootTasks. - * @param normalRootTasks Set {@code true} if this group is neither home nor always on top. * @return The adjusted layer value. */ private int adjustRootTaskLayer(SurfaceControl.Transaction t, - ArrayList<WindowContainer> children, int startLayer, boolean normalRootTasks) { + ArrayList<WindowContainer> children, int startLayer) { mTmpNeedsZBoostIndexes.clear(); final int childCount = children.size(); for (int i = 0; i < childCount; i++) { @@ -923,9 +894,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { if (!childNeedsZBoost) { child.assignLayer(t, startLayer++); - if (normalRootTasks) { - startLayer = adjustNormalRootTaskLayer(child, startLayer); - } } else { mTmpNeedsZBoostIndexes.add(i); } @@ -935,9 +903,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { for (int i = 0; i < zBoostSize; i++) { final WindowContainer child = children.get(mTmpNeedsZBoostIndexes.get(i)); child.assignLayer(t, startLayer++); - if (normalRootTasks) { - startLayer = adjustNormalRootTaskLayer(child, startLayer); - } } return startLayer; } @@ -951,19 +916,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } @Override - SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) { - switch (animationLayer) { - case ANIMATION_LAYER_BOOSTED: - return mBoostedAppAnimationLayer; - case ANIMATION_LAYER_HOME: - return mHomeAppAnimationLayer; - case ANIMATION_LAYER_STANDARD: - default: - return mAppAnimationLayer; - } - } - - @Override RemoteAnimationTarget createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record) { final ActivityRecord activity = getTopMostActivity(); @@ -983,42 +935,21 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { .setName("colorBackgroundLayer") .setCallsite("TaskDisplayArea.onParentChanged") .build(); - mAppAnimationLayer = makeChildSurface(null) - .setName("animationLayer") - .setCallsite("TaskDisplayArea.onParentChanged") - .build(); - mBoostedAppAnimationLayer = makeChildSurface(null) - .setName("boostedAnimationLayer") - .setCallsite("TaskDisplayArea.onParentChanged") - .build(); - mHomeAppAnimationLayer = makeChildSurface(null) - .setName("homeAnimationLayer") - .setCallsite("TaskDisplayArea.onParentChanged") - .build(); mSplitScreenDividerAnchor = makeChildSurface(null) .setName("splitScreenDividerAnchor") .setCallsite("TaskDisplayArea.onParentChanged") .build(); getSyncTransaction() - .show(mAppAnimationLayer) - .show(mBoostedAppAnimationLayer) - .show(mHomeAppAnimationLayer) .show(mSplitScreenDividerAnchor); }); } else { super.onParentChanged(newParent, oldParent); mWmService.mTransactionFactory.get() .remove(mColorBackgroundLayer) - .remove(mAppAnimationLayer) - .remove(mBoostedAppAnimationLayer) - .remove(mHomeAppAnimationLayer) .remove(mSplitScreenDividerAnchor) .apply(); mColorBackgroundLayer = null; - mAppAnimationLayer = null; - mBoostedAppAnimationLayer = null; - mHomeAppAnimationLayer = null; mSplitScreenDividerAnchor = null; } } @@ -1059,15 +990,12 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { @Override void migrateToNewSurfaceControl(SurfaceControl.Transaction t) { super.migrateToNewSurfaceControl(t); - if (mAppAnimationLayer == null) { + if (mColorBackgroundLayer == null) { return; } // As TaskDisplayArea is getting a new surface, reparent and reorder the child surfaces. t.reparent(mColorBackgroundLayer, mSurfaceControl); - t.reparent(mAppAnimationLayer, mSurfaceControl); - t.reparent(mBoostedAppAnimationLayer, mSurfaceControl); - t.reparent(mHomeAppAnimationLayer, mSurfaceControl); t.reparent(mSplitScreenDividerAnchor, mSurfaceControl); reassignLayer(t); scheduleAnimation(); diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 44b22c643347..99f6f341e977 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1428,23 +1428,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { + "directly: %s", prev); didAutoPip = mAtmService.enterPictureInPictureMode(prev, prev.pictureInPictureArgs); - mPausingActivity = null; } else { - ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); - try { - EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), - prev.shortComponentName, "userLeaving=" + userLeaving, reason); - - mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), - prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, - prev.configChangeFlags, pauseImmediately)); - } catch (Exception e) { - // Ignore exception, if process died other code will cleanup. - Slog.w(TAG, "Exception thrown during pause", e); - mPausingActivity = null; - mLastPausedActivity = null; - mTaskSupervisor.mNoHistoryActivities.remove(prev); - } + schedulePauseActivity(prev, userLeaving, pauseImmediately, reason); } } else { mPausingActivity = null; @@ -1459,7 +1444,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { } // If already entered PIP mode, no need to keep pausing. - if (mPausingActivity != null && !didAutoPip) { + if (mPausingActivity != null) { // Have the window manager pause its key dispatching until the new // activity has started. If we're pausing the activity just because // the screen is being turned off and the UI is sleeping, don't interrupt @@ -1494,6 +1479,25 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } + void schedulePauseActivity(ActivityRecord prev, boolean userLeaving, + boolean pauseImmediately, String reason) { + ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev); + try { + EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev), + prev.shortComponentName, "userLeaving=" + userLeaving, reason); + + mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), + prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, + prev.configChangeFlags, pauseImmediately)); + } catch (Exception e) { + // Ignore exception, if process died other code will cleanup. + Slog.w(TAG, "Exception thrown during pause", e); + mPausingActivity = null; + mLastPausedActivity = null; + mTaskSupervisor.mNoHistoryActivities.remove(prev); + } + } + @VisibleForTesting void completePause(boolean resumeNext, ActivityRecord resuming) { // Complete the pausing process of a pausing activity, so it doesn't make sense to diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index 9cc24e2b2120..e31a6620187a 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -261,8 +261,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { if (launchMode == WINDOWING_MODE_PINNED) { if (DEBUG) appendLog("picture-in-picture"); } else if (!root.isResizeable()) { - if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea, - options.getLaunchWindowingMode())) { + if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea, options)) { launchMode = WINDOWING_MODE_FREEFORM; if (outParams.mBounds.isEmpty()) { getTaskBounds(root, suggestedDisplayArea, layout, launchMode, @@ -618,8 +617,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity, - TaskDisplayArea displayArea, int launchWindowingMode) { - if (launchWindowingMode == WINDOWING_MODE_FULLSCREEN) { + TaskDisplayArea displayArea, @Nullable ActivityOptions options) { + if (options != null && options.getLaunchWindowingMode() == WINDOWING_MODE_FULLSCREEN) { // Do not launch the activity in freeform if it explicitly requested fullscreen mode. return false; } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 841783d6b8cd..9a4bf6318249 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -57,6 +57,7 @@ import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER import static com.android.server.wm.WindowContainerProto.IDENTIFIER; import static com.android.server.wm.WindowContainerProto.ORIENTATION; import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR; +import static com.android.server.wm.WindowContainerProto.SURFACE_CONTROL; import static com.android.server.wm.WindowContainerProto.VISIBLE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -70,7 +71,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; -import android.app.WindowConfiguration; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -127,26 +127,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM; - /** Animation layer that happens above all animating {@link Task}s. */ - static final int ANIMATION_LAYER_STANDARD = 0; - - /** Animation layer that happens above all {@link Task}s. */ - static final int ANIMATION_LAYER_BOOSTED = 1; - - /** - * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME} - * activities and all activities that are being controlled by the recents animation. This - * layer is generally below all {@link Task}s. - */ - static final int ANIMATION_LAYER_HOME = 2; - - @IntDef(prefix = { "ANIMATION_LAYER_" }, value = { - ANIMATION_LAYER_STANDARD, - ANIMATION_LAYER_BOOSTED, - ANIMATION_LAYER_HOME, - }) - @interface AnimationLayer {} - static final int POSITION_TOP = Integer.MAX_VALUE; static final int POSITION_BOTTOM = Integer.MIN_VALUE; @@ -2429,6 +2409,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (mSurfaceAnimator.isAnimating()) { mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR); } + if (mSurfaceControl != null) { + mSurfaceControl.dumpDebug(proto, SURFACE_CONTROL); + } // add children to proto for (int i = 0; i < getChildCount(); i++) { @@ -2668,17 +2651,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return getParentSurfaceControl(); } - /** - * @return The layer on which all app animations are happening. - */ - SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) { - final WindowContainer parent = getParent(); - if (parent != null) { - return parent.getAppAnimationLayer(animationLayer); - } - return null; - } - // TODO: Remove this and use #getBounds() instead once we set an app transition animation // on TaskStack. Rect getAnimationBounds(int appRootTaskClipMode) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 14970ceb13d2..a3ff6da9782b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -10685,7 +10685,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return; + if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile() + || user.isGuest()) { + return; + } if (mInjector.userManagerIsHeadlessSystemUserMode()) { ComponentName admin = mOwners.getDeviceOwnerComponent(); diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java index 4a67ec71fcaa..8a8a6246b73b 100644 --- a/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java @@ -74,15 +74,20 @@ public class BatteryExternalStatsWorkerTest { @Test public void testTargetedEnergyConsumerQuerying() { final int numCpuClusters = 4; + final int numDisplays = 5; final int numOther = 3; // Add some energy consumers used by BatteryExternalStatsWorker. final IntArray tempAllIds = new IntArray(); - final int displayId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.DISPLAY, 0, - "display"); - tempAllIds.add(displayId); - mPowerStatsInternal.incrementEnergyConsumption(displayId, 12345); + final int[] displayIds = new int[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + displayIds[i] = mPowerStatsInternal.addEnergyConsumer( + EnergyConsumerType.DISPLAY, i, "display" + i); + tempAllIds.add(displayIds[i]); + mPowerStatsInternal.incrementEnergyConsumption(displayIds[i], 12345 + i); + } + Arrays.sort(displayIds); final int wifiId = mPowerStatsInternal.addEnergyConsumer(EnergyConsumerType.WIFI, 0, "wifi"); @@ -130,9 +135,13 @@ public class BatteryExternalStatsWorkerTest { final EnergyConsumerResult[] displayResults = mBatteryExternalStatsWorker.getMeasuredEnergyLocked(UPDATE_DISPLAY).getNow(null); - // Results should only have the display energy consumer - assertEquals(1, displayResults.length); - assertEquals(displayId, displayResults[0].id); + // Results should only have the cpu cluster energy consumers + final int[] receivedDisplayIds = new int[displayResults.length]; + for (int i = 0; i < displayResults.length; i++) { + receivedDisplayIds[i] = displayResults[i].id; + } + Arrays.sort(receivedDisplayIds); + assertArrayEquals(displayIds, receivedDisplayIds); final EnergyConsumerResult[] wifiResults = mBatteryExternalStatsWorker.getMeasuredEnergyLocked(UPDATE_WIFI).getNow(null); diff --git a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java index 8c87506295f3..a0cbcadee844 100644 --- a/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java +++ b/services/tests/servicestests/src/com/android/server/am/MeasuredEnergySnapshotTest.java @@ -16,8 +16,6 @@ package com.android.server.am; -import static com.android.server.am.MeasuredEnergySnapshot.UNAVAILABLE; - import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; @@ -120,7 +118,7 @@ public final class MeasuredEnergySnapshotTest { // results0 MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0); if (delta != null) { // null is fine here. If non-null, it better be uninteresting though. - assertEquals(UNAVAILABLE, delta.displayChargeUC); + assertNull(delta.displayChargeUC); assertNull(delta.otherTotalChargeUC); assertNull(delta.otherUidChargesUC); } @@ -130,7 +128,7 @@ public final class MeasuredEnergySnapshotTest { assertNotNull(delta); long expectedChargeUC; expectedChargeUC = calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1); - assertEquals(expectedChargeUC, delta.displayChargeUC); + assertEquals(expectedChargeUC, delta.displayChargeUC[0]); assertNotNull(delta.otherTotalChargeUC); @@ -149,14 +147,14 @@ public final class MeasuredEnergySnapshotTest { delta = snapshot.updateAndGetDelta(RESULTS_2, VOLTAGE_2); assertNotNull(delta); expectedChargeUC = calculateChargeConsumedUC(24_000, VOLTAGE_1, 36_000, VOLTAGE_2); - assertEquals(expectedChargeUC, delta.displayChargeUC); + assertEquals(expectedChargeUC, delta.displayChargeUC[0]); assertNull(delta.otherUidChargesUC); assertNull(delta.otherTotalChargeUC); // results3 delta = snapshot.updateAndGetDelta(RESULTS_3, VOLTAGE_3); assertNotNull(delta); - assertEquals(UNAVAILABLE, delta.displayChargeUC); + assertNull(delta.displayChargeUC); assertNotNull(delta.otherTotalChargeUC); @@ -183,7 +181,7 @@ public final class MeasuredEnergySnapshotTest { delta = snapshot.updateAndGetDelta(RESULTS_4, VOLTAGE_4); assertNotNull(delta); expectedChargeUC = calculateChargeConsumedUC(36_000, VOLTAGE_2, 43_000, VOLTAGE_4); - assertEquals(expectedChargeUC, delta.displayChargeUC); + assertEquals(expectedChargeUC, delta.displayChargeUC[0]); assertNotNull(delta.otherTotalChargeUC); expectedChargeUC = calculateChargeConsumedUC(190_000, VOLTAGE_3, 290_000, VOLTAGE_4); @@ -210,7 +208,7 @@ public final class MeasuredEnergySnapshotTest { // results0 MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0); if (delta != null) { // null is fine here. If non-null, it better be uninteresting though. - assertEquals(UNAVAILABLE, delta.displayChargeUC); + assertNull(delta.displayChargeUC); assertNull(delta.otherTotalChargeUC); assertNull(delta.otherUidChargesUC); } @@ -220,7 +218,7 @@ public final class MeasuredEnergySnapshotTest { assertNotNull(delta); final long expectedChargeUC = calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1); - assertEquals(expectedChargeUC, delta.displayChargeUC); + assertEquals(expectedChargeUC, delta.displayChargeUC[0]); assertNull(delta.otherTotalChargeUC); // Although in the results, they're not in the idMap assertNull(delta.otherUidChargesUC); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java index fd562c3f90b2..ebefeaff7f26 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java @@ -75,13 +75,19 @@ public class AppWindowTokenAnimationTests extends WindowTestsBase { @Test public void clipAfterAnim_boundsLayerZBoosted() { + final Task task = mActivity.getTask(); + final ActivityRecord topActivity = createActivityRecord(task); + task.assignChildLayers(mTransaction); + + assertThat(topActivity.getLastLayer()).isGreaterThan(mActivity.getLastLayer()); + mActivity.mNeedsAnimationBoundsLayer = true; mActivity.mNeedsZBoost = true; - mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */, ANIMATION_TYPE_APP_TRANSITION); + verify(mTransaction).setLayer(eq(mActivity.mAnimationBoundsLayer), - intThat(layer -> layer >= ActivityRecord.Z_BOOST_BASE)); + intThat(layer -> layer > topActivity.getLastLayer())); } @Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt index 2cc19438b927..562a0bd6a05d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -17,22 +17,29 @@ @file:JvmName("CommonAssertions") package com.android.server.wm.flicker -import android.content.ComponentName import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName -val LAUNCHER_COMPONENT = ComponentName("com.google.android.apps.nexuslauncher", +val LAUNCHER_COMPONENT = FlickerComponentName("com.google.android.apps.nexuslauncher", "com.google.android.apps.nexuslauncher.NexusLauncherActivity") +/** + * Checks that [FlickerComponentName.STATUS_BAR] window is visible and above the app windows in + * all WM trace entries + */ fun FlickerTestParameter.statusBarWindowIsVisible() { assertWm { - this.isAboveAppWindowVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT) + this.isAboveAppWindowVisible(FlickerComponentName.STATUS_BAR) } } +/** + * Checks that [FlickerComponentName.NAV_BAR] window is visible and above the app windows in + * all WM trace entries + */ fun FlickerTestParameter.navBarWindowIsVisible() { assertWm { - this.isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + this.isAboveAppWindowVisible(FlickerComponentName.NAV_BAR) } } @@ -69,21 +76,29 @@ fun FlickerTestParameter.entireScreenCovered(allStates: Boolean = true) { } } +/** + * Checks that [FlickerComponentName.NAV_BAR] layer is visible at the start and end of the SF + * trace + */ fun FlickerTestParameter.navBarLayerIsVisible() { assertLayersStart { - this.isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + this.isVisible(FlickerComponentName.NAV_BAR) } assertLayersEnd { - this.isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + this.isVisible(FlickerComponentName.NAV_BAR) } } +/** + * Checks that [FlickerComponentName.STATUS_BAR] layer is visible at the start and end of the SF + * trace + */ fun FlickerTestParameter.statusBarLayerIsVisible() { assertLayersStart { - this.isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT) + this.isVisible(FlickerComponentName.STATUS_BAR) } assertLayersEnd { - this.isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT) + this.isVisible(FlickerComponentName.STATUS_BAR) } } @@ -96,10 +111,10 @@ fun FlickerTestParameter.navBarLayerRotatesAndScales( val endingPos = WindowUtils.getNavigationBarPosition(endRotation) assertLayersStart { - this.visibleRegion(WindowManagerStateHelper.NAV_BAR_COMPONENT).coversExactly(startingPos) + this.visibleRegion(FlickerComponentName.NAV_BAR).coversExactly(startingPos) } assertLayersEnd { - this.visibleRegion(WindowManagerStateHelper.NAV_BAR_COMPONENT).coversExactly(endingPos) + this.visibleRegion(FlickerComponentName.NAV_BAR).coversExactly(endingPos) } } @@ -112,10 +127,10 @@ fun FlickerTestParameter.statusBarLayerRotatesScales( val endingPos = WindowUtils.getStatusBarPosition(endRotation) assertLayersStart { - this.visibleRegion(WindowManagerStateHelper.STATUS_BAR_COMPONENT).coversExactly(startingPos) + this.visibleRegion(FlickerComponentName.STATUS_BAR).coversExactly(startingPos) } assertLayersEnd { - this.visibleRegion(WindowManagerStateHelper.STATUS_BAR_COMPONENT).coversExactly(endingPos) + this.visibleRegion(FlickerComponentName.STATUS_BAR).coversExactly(endingPos) } } @@ -132,15 +147,15 @@ fun FlickerTestParameter.statusBarLayerRotatesScales( * (useful mostly for app launch) */ fun FlickerTestParameter.replacesLayer( - originalLayer: ComponentName, - newLayer: ComponentName, + originalLayer: FlickerComponentName, + newLayer: FlickerComponentName, ignoreSnapshot: Boolean = false ) { assertLayers { val assertion = this.isVisible(originalLayer) if (ignoreSnapshot) { assertion.then() - .isVisible(WindowManagerStateHelper.SNAPSHOT_COMPONENT, isOptional = true) + .isVisible(FlickerComponentName.SNAPSHOT, isOptional = true) } assertion.then().isVisible(newLayer) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt index 90c851d6e266..9b34853092a2 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt @@ -23,7 +23,7 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import org.junit.FixMethodOrder import org.junit.Test @@ -33,13 +33,38 @@ import org.junit.runners.Parameterized /** * Test app closes by pressing back button + * * To run this test: `atest FlickerTests:CloseAppBackButtonTest` + * + * Actions: + * Make sure no apps are running on the device + * Launch an app [testApp] and wait animation to complete + * Press back button + * + * To run only the presubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit` + * + * To run only the postsubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit` + * + * To run only the flaky assertions add: `-- + * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest` + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [CloseAppTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) { override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = { @@ -50,14 +75,23 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio } } + /** {@inheritDoc} */ @FlakyTest @Test override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() + /** {@inheritDoc} */ @Postsubmit + @Test override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): List<FlickerTestParameter> { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt index e8391ed9cfa1..e38079490618 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt @@ -22,7 +22,7 @@ import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import org.junit.FixMethodOrder import org.junit.Test @@ -31,14 +31,39 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Test app closes by pressing home button. + * Test app closes by pressing home button + * * To run this test: `atest FlickerTests:CloseAppHomeButtonTest` + * + * Actions: + * Make sure no apps are running on the device + * Launch an app [testApp] and wait animation to complete + * Press home button + * + * To run only the presubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit` + * + * To run only the postsubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit` + * + * To run only the flaky assertions add: `-- + * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest` + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [CloseAppTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) { override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit get() = { @@ -49,14 +74,23 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio } } + /** {@inheritDoc} */ @FlakyTest @Test override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() + /** {@inheritDoc} */ @Postsubmit + @Test override fun navBarLayerIsVisible() = super.navBarLayerIsVisible() companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt index 1efb6daae31b..04826191d8ad 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt @@ -62,6 +62,10 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Entry point for the test runner. It will use this method to initialize and cache + * flicker executions + */ @FlickerBuilderProvider fun buildFlicker(): FlickerBuilder { return FlickerBuilder(instrumentation).apply { @@ -69,42 +73,64 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that the navigation bar window is visible during the whole transition + */ @Presubmit @Test open fun navBarWindowIsVisible() { testSpec.navBarWindowIsVisible() } + /** + * Checks that the status bar window is visible during the whole transition + */ @Presubmit @Test open fun statusBarWindowIsVisible() { testSpec.statusBarWindowIsVisible() } + /** + * Checks that the navigation bar layer is visible during the whole transition + */ @Presubmit @Test open fun navBarLayerIsVisible() { testSpec.navBarLayerIsVisible() } + /** + * Checks that the status bar layer is visible during the whole transition + */ @Presubmit @Test open fun statusBarLayerIsVisible() { testSpec.statusBarLayerIsVisible() } + /** + * Checks the position of the navigation bar at the start and end of the transition + */ @Presubmit @Test open fun navBarLayerRotatesAndScales() { testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0) } + /** + * Checks the position of the status bar at the start and end of the transition + */ @Presubmit @Test open fun statusBarLayerRotatesScales() { testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation, Surface.ROTATION_0) } + /** + * Checks that all windows that are visible on the trace, are visible for at least 2 + * consecutive entries. + */ @Presubmit @Test open fun visibleWindowsShownMoreThanOneConsecutiveEntry() { @@ -113,6 +139,10 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that all layers that are visible on the trace, are visible for at least 2 + * consecutive entries. + */ @Presubmit @Test open fun visibleLayersShownMoreThanOneConsecutiveEntry() { @@ -121,10 +151,17 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that all parts of the screen are covered during the transition + */ @Presubmit @Test open fun entireScreenCovered() = testSpec.entireScreenCovered() + /** + * Checks that [testApp] is the top visible app window at the start of the transition and + * that it is replaced by [LAUNCHER_COMPONENT] during the transition + */ @Presubmit @Test open fun launcherReplacesAppWindowAsTopWindow() { @@ -135,19 +172,26 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that [LAUNCHER_COMPONENT] is invisible at the start of the transition and that + * it becomes visible during the transition + */ @Presubmit @Test open fun launcherWindowBecomesVisible() { testSpec.assertWm { - this.isAppWindowInvisible(LAUNCHER_COMPONENT) + this.isAppWindowNotOnTop(LAUNCHER_COMPONENT) .then() .isAppWindowOnTop(LAUNCHER_COMPONENT) } } + /** + * Checks that [LAUNCHER_COMPONENT] layer becomes visible when [testApp] becomes invisible + */ @Presubmit @Test open fun launcherLayerReplacesApp() { testSpec.replacesLayer(testApp.component, LAUNCHER_COMPONENT) } -} +}
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt index fad25b4fa0b9..75900df978df 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt @@ -14,6 +14,7 @@ * limitations under the License. */ +@file:JvmName("FlickerExtensions") package com.android.server.wm.flicker.helpers import com.android.server.wm.flicker.Flicker diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt index bd7c1855fea9..0b1748a6bda4 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt @@ -17,9 +17,10 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import androidx.test.uiautomator.UiDevice import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper class ImeAppAutoFocusHelper @JvmOverloads constructor( @@ -27,7 +28,8 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor( private val rotation: Int, private val imePackageName: String = IME_PACKAGE, launcherName: String = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_LAUNCHER_NAME, - component: ComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME + component: FlickerComponentName = + ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent() ) : ImeAppHelper(instr, launcherName, component) { override fun openIME( device: UiDevice, diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt index d224af97462e..1c2164a70a55 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt @@ -17,19 +17,21 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper open class ImeAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.IME_ACTIVITY_LAUNCHER_NAME, - component: ComponentName = ActivityOptions.IME_ACTIVITY_COMPONENT_NAME, + component: FlickerComponentName = + ActivityOptions.IME_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt index 3074e28b43fa..f7ca5ce1c001 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt @@ -17,15 +17,17 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent class NonResizeableAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME, - component: ComponentName = ActivityOptions.NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME, + component: FlickerComponentName = + ActivityOptions.NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt index 02be3cf0a8a3..7bab981ce231 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt @@ -17,15 +17,17 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent class SeamlessRotationAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.SEAMLESS_ACTIVITY_LAUNCHER_NAME, - component: ComponentName = ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME, + component: FlickerComponentName = + ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt index d7cbaaee2627..f6a8817e5b08 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt @@ -17,15 +17,17 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent class SimpleAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.SIMPLE_ACTIVITY_LAUNCHER_NAME, - component: ComponentName = ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME, + component: FlickerComponentName = + ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt index 19fefb93b487..59e8dc826007 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt @@ -17,19 +17,21 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.content.ComponentName import android.support.test.launcherhelper.ILauncherStrategy import android.support.test.launcherhelper.LauncherStrategyFactory import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.traces.common.FlickerComponentName +import com.android.server.wm.traces.parser.toFlickerComponent import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper class TwoActivitiesAppHelper @JvmOverloads constructor( instr: Instrumentation, launcherName: String = ActivityOptions.BUTTON_ACTIVITY_LAUNCHER_NAME, - component: ComponentName = ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME, + component: FlickerComponentName = + ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME.toFlickerComponent(), launcherStrategy: ILauncherStrategy = LauncherStrategyFactory .getInstance(instr) .launcherStrategy diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt index d17e77d74c1c..35505367ce21 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt @@ -37,7 +37,7 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -125,7 +125,7 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter @Test fun imeLayerVisibleStart() { testSpec.assertLayersStart { - this.isVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isVisible(FlickerComponentName.IME) } } @@ -133,7 +133,7 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter @Test fun imeLayerInvisibleEnd() { testSpec.assertLayersEnd { - this.isInvisible(WindowManagerStateHelper.IME_COMPONENT) + this.isInvisible(FlickerComponentName.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt index 6f0f55aa4888..f7f325ec7e22 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt @@ -38,7 +38,7 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -110,7 +110,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete testSpec.assertWm { this.isAppWindowOnTop(testApp.component) .then() - .appWindowNotOnTop(testApp.component) + .isAppWindowNotOnTop(testApp.component) } } @@ -122,7 +122,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete @Test fun imeLayerVisibleStart() { testSpec.assertLayersStart { - this.isVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isVisible(FlickerComponentName.IME) } } @@ -130,7 +130,7 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete @Test fun imeLayerInvisibleEnd() { testSpec.assertLayersEnd { - this.isInvisible(WindowManagerStateHelper.IME_COMPONENT) + this.isInvisible(FlickerComponentName.IME) } } @@ -173,8 +173,8 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete fun visibleLayersShownMoreThanOneConsecutiveEntry() { testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry(listOf( - WindowManagerStateHelper.IME_COMPONENT, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT)) + FlickerComponentName.IME, + FlickerComponentName.SPLASH_SCREEN)) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt index 6751439709bf..11660dfe43fc 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt @@ -35,8 +35,8 @@ import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.Assume -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -91,9 +91,9 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) { fun visibleWindowsShownMoreThanOneConsecutiveEntry() { testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf( - WindowManagerStateHelper.IME_COMPONENT, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT)) + FlickerComponentName.IME, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT)) } } @@ -165,4 +165,4 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) { .getConfigNonRotationTests(repetitions = 5) } } -} +}
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt index 8aaf9251018f..bb2ffbc372d0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt @@ -37,7 +37,7 @@ import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -95,9 +95,9 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) { fun visibleWindowsShownMoreThanOneConsecutiveEntry() { testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf( - WindowManagerStateHelper.IME_COMPONENT, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT)) + FlickerComponentName.IME, + FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT)) } } @@ -157,8 +157,8 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) { fun visibleLayersShownMoreThanOneConsecutiveEntry() { testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry(listOf( - WindowManagerStateHelper.IME_COMPONENT, - WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT)) + FlickerComponentName.IME, + FlickerComponentName.SPLASH_SCREEN)) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt index 7659d9471e2f..ba78e25580ec 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt @@ -18,52 +18,52 @@ package com.android.server.wm.flicker.ime import com.android.server.wm.flicker.FlickerTestParameter -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName fun FlickerTestParameter.imeLayerBecomesVisible() { assertLayers { - this.isInvisible(WindowManagerStateHelper.IME_COMPONENT) + this.isInvisible(FlickerComponentName.IME) .then() - .isVisible(WindowManagerStateHelper.IME_COMPONENT) + .isVisible(FlickerComponentName.IME) } } fun FlickerTestParameter.imeLayerBecomesInvisible() { assertLayers { - this.isVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isVisible(FlickerComponentName.IME) .then() - .isInvisible(WindowManagerStateHelper.IME_COMPONENT) + .isInvisible(FlickerComponentName.IME) } } fun FlickerTestParameter.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) { if (rotatesScreen) { assertWm { - this.isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isNonAppWindowVisible(FlickerComponentName.IME) .then() - .isNonAppWindowInvisible(WindowManagerStateHelper.IME_COMPONENT) + .isNonAppWindowInvisible(FlickerComponentName.IME) .then() - .isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT) + .isNonAppWindowVisible(FlickerComponentName.IME) } } else { assertWm { - this.isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isNonAppWindowVisible(FlickerComponentName.IME) } } } fun FlickerTestParameter.imeWindowBecomesVisible() { assertWm { - this.isNonAppWindowInvisible(WindowManagerStateHelper.IME_COMPONENT) + this.isNonAppWindowInvisible(FlickerComponentName.IME) .then() - .isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT) + .isNonAppWindowVisible(FlickerComponentName.IME) } } fun FlickerTestParameter.imeWindowBecomesInvisible() { assertWm { - this.isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isNonAppWindowVisible(FlickerComponentName.IME) .then() - .isNonAppWindowInvisible(WindowManagerStateHelper.IME_COMPONENT) + .isNonAppWindowInvisible(FlickerComponentName.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt index 665204bc9e1e..44a27b1278c8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt @@ -20,6 +20,7 @@ import android.app.Instrumentation import android.platform.test.annotations.Presubmit import android.view.Surface import android.view.WindowManagerPolicyConstants +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerBuilderProvider @@ -142,7 +143,7 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) { } } - @Presubmit + @FlakyTest @Test fun visibleWindowsShownMoreThanOneConsecutiveEntry() { testSpec.assertWm { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt index b37c40447934..7a017039534a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt @@ -17,7 +17,6 @@ package com.android.server.wm.flicker.ime import android.app.Instrumentation -import android.content.ComponentName import android.os.SystemProperties import android.platform.test.annotations.Presubmit import android.view.Surface @@ -43,7 +42,7 @@ import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.Assume import org.junit.FixMethodOrder import org.junit.Test @@ -104,12 +103,12 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { @Presubmit @Test fun visibleWindowsShownMoreThanOneConsecutiveEntry() { - val component = ComponentName("", "RecentTaskScreenshotSurface") + val component = FlickerComponentName("", "RecentTaskScreenshotSurface") testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry( - ignoreWindows = listOf(WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT, - component) + ignoreWindows = listOf(FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, + component) ) } } @@ -138,9 +137,9 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { // Since we log 1x per frame, sometimes the activity visibility and the app visibility // are updated together, sometimes not, thus ignore activity check at the start testSpec.assertWm { - this.isAppWindowVisible(testApp.component, ignoreActivity = true) + this.isAppWindowVisible(testApp.component) .then() - .isAppWindowInvisible(testApp.component, ignoreActivity = true) + .isAppWindowInvisible(testApp.component) .then() .isAppWindowVisible(testApp.component) } @@ -155,7 +154,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { // and the app visibility are updated together, sometimes not, thus ignore activity // check at the start testSpec.assertWm { - this.isAppWindowVisible(testApp.component, ignoreActivity = true) + this.isAppWindowVisible(testApp.component) } } @@ -177,11 +176,11 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { fun imeLayerIsBecomesVisibleLegacy() { Assume.assumeFalse(isShellTransitionsEnabled) testSpec.assertLayers { - this.isVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isVisible(FlickerComponentName.IME) .then() - .isInvisible(WindowManagerStateHelper.IME_COMPONENT) + .isInvisible(FlickerComponentName.IME) .then() - .isVisible(WindowManagerStateHelper.IME_COMPONENT) + .isVisible(FlickerComponentName.IME) } } @@ -190,7 +189,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { fun imeLayerIsBecomesVisible() { Assume.assumeTrue(isShellTransitionsEnabled) testSpec.assertLayers { - this.isVisible(WindowManagerStateHelper.IME_COMPONENT) + this.isVisible(FlickerComponentName.IME) } } @@ -200,7 +199,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { testSpec.assertLayers { this.isVisible(LAUNCHER_COMPONENT) .then() - .isVisible(WindowManagerStateHelper.SNAPSHOT_COMPONENT, isOptional = true) + .isVisible(FlickerComponentName.SNAPSHOT, isOptional = true) .then() .isVisible(testApp.component) } @@ -223,11 +222,11 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) { fun visibleLayersShownMoreThanOneConsecutiveEntry() { // depends on how much of the animation transactions are sent to SF at once // sometimes this layer appears for 2-3 frames, sometimes for only 1 - val recentTaskComponent = ComponentName("", "RecentTaskScreenshotSurface") + val recentTaskComponent = FlickerComponentName("", "RecentTaskScreenshotSurface") testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry( - listOf(WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT, recentTaskComponent) + listOf(FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, recentTaskComponent) ) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt index f9dd88e8cb29..4c506b0fea4d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt @@ -17,7 +17,6 @@ package com.android.server.wm.flicker.ime import android.app.Instrumentation -import android.content.ComponentName import android.platform.test.annotations.Presubmit import android.view.Surface import android.view.WindowManagerPolicyConstants @@ -28,7 +27,7 @@ import com.android.server.wm.flicker.FlickerBuilderProvider import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory -import com.android.server.wm.flicker.annotation.Group2 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.WindowUtils @@ -36,7 +35,7 @@ import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test @@ -52,7 +51,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group2 +@Group4 @Presubmit class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) { private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() @@ -107,51 +106,52 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame @Test fun imeAppWindowVisibility() { - val component = ComponentName(imeTestApp.`package`, "") testSpec.assertWm { - this.isAppWindowOnTop(component) - .then() - .isAppWindowVisible(component, ignoreActivity = true) + isAppWindowVisible(imeTestApp.component) + .then() + .isAppWindowVisible(testApp.component) + .then() + .isAppWindowVisible(imeTestApp.component) } } @Test fun navBarLayerIsVisibleAroundSwitching() { testSpec.assertLayersStart { - isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + isVisible(FlickerComponentName.NAV_BAR) } testSpec.assertLayersEnd { - isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + isVisible(FlickerComponentName.NAV_BAR) } } @Test fun statusBarLayerIsVisibleAroundSwitching() { testSpec.assertLayersStart { - isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT) + isVisible(FlickerComponentName.STATUS_BAR) } testSpec.assertLayersEnd { - isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT) + isVisible(FlickerComponentName.STATUS_BAR) } } @Test fun imeLayerIsVisibleWhenSwitchingToImeApp() { testSpec.assertLayersStart { - isVisible(WindowManagerStateHelper.IME_COMPONENT) + isVisible(FlickerComponentName.IME) } testSpec.assertLayersTag(TAG_IME_VISIBLE) { - isVisible(WindowManagerStateHelper.IME_COMPONENT) + isVisible(FlickerComponentName.IME) } testSpec.assertLayersEnd { - isVisible(WindowManagerStateHelper.IME_COMPONENT) + isVisible(FlickerComponentName.IME) } } @Test fun imeLayerIsInvisibleWhenSwitchingToTestApp() { testSpec.assertLayersTag(TAG_IME_INVISIBLE) { - isInvisible(WindowManagerStateHelper.IME_COMPONENT) + isInvisible(FlickerComponentName.IME) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt index 42c252e70eea..f74a7718461f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt @@ -27,10 +27,11 @@ import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.LAUNCHER_COMPONENT import com.android.server.wm.flicker.repetitions -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.server.wm.traces.parser.toFlickerComponent import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -39,17 +40,33 @@ import org.junit.runners.Parameterized /** * Test the back and forward transition between 2 activities. + * * To run this test: `atest FlickerTests:ActivitiesTransitionTest` + * + * Actions: + * Launch an app + * Launch a secondary activity within the app + * Close the secondary activity back to the initial one + * + * Notes: + * 1. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) { val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation) + /** + * Entry point for the test runner. It will use this method to initialize and cache + * flicker executions + */ @FlickerBuilderProvider fun buildFlicker(): FlickerBuilder { return FlickerBuilder(instrumentation).apply { @@ -75,30 +92,52 @@ class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) { } } + /** + * Checks that the [ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME] activity is visible at + * the start of the transition, that + * [ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME] becomes visible during the + * transition, and that [ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME] is again visible + * at the end + */ @Presubmit @Test fun finishSubActivity() { + val buttonActivityComponent = ActivityOptions + .BUTTON_ACTIVITY_COMPONENT_NAME.toFlickerComponent() + val imeAutoFocusActivityComponent = ActivityOptions + .SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent() testSpec.assertWm { - this.isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME) - .then() - .isAppWindowOnTop(ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME) - .then() - .isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME) + this.isAppWindowOnTop(buttonActivityComponent) + .then() + .isAppWindowOnTop(imeAutoFocusActivityComponent) + .then() + .isAppWindowOnTop(buttonActivityComponent) } } + /** + * Checks that all parts of the screen are covered during the transition + */ @Presubmit @Test fun entireScreenCovered() = testSpec.entireScreenCovered() + /** + * Checks that the [LAUNCHER_COMPONENT] window is not on top. The launcher cannot be + * asserted with `isAppWindowVisible` because it contains 2 windows with the exact same name, + * and both are never simultaneously visible + */ @Presubmit @Test - fun launcherWindowNotVisible() { + fun launcherWindowNotOnTop() { testSpec.assertWm { - this.isAppWindowInvisible(LAUNCHER_COMPONENT, ignoreActivity = true) + this.isAppWindowNotOnTop(LAUNCHER_COMPONENT) } } + /** + * Checks that the [LAUNCHER_COMPONENT] layer is never visible during the transition + */ @Presubmit @Test fun launcherLayerNotVisible() { @@ -106,6 +145,12 @@ class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) { } companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt index b7176122095b..1bdc23547bef 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt @@ -16,7 +16,6 @@ package com.android.server.wm.flicker.launch -import android.content.ComponentName import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.view.Surface @@ -29,7 +28,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.annotation.Group1 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import com.google.common.truth.Truth import org.junit.FixMethodOrder import org.junit.Test @@ -61,7 +60,7 @@ import org.junit.runners.Parameterized @Group1 class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) { override val testApp = NonResizeableAppHelper(instrumentation) - private val colorFadComponent = ComponentName("", "ColorFade BLAST#") + private val colorFadComponent = FlickerComponentName("", "ColorFade BLAST#") /** * Defines the transition used to run the test @@ -92,15 +91,15 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti * Checks that the nav bar layer starts visible, becomes invisible during unlocking animation * and becomes visible at the end */ - @Presubmit + @Postsubmit @Test fun navBarLayerVisibilityChanges() { testSpec.assertLayers { - this.isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + this.isVisible(FlickerComponentName.NAV_BAR) .then() - .isInvisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + .isInvisible(FlickerComponentName.NAV_BAR) .then() - .isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + .isVisible(FlickerComponentName.NAV_BAR) } } @@ -133,10 +132,9 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti testSpec.assertWm { this.notContains(testApp.component) .then() - .isAppWindowInvisible(testApp.component, - ignoreActivity = true, isOptional = true) + .isAppWindowInvisible(testApp.component, isOptional = true) .then() - .isAppWindowVisible(testApp.component, ignoreActivity = true) + .isAppWindowVisible(testApp.component) } } @@ -147,7 +145,7 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti @Test fun appWindowBecomesVisibleAtEnd() { testSpec.assertWmEnd { - this.isVisible(testApp.component) + this.isAppWindowVisible(testApp.component) } } @@ -159,11 +157,11 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti @Test fun navBarWindowsVisibilityChanges() { testSpec.assertWm { - this.isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + this.isAboveAppWindowVisible(FlickerComponentName.NAV_BAR) .then() - .isNonAppWindowInvisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + .isNonAppWindowInvisible(FlickerComponentName.NAV_BAR) .then() - .isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT) + .isAboveAppWindowVisible(FlickerComponentName.NAV_BAR) } } @@ -173,6 +171,10 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = super.visibleWindowsShownMoreThanOneConsecutiveEntry() + @FlakyTest + @Test + override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() + /** {@inheritDoc} */ @FlakyTest @Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt index 14d17f82b805..419d3e88983b 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt @@ -39,10 +39,12 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SPLASH_SCREEN_COMPONENT +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.Test +/** + * Base class for app launch tests + */ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) { protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation) @@ -85,7 +87,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) { } /** - * Checks that the navigation bar layer is visible during the whole transition + * Checks that the navigation bar layer is visible at the start and end of the trace */ open fun navBarLayerIsVisible() { testSpec.navBarLayerIsVisible() @@ -110,7 +112,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) { } /** - * Checks that the status bar layer is visible during the whole transition + * Checks that the status bar layer is visible at the start and end of the trace */ @Presubmit @Test @@ -188,9 +190,9 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) { testSpec.assertWm { this.isAppWindowOnTop(LAUNCHER_COMPONENT) .then() - .isAppWindowOnTop(SNAPSHOT_COMPONENT, isOptional = true) + .isAppWindowOnTop(FlickerComponentName.SNAPSHOT, isOptional = true) .then() - .isAppWindowOnTop(SPLASH_SCREEN_COMPONENT, isOptional = true) + .isAppWindowOnTop(FlickerComponentName.SPLASH_SCREEN, isOptional = true) .then() .isAppWindowOnTop(testApp.component) } @@ -202,9 +204,9 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) { */ open fun launcherWindowBecomesInvisible() { testSpec.assertWm { - this.isAppWindowVisible(LAUNCHER_COMPONENT) + this.isAppWindowOnTop(LAUNCHER_COMPONENT) .then() - .isAppWindowInvisible(LAUNCHER_COMPONENT) + .isAppWindowNotOnTop(LAUNCHER_COMPONENT) } } }
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index 035aac1c5e86..cdab6818e209 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -39,7 +39,7 @@ import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -189,9 +189,9 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet testSpec.assertWm { this.isAppWindowInvisible(testApp1.component) .then() - .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true) + .isAppWindowVisible(FlickerComponentName.SNAPSHOT, isOptional = true) .then() - .isAppWindowVisible(testApp1.component, ignoreActivity = true) + .isAppWindowVisible(testApp1.component) } } @@ -217,7 +217,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet @Test fun app2WindowBecomesAndStaysInvisible() { testSpec.assertWm { - this.isAppWindowVisible(testApp2.component, ignoreActivity = true) + this.isAppWindowVisible(testApp2.component) .then() .isAppWindowInvisible(testApp2.component) } @@ -251,7 +251,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet // TODO: Do we actually want to test this? Seems too implementation specific... .isAppWindowVisible(LAUNCHER_COMPONENT, isOptional = true) .then() - .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true) + .isAppWindowVisible(FlickerComponentName.SNAPSHOT, isOptional = true) .then() .isAppWindowVisible(testApp1.component) } @@ -270,7 +270,7 @@ class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParamet .then() .isVisible(LAUNCHER_COMPONENT, isOptional = true) .then() - .isVisible(SNAPSHOT_COMPONENT, isOptional = true) + .isVisible(FlickerComponentName.SNAPSHOT, isOptional = true) .then() .isVisible(testApp1.component) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt new file mode 100644 index 000000000000..d1a3fe43b6da --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm.flicker.quickswitch + +import android.app.Instrumentation +import android.platform.test.annotations.Postsubmit +import android.platform.test.annotations.RequiresDevice +import android.view.Surface +import android.view.WindowManagerPolicyConstants +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerBuilderProvider +import com.android.server.wm.flicker.FlickerParametersRunnerFactory +import com.android.server.wm.flicker.FlickerTestParameter +import com.android.server.wm.flicker.FlickerTestParameterFactory +import com.android.server.wm.flicker.LAUNCHER_COMPONENT +import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.helpers.NonResizeableAppHelper +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.helpers.isRotated +import com.android.server.wm.flicker.navBarLayerIsVisible +import com.android.server.wm.flicker.navBarLayerRotatesAndScales +import com.android.server.wm.flicker.navBarWindowIsVisible +import com.android.server.wm.flicker.repetitions +import com.android.server.wm.flicker.startRotation +import com.android.server.wm.flicker.statusBarLayerIsVisible +import com.android.server.wm.flicker.statusBarWindowIsVisible +import com.android.server.wm.traces.common.FlickerComponentName +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test quick switching back to previous app from last opened app + * + * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest` + * + * Actions: + * Launch an app [testApp1] + * Launch another app [testApp2] + * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1] + * Swipe left from the bottom of the screen to quick switch forward to the second app [testApp2] + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Group1 +class QuickSwitchBetweenTwoAppsForwardTest(private val testSpec: FlickerTestParameter) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + + private val testApp1 = SimpleAppHelper(instrumentation) + private val testApp2 = NonResizeableAppHelper(instrumentation) + + private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation) + + @FlickerBuilderProvider + fun buildFlicker(): FlickerBuilder { + return FlickerBuilder(instrumentation).apply { + withTestName { testSpec.name } + repeat { testSpec.config.repetitions } + setup { + eachRun { + testApp1.launchViaIntent(wmHelper) + wmHelper.waitForFullScreenApp(testApp1.component) + + testApp2.launchViaIntent(wmHelper) + wmHelper.waitForFullScreenApp(testApp2.component) + + // Swipe right from bottom to quick switch back + // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle + // as to not accidentally trigger a swipe back or forward action which would result + // in the same behavior but not testing quick swap. + device.swipe( + startDisplayBounds.bounds.right / 3, + startDisplayBounds.bounds.bottom, + 2 * startDisplayBounds.bounds.right / 3, + startDisplayBounds.bounds.bottom, + if (testSpec.config.startRotation.isRotated()) 75 else 30 + ) + + wmHelper.waitForFullScreenApp(testApp1.component) + wmHelper.waitForAppTransitionIdle() + } + } + transitions { + // Swipe left from bottom to quick switch forward + // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle + // as to not accidentally trigger a swipe back or forward action which would result + // in the same behavior but not testing quick swap. + device.swipe( + 2 * startDisplayBounds.bounds.right / 3, + startDisplayBounds.bounds.bottom, + startDisplayBounds.bounds.right / 3, + startDisplayBounds.bounds.bottom, + if (testSpec.config.startRotation.isRotated()) 75 else 30 + ) + + wmHelper.waitForFullScreenApp(testApp2.component) + wmHelper.waitForAppTransitionIdle() + } + + teardown { + test { + testApp1.exit() + testApp2.exit() + } + } + } + } + + /** + * Checks that the transition starts with [testApp1]'s windows filling/covering exactly the + * entirety of the display. + */ + @Postsubmit + @Test + fun startsWithApp1WindowsCoverFullScreen() { + testSpec.assertWmStart { + this.frameRegion(testApp1.component).coversExactly(startDisplayBounds) + } + } + + /** + * Checks that the transition starts with [testApp1]'s layers filling/covering exactly the + * entirety of the display. + */ + @Postsubmit + @Test + fun startsWithApp1LayersCoverFullScreen() { + testSpec.assertLayersStart { + this.visibleRegion(testApp1.component).coversExactly(startDisplayBounds) + } + } + + /** + * Checks that the transition starts with [testApp1] being the top window. + */ + @Postsubmit + @Test + fun startsWithApp1WindowBeingOnTop() { + testSpec.assertWmStart { + this.isAppWindowOnTop(testApp1.component) + } + } + + /** + * Checks that [testApp2] windows fill the entire screen (i.e. is "fullscreen") at the end of the + * transition once we have fully quick switched from [testApp1] back to the [testApp2]. + */ + @Postsubmit + @Test + fun endsWithApp2WindowsCoveringFullScreen() { + testSpec.assertWmEnd { + this.frameRegion(testApp2.component).coversExactly(startDisplayBounds) + } + } + + /** + * Checks that [testApp2] layers fill the entire screen (i.e. is "fullscreen") at the end of the + * transition once we have fully quick switched from [testApp1] back to the [testApp2]. + */ + @Postsubmit + @Test + fun endsWithApp2LayersCoveringFullScreen() { + testSpec.assertLayersEnd { + this.visibleRegion(testApp2.component).coversExactly(startDisplayBounds) + } + } + + /** + * Checks that [testApp2] is the top window at the end of the transition once we have fully quick + * switched from [testApp1] back to the [testApp2]. + */ + @Postsubmit + @Test + fun endsWithApp2BeingOnTop() { + testSpec.assertWmEnd { + this.isAppWindowOnTop(testApp2.component) + } + } + + /** + * Checks that [testApp2]'s window starts off invisible and becomes visible at some point before + * the end of the transition and then stays visible until the end of the transition. + */ + @Postsubmit + @Test + fun app2WindowBecomesAndStaysVisible() { + testSpec.assertWm { + this.isAppWindowInvisible(testApp2.component) + .then() + .isAppWindowVisible(FlickerComponentName.SNAPSHOT, isOptional = true) + .then() + .isAppWindowVisible(testApp2.component) + } + } + + /** + * Checks that [testApp2]'s layer starts off invisible and becomes visible at some point before + * the end of the transition and then stays visible until the end of the transition. + */ + @Postsubmit + @Test + fun app2LayerBecomesAndStaysVisible() { + testSpec.assertLayers { + this.isInvisible(testApp2.component) + .then() + .isVisible(testApp2.component) + } + } + + /** + * Checks that [testApp1]'s window starts off visible and becomes invisible at some point before + * the end of the transition and then stays invisible until the end of the transition. + */ + @Postsubmit + @Test + fun app1WindowBecomesAndStaysInvisible() { + testSpec.assertWm { + this.isAppWindowVisible(testApp1.component) + .then() + .isAppWindowInvisible(testApp1.component) + } + } + + /** + * Checks that [testApp1]'s layer starts off visible and becomes invisible at some point before + * the end of the transition and then stays invisible until the end of the transition. + */ + @Postsubmit + @Test + fun app1LayerBecomesAndStaysInvisible() { + testSpec.assertLayers { + this.isVisible(testApp1.component) + .then() + .isInvisible(testApp1.component) + } + } + + /** + * Checks that [testApp1]'s window is visible at least until [testApp2]'s window is visible. + * Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially + * visible. + */ + @Postsubmit + @Test + fun app2WindowIsVisibleOnceApp1WindowIsInvisible() { + testSpec.assertWm { + this.isAppWindowVisible(testApp1.component) + .then() + .isAppWindowVisible(LAUNCHER_COMPONENT, isOptional = true) + .then() + .isAppWindowVisible(FlickerComponentName.SNAPSHOT, isOptional = true) + .then() + .isAppWindowVisible(testApp2.component) + } + } + + /** + * Checks that [testApp1]'s layer is visible at least until [testApp2]'s window is visible. + * Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially + * visible. + */ + @Postsubmit + @Test + fun app2LayerIsVisibleOnceApp1LayerIsInvisible() { + testSpec.assertLayers { + this.isVisible(testApp1.component) + .then() + .isVisible(LAUNCHER_COMPONENT, isOptional = true) + .then() + .isVisible(FlickerComponentName.SNAPSHOT, isOptional = true) + .then() + .isVisible(testApp2.component) + } + } + + /** + * Checks that the navbar window is visible throughout the entire transition. + */ + @Postsubmit + @Test + fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible() + + /** + * Checks that the navbar layer is visible throughout the entire transition. + */ + @Postsubmit + @Test + fun navBarLayerAlwaysIsVisible() = testSpec.navBarLayerIsVisible() + + /** + * Checks that the navbar is always in the right position and covers the expected region. + * + * NOTE: This doesn't check that the navbar is visible or not. + */ + @Postsubmit + @Test + fun navbarIsAlwaysInRightPosition() = + testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation) + + /** + * Checks that the status bar window is visible throughout the entire transition. + */ + @Postsubmit + @Test + fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible() + + /** + * Checks that the status bar layer is visible throughout the entire transition. + */ + @Postsubmit + @Test + fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible() + + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<FlickerTestParameter> { + return FlickerTestParameterFactory.getInstance() + .getConfigNonRotationTests( + repetitions = 5, + supportedNavigationModes = listOf( + WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY + ), + supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90) + ) + } + } +}
\ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt index ca8f8af2df94..0389f7ce8d8d 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.FlickerParametersRunnerFactory import com.android.server.wm.flicker.FlickerTestParameter import com.android.server.wm.flicker.FlickerTestParameterFactory import com.android.server.wm.flicker.LAUNCHER_COMPONENT -import com.android.server.wm.flicker.annotation.Group1 +import com.android.server.wm.flicker.annotation.Group4 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.SimpleAppHelper @@ -38,7 +38,7 @@ import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -60,7 +60,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Group1 +@Group4 class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) { private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() private val testApp = SimpleAppHelper(instrumentation) @@ -145,7 +145,7 @@ class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) { @Test fun startsWithHomeActivityFlaggedVisible() { testSpec.assertWmStart { - this.isHomeActivityVisible(true) + this.isHomeActivityVisible() } } @@ -192,7 +192,7 @@ class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) { @Test fun endsWithHomeActivityFlaggedInvisible() { testSpec.assertWmEnd { - this.isHomeActivityVisible(false) + this.isHomeActivityInvisible() } } @@ -204,9 +204,9 @@ class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) { @Test fun appWindowBecomesAndStaysVisible() { testSpec.assertWm { - this.isAppWindowInvisible(testApp.component, ignoreActivity = true) + this.isAppWindowInvisible(testApp.component) .then() - .isAppWindowVisible(testApp.component, ignoreActivity = true) + .isAppWindowVisible(testApp.component) } } @@ -232,9 +232,9 @@ class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) { @Test fun launcherWindowBecomesAndStaysInvisible() { testSpec.assertWm { - this.isAppWindowVisible(LAUNCHER_COMPONENT) + this.isAppWindowOnTop(LAUNCHER_COMPONENT) .then() - .isAppWindowInvisible(LAUNCHER_COMPONENT) + .isAppWindowNotOnTop(LAUNCHER_COMPONENT) } } @@ -260,9 +260,9 @@ class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) { @Test fun appWindowIsVisibleOnceLauncherWindowIsInvisible() { testSpec.assertWm { - this.isAppWindowVisible(LAUNCHER_COMPONENT) + this.isAppWindowOnTop(LAUNCHER_COMPONENT) .then() - .isAppWindowVisible(SNAPSHOT_COMPONENT) + .isAppWindowVisible(FlickerComponentName.SNAPSHOT) .then() .isAppWindowVisible(testApp.component) } @@ -278,7 +278,7 @@ class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) { testSpec.assertLayers { this.isVisible(LAUNCHER_COMPONENT) .then() - .isVisible(SNAPSHOT_COMPONENT) + .isVisible(FlickerComponentName.SNAPSHOT) .then() .isVisible(testApp.component) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index d57c6698e35c..878821a80d0e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -30,7 +30,7 @@ import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsVisible -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.ROTATION_COMPONENT +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -38,8 +38,39 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Cycle through supported app rotations. + * Test opening an app and cycling through app rotations + * + * Currently runs: + * 0 -> 90 degrees + * 90 -> 0 degrees + * + * Actions: + * Launch an app (via intent) + * Set initial device orientation + * Start tracing + * Change device orientation + * Stop tracing + * * To run this test: `atest FlickerTests:ChangeAppRotationTest` + * + * To run only the presubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit` + * + * To run only the postsubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit` + * + * To run only the flaky assertions add: `-- + * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest` + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [RotationTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @@ -60,36 +91,51 @@ class ChangeAppRotationTest( } } + /** {@inheritDoc} */ @FlakyTest(bugId = 190185577) @Test override fun focusDoesNotChange() { super.focusDoesNotChange() } + /** + * Checks that the [FlickerComponentName.ROTATION] layer appears during the transition, + * doesn't flicker, and disappears before the transition is complete + */ @Presubmit @Test - fun screenshotLayerBecomesInvisible() { + fun rotationLayerAppearsAndVanishes() { testSpec.assertLayers { this.isVisible(testApp.component) .then() - .isVisible(ROTATION_COMPONENT) + .isVisible(FlickerComponentName.ROTATION) .then() .isVisible(testApp.component) } } + /** + * Checks that the status bar window is visible and above the app windows in all WM + * trace entries + */ @Presubmit @Test fun statusBarWindowIsVisible() { testSpec.statusBarWindowIsVisible() } + /** + * Checks that the status bar layer is visible at the start and end of the transition + */ @Presubmit @Test fun statusBarLayerIsVisible() { testSpec.statusBarLayerIsVisible() } + /** + * Checks the position of the status bar at the start and end of the transition + */ @Presubmit @Test fun statusBarLayerRotatesScales() { @@ -97,13 +143,26 @@ class ChangeAppRotationTest( testSpec.config.startRotation, testSpec.config.endRotation) } + /** {@inheritDoc} */ @FlakyTest @Test override fun navBarLayerRotatesAndScales() { super.navBarLayerRotatesAndScales() } + /** {@inheritDoc} */ + @FlakyTest + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() = + super.visibleLayersShownMoreThanOneConsecutiveEntry() + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt index 612ff9d3a153..2b03396c6296 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt @@ -17,7 +17,6 @@ package com.android.server.wm.flicker.rotation import android.app.Instrumentation -import android.content.ComponentName import android.platform.test.annotations.Presubmit import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerBuilderProvider @@ -31,9 +30,12 @@ import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsVisible import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.startRotation -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.Test +/** + * Base class for app rotation tests + */ abstract class RotationTransition(protected val testSpec: FlickerTestParameter) { protected abstract val testApp: StandardAppHelper @@ -55,6 +57,10 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Entry point for the test runner. It will use this method to initialize and cache + * flicker executions + */ @FlickerBuilderProvider fun buildFlicker(): FlickerBuilder { return FlickerBuilder(instrumentation).apply { @@ -62,18 +68,28 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that the navigation bar window is visible and above the app windows in all WM + * trace entries + */ @Presubmit @Test open fun navBarWindowIsVisible() { testSpec.navBarWindowIsVisible() } + /** + * Checks that the navigation bar layer is visible at the start and end of the transition + */ @Presubmit @Test open fun navBarLayerIsVisible() { testSpec.navBarLayerIsVisible() } + /** + * Checks the position of the navigation bar at the start and end of the transition + */ @Presubmit @Test open fun navBarLayerRotatesAndScales() { @@ -81,19 +97,27 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter) testSpec.config.startRotation, testSpec.config.endRotation) } + /** + * Checks that all layers that are visible on the trace, are visible for at least 2 + * consecutive entries. + */ @Presubmit @Test open fun visibleLayersShownMoreThanOneConsecutiveEntry() { testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry( - ignoreLayers = listOf(WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT, - WindowManagerStateHelper.SNAPSHOT_COMPONENT, - ComponentName("", "SecondaryHomeHandle") + ignoreLayers = listOf(FlickerComponentName.SPLASH_SCREEN, + FlickerComponentName.SNAPSHOT, + FlickerComponentName("", "SecondaryHomeHandle") ) ) } } + /** + * Checks that all windows that are visible on the trace, are visible for at least 2 + * consecutive entries. + */ @Presubmit @Test open fun visibleWindowsShownMoreThanOneConsecutiveEntry() { @@ -102,10 +126,16 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that all parts of the screen are covered during the transition + */ @Presubmit @Test open fun entireScreenCovered() = testSpec.entireScreenCovered() + /** + * Checks that the focus doesn't change during animation + */ @Presubmit @Test open fun focusDoesNotChange() { @@ -114,6 +144,9 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that [testApp] layer covers the entire screen at the start of the transition + */ @Presubmit @Test open fun appLayerRotates_StartingPos() { @@ -124,6 +157,9 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter) } } + /** + * Checks that [testApp] layer covers the entire screen at the end of the transition + */ @Presubmit @Test open fun appLayerRotates_EndingPos() { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 48efe73312c3..310f04b9710f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -27,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group3 import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.traces.common.FlickerComponentName import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -35,8 +35,41 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Cycle through supported app rotations using seamless rotations. + * Test opening an app and cycling through app rotations using seamless rotations + * + * Currently runs: + * 0 -> 90 degrees + * 0 -> 90 degrees (with starved UI thread) + * 90 -> 0 degrees + * 90 -> 0 degrees (with starved UI thread) + * + * Actions: + * Launch an app in fullscreen and supporting seamless rotation (via intent) + * Set initial device orientation + * Start tracing + * Change device orientation + * Stop tracing + * * To run this test: `atest FlickerTests:SeamlessAppRotationTest` + * + * To run only the presubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit` + * + * To run only the postsubmit assertions add: `-- + * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest + * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit` + * + * To run only the flaky assertions add: `-- + * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest` + * + * Notes: + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [RotationTransition] + * 2. Part of the test setup occurs automatically via + * [com.android.server.wm.flicker.TransitionRunnerWithRules], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup */ @RequiresDevice @RunWith(Parameterized::class) @@ -61,6 +94,9 @@ class SeamlessAppRotationTest( } } + /** + * Checks that [testApp] window is always in full screen + */ @Presubmit @Test fun appWindowFullScreen() { @@ -75,6 +111,9 @@ class SeamlessAppRotationTest( } } + /** + * Checks that [testApp] window is always with seamless rotation + */ @Presubmit @Test fun appWindowSeamlessRotation() { @@ -90,6 +129,9 @@ class SeamlessAppRotationTest( } } + /** + * Checks that [testApp] window is always visible + */ @Presubmit @Test fun appLayerAlwaysVisible() { @@ -98,6 +140,9 @@ class SeamlessAppRotationTest( } } + /** + * Checks that [testApp] layer covers the entire screen during the whole transition + */ @Presubmit @Test fun appLayerRotates() { @@ -110,29 +155,36 @@ class SeamlessAppRotationTest( } } + /** + * Checks that the [FlickerComponentName.STATUS_BAR] window is invisible during the whole + * transition + */ @Presubmit @Test fun statusBarWindowIsAlwaysInvisible() { testSpec.assertWm { - this.isAboveAppWindowInvisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT) + this.isAboveAppWindowInvisible(FlickerComponentName.STATUS_BAR) } } + /** + * Checks that the [FlickerComponentName.STATUS_BAR] layer is invisible during the whole + * transition + */ @Presubmit @Test fun statusBarLayerIsAlwaysInvisible() { testSpec.assertLayers { - this.isInvisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT) + this.isInvisible(FlickerComponentName.STATUS_BAR) } } + /** {@inheritDoc} */ @FlakyTest @Test override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales() companion object { - private val testFactory = FlickerTestParameterFactory.getInstance() - private val Map<String, Any?>.starveUiThread get() = this.getOrDefault(ActivityOptions.EXTRA_STARVE_UI_THREAD, false) as Boolean @@ -144,20 +196,34 @@ class SeamlessAppRotationTest( return config } + /** + * Creates the test configurations for seamless rotation based on the default rotation + * tests from [FlickerTestParameterFactory.getConfigRotationTests], but adding an + * additional flag ([ActivityOptions.EXTRA_STARVE_UI_THREAD]) to indicate if the app + * should starve the UI thread of not + */ @JvmStatic private fun getConfigurations(): List<FlickerTestParameter> { - return testFactory.getConfigRotationTests(repetitions = 2).flatMap { - val defaultRun = it.createConfig(starveUiThread = false) - val busyUiRun = it.createConfig(starveUiThread = true) - listOf( - FlickerTestParameter(defaultRun), - FlickerTestParameter(busyUiRun, - name = "${FlickerTestParameter.defaultName(busyUiRun)}_BUSY_UI_THREAD" + return FlickerTestParameterFactory.getInstance() + .getConfigRotationTests(repetitions = 2) + .flatMap { + val defaultRun = it.createConfig(starveUiThread = false) + val busyUiRun = it.createConfig(starveUiThread = true) + listOf( + FlickerTestParameter(defaultRun), + FlickerTestParameter(busyUiRun, + name = "${FlickerTestParameter.defaultName(busyUiRun)}_BUSY_UI_THREAD" + ) ) - ) - } + } } + /** + * Creates the test configurations. + * + * See [FlickerTestParameterFactory.getConfigRotationTests] for configuring + * repetitions, screen orientation and navigation modes. + */ @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<FlickerTestParameter> { |